본문 바로가기
-----ETC-----/C++ 게임 개발 시리즈

[C++ 게임 개발 시리즈] Day 21: 적 캐릭터와 NPC의 AI 구현

by cogito21_cpp 2024. 8. 1.
반응형

적 캐릭터와 NPC의 AI 구현

오늘은 행동 트리(Behavior Tree)를 사용하여 적 캐릭터와 NPC의 AI를 구현하는 방법을 학습하겠습니다. 이를 통해 게임 캐릭터가 주변 환경과 상호작용하고, 다양한 상황에 반응하는 방법을 배울 것입니다.

기본 AI 동작 정의

적 캐릭터와 NPC의 AI는 다양한 동작으로 구성됩니다. 여기서는 찾기, 이동, 공격과 같은 기본 동작을 정의하겠습니다.

기본 노드 클래스 및 동작 구현

기본 노드 클래스 정의

우선, AI 동작을 정의하는 기본 노드를 구현합니다.

#include <iostream>
#include <vector>
#include <functional>

enum class NodeStatus {
    Success,
    Failure,
    Running
};

class Node {
public:
    virtual ~Node() {}
    virtual NodeStatus tick() = 0;
};

class ActionNode : public Node {
public:
    ActionNode(std::function<NodeStatus()> action) : action(action) {}

    NodeStatus tick() override {
        return action();
    }

private:
    std::function<NodeStatus()> action;
};

선택자 노드 정의

class Selector : public Node {
public:
    void addChild(Node* child) {
        children.push_back(child);
    }

    NodeStatus tick() override {
        for (auto& child : children) {
            NodeStatus status = child->tick();
            if (status != NodeStatus::Failure) {
                return status;
            }
        }
        return NodeStatus::Failure;
    }

private:
    std::vector<Node*> children;
};

시퀀스 노드 정의

class Sequence : public Node {
public:
    void addChild(Node* child) {
        children.push_back(child);
    }

    NodeStatus tick() override {
        for (auto& child : children) {
            NodeStatus status = child->tick();
            if (status != NodeStatus::Success) {
                return status;
            }
        }
        return NodeStatus::Success;
    }

private:
    std::vector<Node*> children;
};

AI 동작 구현

다음은 적 캐릭터와 NPC의 AI 동작을 구현한 예제입니다. 여기서는 목표를 찾고, 목표로 이동하며, 목표를 공격하는 기본 동작을 정의합니다.

행동 정의

NodeStatus findTarget() {
    std::cout << "Finding target..." << std::endl;
    return NodeStatus::Success; // 단순히 성공으로 가정
}

NodeStatus moveToTarget() {
    std::cout << "Moving to target..." << std::endl;
    return NodeStatus::Running; // 단순히 실행 중으로 가정
}

NodeStatus attackTarget() {
    std::cout << "Attacking target..." << std::endl;
    return NodeStatus::Success; // 단순히 성공으로 가정
}

행동 트리 구현

다음은 행동 트리를 구성하여 적 캐릭터의 AI를 구현한 예제입니다.

int main() {
    // 행동 트리 생성
    Selector root;

    Sequence sequence;
    root.addChild(&sequence);

    ActionNode findTargetNode(findTarget);
    ActionNode moveToTargetNode(moveToTarget);
    ActionNode attackTargetNode(attackTarget);

    sequence.addChild(&findTargetNode);
    sequence.addChild(&moveToTargetNode);
    sequence.addChild(&attackTargetNode);

    // 행동 트리 실행
    while (root.tick() == NodeStatus::Running) {
        std::cout << "Behavior tree running..." << std::endl;
    }

    std::cout << "Behavior tree completed." << std::endl;
    return 0;
}

NPC 클래스에 행동 트리 적용

NPC 클래스에 행동 트리를 적용하여 AI 동작을 관리합니다.

class NPC {
public:
    NPC(Node* behaviorTree) : behaviorTree(behaviorTree) {}

    void update(float deltaTime) {
        if (behaviorTree->tick() == NodeStatus::Running) {
            std::cout << "NPC behavior running..." << std::endl;
        } else {
            std::cout << "NPC behavior completed." << std::endl;
        }
    }

private:
    Node* behaviorTree;
};

int main() {
    // 행동 트리 생성
    Selector root;

    Sequence sequence;
    root.addChild(&sequence);

    ActionNode findTargetNode(findTarget);
    ActionNode moveToTargetNode(moveToTarget);
    ActionNode attackTargetNode(attackTarget);

    sequence.addChild(&findTargetNode);
    sequence.addChild(&moveToTargetNode);
    sequence.addChild(&attackTargetNode);

    // NPC 생성 및 행동 트리 할당
    NPC npc(&root);

    // 게임 루프
    while (true) {
        npc.update(0.1f); // deltaTime 임시값 사용
    }

    return 0;
}

결론

오늘은 행동 트리를 사용하여 적 캐릭터와 NPC의 AI를 구현하는 방법을 학습했습니다. 행동 트리는 상태 머신보다 더 유연하고 확장 가능한 구조를 제공하여 복잡한 AI를 구현할 수 있습니다. 질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Day 22: 3D 그래픽 기초"에 대해 학습하겠습니다.

반응형