WIN32API FrameWork/한단계씩 직접 구현

23. 플레이어를 향해 총을 쏘는 몬스터

hyrule 2022. 5. 21. 21:23

http://hyrule.tistory.com/111 

 

*** 공부 방법 ***

1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. 처

hyrule.tistory.com

 


- 저번에 만들었던 각도 구하기 메소드를 활용해 몬스터가 매 3발마다 플레이어를 향해 총을 쏘게 만들어보자.

 

- 우선, 총을 발사하기 위해서는 '플레이어'의 좌표값이 필요한데...

좌표값에 접근하기 위해서는 우선 CPlayer에 접근하는 방법을 생각해봐야 한다.

-- 방법은 2가지가 있다.

---1. 플레이어의 주소는 자주 쓰이므로 아예 CGameManager 클래스에 CPlayer의 주소를 등록해 놓고,
필요할 때마다 호출해서 주소를 받기.

---- 이렇게 하게 되면, CPlayer를 초기화할 때 등록해 주는 과정도 추가로 작성 주어야 한다.

 

---2. CScene에서 모든 게임오브젝트의 목록에 접근하여 원하는 CGameObject를 찾아주는 메소드를 만들기

2번 방식을 쓰기 위해서는 CScene에 접근하기 위한 방법도 추가해주어야 한다.

----2-1. CSceneManager에서 CScene에 접근하기

----2-2. CGameObject이 생성될 때, 자신이 소속된 CScene을 등록해서 CScene에 접근하기.

---- 현재 구동되고 있는 CScene은 CSceneManager 에서 관리하고 있으므로, 실제 접근은 CSceneManager에서 현재 CScene에 접근하는 방식으로 구현해야 한다.

 

- 편의를 위해 모두 구현해보자.

▼1번

더보기
//GameManager.h에 추가할 내용

private:
	//플레이어 헤더 포함시키지 않고 전방선언(코드꼬임 방지)
	//플레이어는 자주 쓰이므로 변수로 따로 잡아놓고, 
	//다른 객체에서 요청 시 주소를 반환해준다.
	class CPlayer* m_Player;
    
public:
	void SetPlayer(class CPlayer* Player);
	class CPlayer* GetPlayer()	const;

 

//GameManager.cpp에 추가할 내용

void CGameManager::SetPlayer(CPlayer* Player)
{
    m_Player = Player;
}

CPlayer* CGameManager::GetPlayer() const
{
    return m_Player;
}

//Player.cpp에 추가할 내용

#include "../GameManager.h"

bool CPlayer::Init()
{
	//Player의 주소를 CGameManager에 등록한다.
	CGameManager::GetInst()->SetPlayer(this);
    
    //...이외의 코드들...
    
}

▼2-1 번

더보기
//SceneManager.h에 해당 내용 추가

public:
	CScene* GetScene()	const
	{
		return m_PresentScene;
	}

 

 


▼2-2 번

더보기
//GameObject.h에 해당 내용 추가

protected:
	CScene* m_OwnerScene;
    
private:
    void SetOwnerScene(CScene* Scene)
	{
		m_OwnerScene = Scene;
	}
    
public:
    CScene* GetOwnerScene() const
	{
		return m_OwnerScene;
	}

게임오브젝트에서 자신을 생성한 CScene을 등록해 주고 등록하는 메소드도 추가해 준다.

 

 

public:
	template <typename T>
	T* CreateObject(const std::string& Name = "GameObject")
	{
    	//...기존 코드들...

		//게임오브젝트가 생성될 때 생성한 씬을 등록.
		Obj->SetOwner(this);

		//...기존 코드들...
	}

CScene에서 게임오브젝트를 생성할 때, 생성한 CScene의 클래스 주소를 등록해 준다.


CScene::FindObject()

- 이제 CScene에 접근할 수 있는 방법을 마련했으므로 CScene에서 등록된 CGameObject의 '이름'(문자열)을 통해 접근하는 메소드를 추가해 준다.

 

- m_ObjList를 iterator로 순회 돌면서 이름이 일치하는 CGameObject를 찾으면 주소를 반환한다.

더보기
CGameObject* CScene::FindObject(const std::string& Name)
{
	std::list<CSharedPtr<class CGameObject>>::iterator iter = m_ObjList.begin();
	std::list<CSharedPtr<class CGameObject>>::iterator iterEnd = m_ObjList.end();

	while (iter != iterEnd)
	{
		if ((*iter)->m_Name == Name)
			return *iter;

		++iter;
	}
	return nullptr;
}

- 이제 CMonster에서 CPlayer의 위치를 받아올 수 있다.

 

- 이제 이 주소를 받아다가 플레이어를 향해 총을 쏘는 로직을 구현한다.

 

- 각도를 구해서 발사하는 로직은 플레이어의 총 방향 구현과 비슷하다.

-- 각도의 코사인값은 x축 방향 벡터가 되고, 사인값은 y축 방향 벡터가 된다. 

더보기

 

//GameInfo.h에 해당 변수 추가 선언
private:
	int m_InhancedFireCycle;
	int m_InhancedFireCount;

 

* 여기서는 2-1번 방법을 사용하여 CPlayer의 주소를 받아왔다.

//GameInfo.cpp에 해당 코드 추가

#include "../GameManager.h"
#include "../GameObject/Player.h"

void CMonster::Update(float DeltaTime)
{
	
    //...기존 코드들...

	m_BulletDurationTimer += DeltaTime;
	if (m_BulletDurationTimer > m_BulletDuration)
	{
		CBullet* Bullet = CSceneManager::GetInst()->GetScene()->CreateObject<CBullet>("Bullet");

		Bullet->SetSpeedDir(1000.f, Vector2(-1.f, 0.f));

		++m_InhancedFireCount;
		if (m_InhancedFireCount == m_InhancedFireCycle)
		{
			
			CGameObject* Player = m_OwnerScene->FindObject("Player");

			if (Player)
			{
				float angle = m_Pos.Angle(Player->GetPos());
				Vector2 Dir;
				Dir.x = cosf(angle);
				Dir.y = sinf(angle);

				Bullet->SetSpeedDir(1000.f, Dir);
			}

			m_InhancedFireCount = 0;
		}


		Bullet->SetPos(m_Pos.x, m_Pos.y);
		
		m_BulletDurationTimer = 0.f;
	}
	
}

매 3발마다 플레이어를 향해 총알이 발사된다.
GameFrameworkStepbyStep_23_FindPlayer.zip
4.52MB