WIN32 Object + 숙제

Date:     Updated:

카테고리:

태그:

9일차

- Default
    - Client.h
    - framework.h
    - Resouce.h
    - targetver.h
- Engine
    1. Header
        **1. define.h**
        **2. struct.h**
    2. Core
        **1. CCore.cpp**
        2. CCore.h
    3. Manager
        1. KeyMgr
            1. CkeyMgr.cpp
            2. CkeyMgr.h
        2. TimeMgr
            1. CTimeMgr.cpp
            2. CTimeMgr.h
        3. SceneMgr
            1. CSceneMgr.cpp
            **2. CSceneMgr.h**
    **4. Object
		    1. Monser
			    1. CMonster.cpp
			    2. CMonster.h
			  2. Missle
				  1. Missile.cpp
				  2. Missile.h
				3. Player
					1. CPlayer.cpp
					2. Cplayer.h
        1. CObject.cpp
        2. CObject.h**
    5. Scene
        **1. Scene_Start
            1. CScene_Start.cpp
            2. CScene_Start.h**
        2. Scene_Tool
        3. CScene.cpp
        **4. CScene.h**
- 리소스 파일
- main.cpp
- pch.h.
  • 규모가 커지다보니 복붙하기가 어려워졌다.. 앞으론 코드에다가 복붙 해야할 것 같다.
  1. define.h
#pragma once

//매크로는 코드를 치환하는 것. 
//따라서 함수를 호출한 적이 없어서 스위칭이 없어서 더 빠름. 
//주의점은 매크로는 함수가 아니라, 그대로 코드를 치환하는거라서

//완전히 다른 느낌이 될 수 있음...

//이렇게 하면 내가 해제를 신경쓰지 않아도 된다는 점
//반대로 이렇게 하면의 단점. 
//끝까지 끌고 나가야 하는 방식.

//SingleTon 매크로. 

#define SINGLE(type)public: \
					static type* GetInstance()\
					{\
						static type mgr;\
						return &mgr;\
					}\
					private:\
						type();\
						~type();

#define fDT CTimeMgr::GetInstance()->GetfDT()
#define DT	CTimeMgr::GetInstance()->GetDT()

#define KEY_CHECK(key, state) CkeyMgr::GetInstance()->GetKeyState(key) == state

#define KEY_HOLD(key) KEY_CHECK(key, KEY_STATE::HOLD)
#define KEY_TAP(key) KEY_CHECK(key, KEY_STATE::TAP)
#define KEY_NONE(key) KEY_CHECK(key, KEY_STATE::NONE)
#define KEY_AWAY(key) KEY_CHECK(key, KEY_STATE::AWAY)

enum class GROUP_TYPE {
	DEFAULT, 
	PLAYER,
	MISSILE,
	MONSTER,

	
	END = 32,
};

enum class SCENE_TYPE {
	TOOL,
	START,
	STAGE_01,
	STAGE_02,
	
	END,
};
  • 키 입력 처리가 … → GetInstance()→ 식이라 굉장히 길어서 매크로 처리를 해주었다. 또한 HOLD, TAP, AWAY, NONE으로 따로따로 매크로 처리 해주었다.
    1. struct.h
#pragma once

struct Vec2 {
	float x;
	float y;

public:
	Vec2& operator = (POINT _pt) {
		x = (float)_pt.x;
		y = (float)_pt.y;
;	}

public:
	Vec2()
		: x(0.f)
		, y(0.f)
	{}

	Vec2(float _x, float _y)
		: x(_x)
		, y(_y)
	{}

	Vec2(int _x, int _y)
		: x((float)_x)
		, y((float)_y)
	{}

	Vec2(const POINT& _pt)
		: x((float)_pt.x)
		, y((float)_pt.y)
	{}
};
  • POINT형을 받도록 생성자를 만들어주었다.

번외 → CCore.cpp는 CObject를 추상 클래스를 만들어줌으로서 전역변수로 존재하고 있은 CObject과 그와 관련된 쓸모없는 기능들을 정리하였다.

  1. CSceneMgr.h
