1. 목표와 개요

기본적인 게임 시스템 구현

  • 플레이어, 몬스터, 필드 등을 생성합니다.
  • 필드 내 모든 오브젝트는 unordered_map을 통해 관리됩니다.
  • 다형성을 이용해 다양한 타입의 객체를 하나의 컨테이너에서 관리할 수 있습니다.

2. 열거형 ObjectType

enum class ObjectType {
    Player,
    Monster,
    Projectile,
    Env
};

설명:

  • enum class를 사용하여 객체 타입을 정의합니다.
  • 안전성: enum class는 일반 enum과 달리 스코프를 제공하므로 다른 열거형과 이름 충돌을 방지합니다.

객체의 타입 구분:

  • ObjectType::Player: 플레이어 객체
  • ObjectType::Monster: 몬스터 객체
  • ObjectType::Projectile: 투사체 객체
  • ObjectType::Env: 환경 객체

3. 기본 클래스 Object

기본 구조

class Object {
public:
    Object(ObjectType type) : _type(type) {}
    virtual ~Object() {}
    virtual void Init() {}
    virtual void Update() {}
    ObjectType GetObjectType() { return _type; }

protected:
    int _id = 0;
    ObjectType _type;
};

세부 설명:

  1. 생성자:

    • ObjectType을 입력받아 _type 멤버를 초기화합니다.
  2. 소멸자:

    • virtual ~Object(): 상속된 클래스의 소멸자가 올바르게 호출되도록 합니다.
  3. 가상 함수:

    • Init()Update(): 상속된 클래스에서 재정의할 수 있습니다.
  4. 객체 타입:

    • _type: ObjectType으로 객체의 타입을 저장합니다.
    • GetObjectType(): 객체의 타입을 반환합니다.
  5. ID 관리:

    • _id: 객체의 고유 ID를 저장합니다.

4. 상속받는 클래스들

플레이어 클래스

class Player : public Object {
public:
    Player() : Object(ObjectType::Player) {}
    Player(int id) : Object(ObjectType::Player), _id(id) {}
    int _id;
};
  • 설명:
    • Object 클래스를 상속받습니다.
    • ObjectType::Player를 생성자에 전달해 타입을 설정합니다.
    • ID: 플레이어 고유 ID를 저장합니다.

몬스터 클래스

class Monster : public Object {
public:
    Monster() : Object(ObjectType::Monster) {}
    int _id;
};
  • 설명:
    • Object 클래스를 상속받고, ObjectType::Monster 타입을 설정합니다.

투사체 클래스

class Projectile : public Object {
    Projectile() : Object(ObjectType::Projectile) {}
};
  • 설명:
    • ObjectType::Projectile을 가지는 클래스입니다.

환경 클래스

class Env : public Object {};
  • 설명:
    • Object 클래스를 상속받는 빈 클래스입니다.

5. 싱글톤 Field 클래스

싱글톤 패턴 구현

class Field {
public:
    static Field* GetInstance() {
        static Field field;
        return &field;
    }
  • 설명:
    • 싱글톤 패턴: Field 클래스의 인스턴스를 하나만 유지합니다.
    • static Field field: 정적 멤버로 프로그램이 종료될 때까지 유지됩니다.

객체 추가

    void Add(Object* object) {
        _object.insert(make_pair(object->_id, object));
    }
  • 설명:
    • _object에 객체의 ID와 객체 포인터를 추가합니다.

객체 삭제

    void Remove(int id) {
        _object.erase(id);
    }
  • 설명:
    • ID를 키로 사용해 해당 객체를 삭제합니다.

객체 검색

    Object* Get(int id) {
        auto findIt = _object.find(id);
        if (findIt != _object.end()) {
            return findIt->second;
        }
        return nullptr;
    }
  • 설명:
    • ID로 객체를 찾아 반환합니다. 없으면 nullptr를 반환합니다.

객체 업데이트

    void Update() {
        for (auto& item : _object) {
            Object* obj = item.second;
            obj->Update();
        }
    }
  • 설명:
    • _object에 저장된 모든 객체를 순회하며 Update() 함수를 호출합니다.

6. main 함수

int main() {
    Field::GetInstance()->Add(new Player(1));

    Object* obj = Field::GetInstance()->Get(1);
    if (obj && obj->GetObjectType() == ObjectType::Player) {
        Player* player = static_cast<Player*>(obj);
    }

    Player* player = dynamic_cast<Player*>(Field::GetInstance()->Get(1));
}

세부 설명:

  1. 객체 추가:

    • Field 싱글톤 인스턴스를 통해 Player 객체를 추가합니다.
  2. 객체 검색 및 타입 확인:

    • Get()으로 객체를 검색하고, ObjectType을 확인합니다.
    • static_cast: 객체 타입이 확실할 때 사용합니다.
    • dynamic_cast: 객체 타입을 확인하고 안전하게 변환합니다. 실패 시 nullptr 반환.

7. 주요 개념 정리

  1. 싱글톤 패턴:

    • Field 클래스는 단 하나의 인스턴스만 존재합니다.
  2. 다형성:

    • Object 클래스를 통해 모든 객체를 관리하고, 가상 함수로 동작을 정의합니다.
  3. unordered_map:

    • 객체를 ID로 빠르게 관리하고 검색할 수 있습니다. 평균 시간 복잡도는 O(1)입니다.
  4. 캐스팅:

    • static_cast: 타입 변환이 확실할 때 사용.
    • dynamic_cast: 타입 안전성을 확인하며 변환.

profile
李家네_공부방

0개의 댓글