WIN32 Object + 숙제
카테고리: WINAPI
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.
- 규모가 커지다보니 복붙하기가 어려워졌다.. 앞으론 코드에다가 복붙 해야할 것 같다.
- 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으로 따로따로 매크로 처리 해주었다.
- 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과 그와 관련된 쓸모없는 기능들을 정리하였다.
- 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함수를 만들어주었다.
- 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를 가상함수로 만들어주었다.
- 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));
}
- 사실 변경점이 없긴한데, 일단…
- CPlayer.h
#pragma once
#include "CObject.h"
class CPlayer :
public CObject
{
public :
virtual void update();
private:
void CreateMissile();
};
- 순수 가상함수인 update를 구현하고, 미사일을 쏘는 함수를 넣어주었다.
- 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를 구현하였고, 탄환을 쏘는 함수를 넣어주었다.
- 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로 아래로 쏠지, 위로 쏠지.
- 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));
}
- 위에서 서술한 그대로의 상세 버전이다.
- 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();
};
- 몬스터 클래스다. 사실 정해진 반경을 움직이는 것 이외엔 기능이 없다.
- 속도, 얼마 반경으로 움직일지 등…이 있다.
- 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);
}
- 왕복운동을 구현하였다. 그에 대한 이슈는 주석으로 달아놓았다.
- 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월 27일 9시 42분이니, 아마 조금 시간이 흐른 밤에 작성할 것 같다. 이 게시글에 덧이어 작성할 예정이니… 아마 새벽에 구현이 전부 완료될 것 같다.
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변수를 두었다.
- 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);
}
읽어보면 다 이해 되실거다.
- 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();
};
일정 시간(무작위 가능)에 한 번 미사일을 쏘기 위한 변수, 함수를 넣었다.
- 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);
}
초를 세서 시간 동기화를 하여, 총을 쏜다.
- 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방향으로 총을 쏘도록 했다.
댓글 남기기