#pragma once

class CScene;

class CSceneMgr
{
	SINGLE(CSceneMgr);

private:
	CScene*			m_arrScene[(UINT)SCENE_TYPE::END];	//모든 씬에 대한 정보를 다 가짐
	CScene*			m_pCurScene;						//현재 씬 
public:
	void init();

	void update();
	void render(HDC _dc);

public:
	CScene* GetCurScene() { return m_pCurScene; }
};

  • 현재 씬에 AddObject를 할 수 있도록, GetCurScene함수를 만들어주었다.
  1. CObject.h
#pragma once

//오브젝트라는 건, 가장 부모격인 녀석. 오브젝트마다 성향이 있음 
//어떤 건 UI, 어떤 건 캐릭터... 

//오브젝트를 일괄적으로 관리할 녀석이 필요함. -> Scene

//이 오브젝트는 부모 클래스. -> 상속받은 오브젝트도 Scene의 업데이트 시점에
//부모쪽에 구현되어있는 update뿐만 아니라, 각 오브젝트(자식)들 마다의 update를 하고 싶음

class CObject
{

private:
	Vec2	m_vPos;
	Vec2	m_vScale;

public:
	void SetPos(Vec2 _vPos) { m_vPos = _vPos; }
	void SetScale(Vec2 _vScale) { m_vScale = _vScale; }

	Vec2 GetPos() { return m_vPos; }
	Vec2 GetScale() { return m_vScale; }

public:
	virtual void update() = 0;
	virtual void render(HDC _dc);

public:
	CObject();
	virtual ~CObject();
};

  • update와 render를 가상함수로 만들어주었다.
  1. CObject.cpp
#include "pch.h"
#include "CObject.h"

#include "CkeyMgr.h"
#include "CTimeMgr.h"

CObject::CObject()
	: m_vPos{}
	, m_vScale{}{

}

CObject::~CObject() {

}

void CObject::render(HDC _dc)
{

	Rectangle(_dc, (int)(m_vPos.x - m_vScale.x / 2.f), (int)(m_vPos.y - m_vScale.y / 2.f),
		(int)(m_vPos.x + m_vScale.x / 2.f), (int)(m_vPos.y + m_vScale.y / 2.f));
}
  • 사실 변경점이 없긴한데, 일단…
  1. CPlayer.h
#pragma once
#include "CObject.h"
class CPlayer :
    public CObject
{
public :
    virtual void update();

private:
    void CreateMissile();
};

  • 순수 가상함수인 update를 구현하고, 미사일을 쏘는 함수를 넣어주었다.
  1. CPlayer.cpp
#include "pch.h"
#include "CPlayer.h"

#include "CSceneMgr.h"
#include "CScene.h"
#include "CkeyMgr.h"
#include "CTimeMgr.h"

#include "CMissile.h"

void CPlayer::update()
{
	Vec2 vPos = GetPos();
	if (KEY_HOLD(KEY::W)) {
		vPos.y -= 200.f * fDT;
	}
	if (KEY_HOLD(KEY::S)) {
		vPos.y += 200.f * fDT;
	}
	if (KEY_HOLD(KEY::A)) {
		vPos.x -= 200.f * fDT;
	}
	if (KEY_HOLD(KEY::D)) {
		vPos.x += 200.f * fDT;
	}

	if (KEY_TAP(KEY::SPACE)) {
		CreateMissile();
	}
	SetPos(vPos);
}

void CPlayer::CreateMissile()
{
	Vec2 vMissilePos = GetPos();
	vMissilePos.y -= GetScale().y / 2.f;
	CMissile* pMissile = new CMissile;

	pMissile->SetPos(vMissilePos);
	pMissile->SetScale(Vec2(25.f, 25.f));
	pMissile->SetDir(true);

	CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
	pCurScene->AddObject(pMissile, GROUP_TYPE::DEFAULT);
}

  • 위에서 정의한 매크로를 통해 입력 update를 구현하였고, 탄환을 쏘는 함수를 넣어주었다.
  1. CMissile.h
