1. 언리얼 방식

a. 액터 생성하기

  • 액터 정의:

    • 액터(Actor)는 씬(Scene)에 배치할 수 있는 모든 오브젝트를 의미.
    • 예를 들어, 플레이어, 적, 배경 등이 액터로 표현될 수 있음.
  • Object와의 비교:

    • 기존에 사용하던 Object 클래스와 비슷하지만, 액터는 씬에 배치 가능하며 좌표를 가짐.
  • Init과 Update:

    • 언리얼의 Init과 Update 메서드는 초기화와 상태 갱신을 처리하는 역할.
    • 좌표 추가: 액터는 기본적으로 위치(Position)를 포함해야 하므로, 좌표 정보를 함께 정의.
  • 실수 교훈:

    • 좌표와 관련된 초기화 코드를 작성할 때 일부를 누락하면 오류가 발생할 수 있음.
    • "30분 동안 오류를 해결하느라 시간을 소모했다"는 실수에서, 초기화 코드는 꼼꼼히 작성해야 함을 강조.

b. SpriteActor 생성하기

  • SpriteActor란?

    • SpriteActor는 액터를 상속받아, 스프라이트 렌더링을 필요로 하는 오브젝트를 정의한 클래스.
  • 필요성:

    • 모든 액터가 스프라이트를 가질 필요는 없으므로, 스프라이트 렌더링이 필요한 부분만 SpriteActor로 구현.
  • 클래스 구조:

    • Actor를 상속:
      • SpriteActorActor 클래스를 상속받아 필요한 기능을 추가.
      • 생성자에서 부모 클래스의 생성자를 호출하여 초기화.
  • 렌더링 처리:

    • 기존 DevScene에서 처리하던 렌더링 코드를 SpriteActor로 이동.
    • 포지션(Position):
      • Actor의 포지션 정보를 활용하여 스프라이트를 배치.
      • 위치 계산(_pos.x - size.x / 2 등)은 정확한 배치를 위해 필수적.

c. 개발 씬에서 액터 추가

  • 개발 씬 역할:

    • DevScene은 개발과 테스트 목적으로 사용되는 임시 씬.
  • Init에서 Actor 추가:

    • 초기화 단계에서 액터를 DevScene에 등록.
    • 등록된 액터는 씬의 Update와 Render 메서드에서 호출되어 갱신 및 렌더링됨.
  • Update 처리:

    • DevScene의 Update 메서드에서 추가된 액터들의 상태를 갱신.

d. 배경화면 렌더링하기

  • 배경화면 렌더링:

    • SpriteActor를 기반으로 배경화면을 렌더링.
    • 예제에서는 _background라는 이름으로 SpriteActor를 생성하여 Stage01 파일을 로드.
  • 렌더링 로직:

    • Init에서 배경 스프라이트를 초기화하고, Update에서 화면에 출력.
  • 결과:

    • 화면에 정적으로 배경 이미지가 출력.

💥 구현 고민

  • 문제:

    • 정적인 배경화면에는 문제가 없지만, 애니메이션이 필요한 경우 SpriteActor만으로는 부족.
    • SpriteActor는 엔진 코드에 속하며, 애니메이션 관련 로직을 추가하면 엔진과 게임 로직이 섞이는 문제가 발생.
  • 해결 방법:

    • SpriteActor를 상속받아 별도의 클래스를 생성.
    • : Player 클래스는 SpriteActor를 상속받아, 애니메이션 처리 로직을 포함.

2. 유니티 방식

a. GameObject 생성하기

  • GameObject 정의:
    • GameObject는 씬에 배치할 수 있는 최상위 오브젝트.
    • 언리얼의 Actor와 개념적으로 유사.

b. Component 생성하기

  • Component란?

    • GameObject에 붙일 수 있는 "부품"으로, 오브젝트의 기능을 정의.
  • Component의 부모 클래스:

    • 모든 컴포넌트의 기반이 되는 부모 클래스 생성.
    • 예제에서는 05.Component라는 이름으로 클래스 작성.
  • 기본 구현:

    • Component 클래스에 최소한의 기본 메서드를 작성.

c. 컴포넌트 추가하기

  • 컴포넌트와 GameObject의 관계:

    • GameObject에 여러 컴포넌트를 추가하여 다양한 기능을 조합.
    • 예: 이동, 렌더링, 충돌 감지 등.
  • 컴포넌트 추가 로직:

    • GameObject가 컴포넌트를 등록하고, 등록된 컴포넌트를 불러오는 메서드 작성.

d. 렌더링 컴포넌트 만들기

  • SpriteRenderer:

    • Component를 상속받아 렌더링에 필요한 기능을 구현한 클래스.
  • 구현 내용:

    • SpriteRenderer 클래스에서 기존 렌더링 로직을 활용.

e. 씬에 추가하기

  • GameObject 생성:

    • 씬에 GameObject를 추가하고, 이미지 렌더링 부품(Component)을 장착.
  • 렌더링:

    • Init, Update, Render 메서드를 구현하여 화면에 이미지 출력.
  • 결과:

    • GameObject와 SpriteRenderer 조합으로 이미지가 화면에 출력됨.

3. Actor 클래스

Actor.h

class Actor
{
public:
	Actor();
	virtual ~Actor();

	virtual void BeginPlay();
	virtual void Tick();
	virtual void Render(HDC hdc);
	