#pragma once
#include "CObject.h"
class CMissile :
    public CObject
{

private:
    float     m_fDir;//미사일 방향

public:
    void SetDir(bool _bUp) {
        if (_bUp) m_fDir = -1.f;
        else m_fDir = 1.f;
    }
public:
    virtual void update();
    virtual void render(HDC _dc);

 

public:
    CMissile();
    ~CMissile();
};

  • update로 움직임 구현, render로 다른 형상(동그라미)로 만들기
  • SetDir로 아래로 쏠지, 위로 쏠지.
  1. CMissile.cpp
#include "pch.h"
#include "CMissile.h"

#include "CTimeMgr.h"

CMissile::CMissile()
	:m_fDir(1.f)
{

}

CMissile::~CMissile()
{

}

void CMissile::update()
{
	Vec2 vPos = GetPos();

	vPos.y += 600.f * fDT * (float)m_fDir;

	SetPos(vPos);
}

void CMissile::render(HDC _dc)
{
	Vec2 vPos = GetPos();
	Vec2 vScale = GetScale();

	//부모 클래스 만들기. 
	//CObject::render(_dc);
	Ellipse(_dc, (int)(vPos.x - vScale.x / 2.f), (int)(vPos.y - vScale.y / 2.f),
		(int)(vPos.x + vScale.x / 2.f), (int)(vPos.y + vScale.y / 2.f));
}

  • 위에서 서술한 그대로의 상세 버전이다.
  1. CMonster.h
#pragma once
#include "CObject.h"

class CMonster :
    public CObject
{
private:
    float       m_fSpeed;
    Vec2        m_vCenterPos;
    float       m_fMaxMoveDistance;
    int         m_iDir; // 1, -1 (1 : Right, -1 : Left);

public:
    virtual void update();
    float GetSpeed() { return m_fSpeed; }
    void SetSpeed(float _f) { m_fSpeed = _f; }

    void SetCenterPos(Vec2 _vPos) { m_vCenterPos = _vPos; }
    void SetMaxMoveDistance(float _f) { m_fMaxMoveDistance = _f; }

public:
    CMonster();
    ~CMonster();
};

  • 몬스터 클래스다. 사실 정해진 반경을 움직이는 것 이외엔 기능이 없다.
  • 속도, 얼마 반경으로 움직일지 등…이 있다.
  1. CMonster.cpp
#include "pch.h"
#include "CMonster.h"

#include "CTimeMgr.h"
#include "math.h"

CMonster::CMonster()
	: m_fSpeed(100.f)
	, m_vCenterPos(Vec2(0.f, 0.f))
	, m_fMaxMoveDistance(50.f)
	, m_iDir(1)
{

}

CMonster::~CMonster()
{

}

void CMonster::update()
{
	Vec2 vCurPos = GetPos();

	//진행 방향으로 시간당 m_fSpeed만큼 이동. 
	vCurPos.x += fDT * m_fSpeed * m_iDir;

	//배회 거리 기준점을 넘어섰는지 확인. 
	//부들부들 거릴때가 있음... 한번에 크게(105) 넘어섰는데, 
	//다음 프레임에 조금밖에(-1) 못 되돌아 갔을때. 

	float fDistance = abs(m_vCenterPos.x - vCurPos.x) - m_fMaxMoveDistance;
	if (0.f < fDistance) {
		m_iDir *= -1;
		vCurPos.x += fDT * m_fSpeed * m_iDir;
	}
	
	SetPos(vCurPos);
}
  • 왕복운동을 구현하였다. 그에 대한 이슈는 주석으로 달아놓았다.
  1. CScene_Start.cpp
#include "pch.h"
#include "CScene_start.h"
#include "CObject.h"
#include "CCore.h"

#include "CPlayer.h"
#include "CMonster.h"

CScene_Start::CScene_Start()
{

}

CScene_Start::~CScene_Start()
{

}

void CScene_Start::Enter()
{
	//Object 추가.
	//실제 생성된 객체는 플레이어, 주소를 받은 건 부모 클래스. 
	CObject* pObj = new CPlayer;

	pObj->SetPos(Vec2(640.f, 384.f));
	pObj->SetScale(Vec2(100.f, 100.f));

	AddObject(pObj, GROUP_TYPE::DEFAULT);

	//몬스터 배치. 
	int iMonCount = 15;
	float fMoveDist = 25.f;
	float fObjScale = 50.f;
	Vec2 vResolution = CCore::GetInstance()->GetResolution();
	CMonster* pMonsterObj = nullptr;

	float fTerm = (vResolution.x - ((fMoveDist + fObjScale / 2.f) * 2)) / (float)(iMonCount - 1);
	for (int idx = 0; idx < iMonCount; idx++) {
		//Monster Object 추가.
		pMonsterObj = new CMonster;
		pMonsterObj->SetPos(Vec2((fMoveDist + fObjScale / 2.f) + (float)idx * fTerm, 50.f));
		pMonsterObj->SetCenterPos(pMonsterObj->GetPos());
		pMonsterObj->SetMaxMoveDistance(fMoveDist);
		pMonsterObj->SetScale(Vec2(fObjScale, fObjScale));
		AddObject(pMonsterObj, GROUP_TYPE::DEFAULT);
	}
}

void CScene_Start::Exit()
{

}

  • 몬스터의 숫자, Dist(이동 반경), 크기를 변수로 선언 후, 그걸 일정한 간격으로 배치하는 for문 기능이다.

  • 사실 Object의 특색을 부여하는 내용이다.
  • 숙제가 있는데…
  1. 플레이어 미사일 종류 추가.
  2. 몬스터 미사일 패턴. (다양하게 움직이는 거라던가, 다양한 미사일을 쏜다던가)

이다. 지금이 1월 27일 9시 42분이니, 아마 조금 시간이 흐른 밤에 작성할 것 같다. 이 게시글에 덧이어 작성할 예정이니… 아마 새벽에 구현이 전부 완료될 것 같다.

1시간 정도 걸린 것 같다.

수정한 내역을 보면.

  1. CMissile.h
#pragma once
#include "CObject.h"
class CMissile :
    public CObject
{

private:
    float       m_fYDir;            //미사일 Y축 방향
    float       m_fXDir;            //미사일 X축 방향. 
    float       m_Speed;            //미사일 속도
    int         m_moveType;         //0 : 직선, 1 : 원형 움직임. 

    float       m_circleSpeed;      // 원 각도 속도.
    float       m_circleDegree;     // 원의 호도. 
    float       m_Radius;           // 원의 반지름.

public:
    void SetYDir(bool _bUp) {
        if (_bUp) m_fYDir = -1.f;
        else m_fYDir = 1.f;
    }

    void SetXDir(int _bDir) {
        if (_bDir < 0) m_fXDir = -1.f;
        else if (_bDir > 0) m_fXDir = 0.f;
        else m_fXDir = 1.f;
    }

    void SetMoveType(int _iType) { m_moveType = _iType; }

    void SetSpeed(float _bSpeed) { m_Speed = _bSpeed; }
public:
    virtual void update();
    virtual void render(HDC _dc);

private:
    void circularMove();
    void lineMove();

    float Rad2Deg(const float _radian);
    float Deg2Rad(const float _degree);

public:
    CMissile();
    ~CMissile();
};

X축(왼쪽, 가만히, 오른쪽)으로 이동하는 변수를 두었고, Y축은 기본적인 설계는 별 다를게 없다.

또 원으로 돌면서 이동, 직선으로 이동 타입 구분을 위한 m_moveType을 두었고(enum으로 했어야 했나 하는 생각이 들긴한다.)

원으로 이동하려면 삼각함수 기반이 필요하기에, Rad2Deg, Deg2Rad와 원 운동 속도, Degree, Radius변수를 두었다.

  1. CMissile.cpp