	void SetPos(Vec2 pos) { _pos = pos; }
	Vec2 GetPos() { return _pos; }
protected:
	Vec2 _pos = { 0,0 };
};
  • 클래스 설명:
    • Actor는 언리얼 엔진의 Actor를 모방하여 구현된 클래스.
    • 씬(Scene)에 배치 가능한 모든 오브젝트의 기본 클래스이며, 초기화, 상태 갱신, 렌더링 기능을 갖춤.
  • 멤버 함수:
    • BeginPlay: 객체가 생성된 후 초기화를 처리.
    • Tick: 매 프레임 갱신 로직을 정의.
    • Render: 화면에 객체를 렌더링.
  • 멤버 변수:
    • _pos: 2D 벡터로 표현되는 객체의 위치.

Actor.cpp

Actor::Actor() {}
Actor::~Actor() {}
void Actor::BeginPlay() {}
void Actor::Tick() {}
void Actor::Render(HDC hdc) {}
  • 기본 동작:
    • 생성자와 소멸자는 객체의 생성 및 삭제를 처리.
    • BeginPlay, Tick, Render는 기본적으로 비어 있으며, 파생 클래스에서 구체적인 동작을 오버라이드하도록 설계.

4. SpriteActor 클래스

SpriteActor.h

class SpriteActor : public Actor
{
	using Super = Actor;

public:
	SpriteActor();
	virtual ~SpriteActor();

	virtual void BeginPlay() override;
	virtual void Tick() override;
	virtual void Render(HDC hdc) override;

	void SetSprite(Sprite* sprite) { _sprite = sprite; }
protected:
	Sprite* _sprite = nullptr;
};
  • 클래스 설명:
    • SpriteActorActor를 상속받아, 스프라이트를 렌더링하는 기능을 추가.
    • 멤버 변수 _sprite는 렌더링할 스프라이트를 저장.
    • 멤버 함수 SetSprite를 통해 스프라이트를 설정.

SpriteActor.cpp

void SpriteActor::Render(HDC hdc)
{
	Super::Render(hdc);

	if (_sprite == nullptr) return;

	Vec2Int size = _sprite->GetSize();
	::BitBlt(
		hdc, 
		(int32)_pos.x - size.x / 2, 
		(int32)_pos.y - size.y / 2, 
		size.x, 
		size.y, 
		_sprite->GetDC(), 
		_sprite->GetPos().x, 
		_sprite->GetPos().y, 
		SRCCOPY
	);
}
  • 렌더링 과정:
    • 부모 클래스(Actor)의 Render를 호출.
    • _sprite가 설정되어 있지 않으면 렌더링을 생략.
    • BitBlt 함수:
      • 화면(hdc)에 스프라이트를 렌더링.
      • _pos를 기준으로 스프라이트를 중앙에 배치.

5. Player 클래스

Player.h

class Player : public SpriteActor
{
	using Super = SpriteActor;

public:
	Player();
	virtual ~Player() override;

	virtual void BeginPlay() override;
	virtual void Tick() override;
	virtual void Render(HDC hdc) override;
};
  • 클래스 설명:
    • PlayerSpriteActor를 상속받아 플레이어의 동작을 정의.
    • BeginPlay, Tick, Render는 플레이어 객체의 초기화, 갱신, 렌더링을 처리.

Player.cpp

void Player::Tick()
{
	Super::Tick();
	// TODO: 플레이어 이동 및 미사일 발사 기능 구현
}
  • Tick 메서드:
    • 부모 클래스(SpriteActor)의 Tick 호출 후, 플레이어 전용 로직을 추가.
    • 이동, 공격 등의 기능을 구현 예정.

6. GameObjectComponent

GameObject 클래스

GameObject.h

class GameObject
{
public:
	void AddComponent(Component* component);
protected:
	vector<Component*> _components;
};
  • 클래스 설명:
    • GameObject는 유니티의 GameObject와 유사한 역할.
    • AddComponent 함수는 컴포넌트를 추가.

GameObject.cpp

void GameObject::Update()
{
	for (Component* component : _components)
	{
		component->Update();
	}
}
  • 컴포넌트 갱신:
    • 모든 컴포넌트를 순회하며 Update를 호출.

Component 클래스

Component.h

class Component
{
public:
	virtual void Start();
	virtual void Update();
	virtual void Render(HDC hdc);
};
  • 클래스 설명:
    • Component는 GameObject에 부착 가능한 부품으로, 행동 단위를 정의.

7. SpriteRendererPlayerMoveScript

SpriteRenderer

void SpriteRenderer::Render(HDC hdc)
{
	if (_sprite == nullptr) return;

	Vec2Int size = _sprite->GetSize();
	::BitBlt(
		hdc,
		0,
		0,
		size.x,
		size.y,
		_sprite->GetDC(),
		_sprite->GetPos().x,
		_sprite->GetPos().y,
		SRCCOPY
	);
}
  • 역할:
    • 스프라이트를 렌더링하는 컴포넌트.

PlayerMoveScript

void PlayerMoveScript::Update()
{
	// TODO: 플레이어 이동 로직 추가
}
  • 역할:
    • 플레이어 이동 로직을 처리하는 컴포넌트.

8. DevScene 클래스

Init 메서드

Sprite* sprite = GET_SINGLE(ResourceManager)->GetSprite(L"Stage01");
SpriteActor* background = new SpriteActor();
background->SetSprite(sprite);
_background = background;
  • 배경 설정:
    • Stage01 스프라이트를 로드하고 배경으로 설정.

Update 메서드

_background->Tick();
_player->Tick();
_go->Update();
  • 업데이트 과정:
    • 배경, 플레이어, GameObject를 각각 갱신.

Render 메서드

_background->Render(hdc);
_player->Render(hdc);
_go->Render(hdc);
  • 렌더링 과정:
    • 배경, 플레이어, GameObject를 순서대로 화면에 출력.

profile
李家네_공부방

0개의 댓글