#include "pch.h"
#include "CMissile.h"

#include "CTimeMgr.h"

#include <math.h>

//수식 계산을 위한 상수, 함수
constexpr float PI = 3.14159265359f;

CMissile::CMissile()
	:m_fYDir(1.f),
	m_fXDir(0.f),
	m_Speed(600.f),
	m_moveType(0),
	m_circleSpeed(360.f),
	m_circleDegree(0.f),
	m_Radius(100.f)
{

}

CMissile::~CMissile()
{

}

float CMissile::Rad2Deg(const float _radian) {
	return _radian * 180.f / PI;
}

float CMissile::Deg2Rad(const float _degree) {
	return _degree * PI / 180.f;
}

void CMissile::update()
{
	if (m_moveType == 0) {
		lineMove();
	}
	else {
		circularMove();
	}
}

void CMissile::render(HDC _dc)
{
	Vec2 vPos = GetPos();
	Vec2 vScale = GetScale();

	//부모 클래스 만들기. 
	//CObject::render(_dc);
	Ellipse(_dc, (int)(vPos.x - vScale.x / 2.f), (int)(vPos.y - vScale.y / 2.f),
		(int)(vPos.x + vScale.x / 2.f), (int)(vPos.y + vScale.y / 2.f));
}

void CMissile::circularMove()
{
	Vec2 vPos = GetPos();

	m_circleDegree += fDT * m_circleSpeed;
	vPos.y += m_Speed * fDT * (float)m_fYDir;

	float vRadian = Deg2Rad(m_circleDegree);
	vPos.x += m_Radius * cosf(vRadian) * fDT;
	vPos.y += m_Radius * sinf(vRadian) * fDT;

	SetPos(vPos);
}

void CMissile::lineMove()
{
	Vec2 vPos = GetPos();

	vPos.x += m_Speed * fDT * (float)m_fXDir;
	vPos.y += m_Speed * fDT * (float)m_fYDir;

	SetPos(vPos);
}

읽어보면 다 이해 되실거다.

  1. CMonster.h
#pragma once
#include "CObject.h"

class CMonster :
    public CObject
{
private:
    float       m_fSpeed;
    Vec2        m_vCenterPos;
    float       m_fMaxMoveDistance;
    int         m_iDir; // 1, -1 (1 : Right, -1 : Left);

    float       m_ShootingDistance;
    float       m_ShootingElapsedTime;
public:
    virtual void update();
    float GetSpeed() { return m_fSpeed; }
    void SetSpeed(float _f) { m_fSpeed = _f; }

    void SetCenterPos(Vec2 _vPos) { m_vCenterPos = _vPos; }
    void SetMaxMoveDistance(float _f) { m_fMaxMoveDistance = _f; }

private:
    void CreateMissile();

public:
    CMonster();
    ~CMonster();
};

일정 시간(무작위 가능)에 한 번 미사일을 쏘기 위한 변수, 함수를 넣었다.

  1. CMonster.cpp
#include "pch.h"
#include "CMonster.h"

#include "CSceneMgr.h"

#include "CScene.h"
#include "CTimeMgr.h"
#include "math.h"
#include "CMissile.h"
#include <random>

CMonster::CMonster()
	: m_fSpeed(100.f)
	, m_vCenterPos(Vec2(0.f, 0.f))
	, m_fMaxMoveDistance(50.f)
	, m_iDir(1)
	, m_ShootingDistance(0.f)
	, m_ShootingElapsedTime(0.f)
{
	std::random_device rd;
	std::mt19937 mt(rd());
	std::uniform_real_distribution<float> dist(1.2f, 3.f);
	
	m_ShootingDistance = dist(mt);
}

CMonster::~CMonster()
{

}

void CMonster::update()
{
	Vec2 vCurPos = GetPos();

	//진행 방향으로 시간당 m_fSpeed만큼 이동. 
	vCurPos.x += fDT * m_fSpeed * m_iDir;

	//배회 거리 기준점을 넘어섰는지 확인. 
	//부들부들 거릴때가 있음... 한번에 크게(105) 넘어섰는데, 
	//다음 프레임에 조금밖에(-1) 못 되돌아 갔을때. 

	float fDistance = abs(m_vCenterPos.x - vCurPos.x) - m_fMaxMoveDistance;
	if (0.f < fDistance) {
		m_iDir *= -1;
		vCurPos.x += fDT * m_fSpeed * m_iDir;
	}

	//일정 시간마다 총 쏘기.

	m_ShootingElapsedTime += fDT;

	if (m_ShootingDistance <= m_ShootingElapsedTime) {

		CreateMissile();
		m_ShootingElapsedTime = 0.f;
	}
	
	SetPos(vCurPos);
}

void CMonster::CreateMissile()
{
	Vec2 vMissilePos = GetPos();
	vMissilePos.y += GetScale().y / 2.f;
	CMissile* mMissile = new CMissile;
	mMissile->SetPos(vMissilePos);
	mMissile->SetScale(Vec2(15.f, 15.f));

	mMissile->SetXDir(-1);
	mMissile->SetYDir(false);
	mMissile->SetSpeed(250.f);
	mMissile->SetMoveType(1);

	CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
	pCurScene->AddObject(mMissile, GROUP_TYPE::DEFAULT);
}

초를 세서 시간 동기화를 하여, 총을 쏜다.

  1. CPlayer.cpp
#include "pch.h"
#include "CPlayer.h"

#include "CSceneMgr.h"
#include "CScene.h"
#include "CkeyMgr.h"
#include "CTimeMgr.h"

#include "CMissile.h"

void CPlayer::update()
{
	Vec2 vPos = GetPos();
	if (KEY_HOLD(KEY::W)) {
		vPos.y -= 200.f * fDT;
	}
	if (KEY_HOLD(KEY::S)) {
		vPos.y += 200.f * fDT;
	}
	if (KEY_HOLD(KEY::A)) {
		vPos.x -= 200.f * fDT;
	}
	if (KEY_HOLD(KEY::D)) {
		vPos.x += 200.f * fDT;
	}

	if (KEY_TAP(KEY::SPACE)) {
		CreateMissile();
	}
	SetPos(vPos);
}

void CPlayer::CreateMissile()
{
	CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
	Vec2 vMissilePos = GetPos();
	vMissilePos.y -= GetScale().y / 2.f;

	//가운데 탄환.
	CMissile* pMissile = new CMissile;
	pMissile->SetPos(vMissilePos);
	pMissile->SetScale(Vec2(25.f, 25.f));
	pMissile->SetYDir(true);
	pMissile->SetXDir(0);
	pMissile->SetMoveType(0);

	pCurScene->AddObject(pMissile, GROUP_TYPE::DEFAULT);

	//왼쪽 날아가는 탄환. 
	pMissile = new CMissile;

	pMissile->SetPos(vMissilePos);
	pMissile->SetScale(Vec2(25.f, 25.f));
	pMissile->SetYDir(true);
	pMissile->SetXDir(-1);
	pMissile->SetMoveType(0);

	pCurScene->AddObject(pMissile, GROUP_TYPE::DEFAULT);

	//오른쪽 날아가는 탄환.
	pMissile = new CMissile;

	pMissile->SetPos(vMissilePos);
	pMissile->SetScale(Vec2(25.f, 25.f));
	pMissile->SetYDir(true);
	pMissile->SetXDir(1);
	pMissile->SetMoveType(0);

	pCurScene->AddObject(pMissile, GROUP_TYPE::DEFAULT);
}

기존의 코드와 위에 수정한 것을 기반으로 왼쪽으로 45도, 직선, 오른쪽으로 45도 방향. 이렇게 3방향으로 총을 쏘도록 했다.

WINAPI 카테고리 내 다른 글 보러가기

댓글 남기기