[winAPI 15] Event Manager
μ λ² μκ°μ μ€λͺ νλ― μ΄λ² ν¬μ€ν μμ μ΄λ²€νΈ κ΄λ¦¬μλ₯Ό λ§λ€μ΄λ³΄λλ‘ νκ² λ€.
κ·Έ μ μ μ λ² μκ°μ Objectμ μ΄λ¦ λ³μ(strName)λ₯Ό λ£μ΄μ£Όμλλ° κ·Έμ κ΄λ ¨λ μΈν°νμ΄μ€ ν¨μλ₯Ό μμ±νλλ‘ νλ€.
// Object.h
// μ΄λ¦ κ΄λ ¨ ν¨μ μ€μ
void SetName(const wstring& _str) { strName = _str; }
const wstring& GetName() { return strName; }
본격μ μΈ EventManager ν΄λμ€λ₯Ό μμ±νλλ‘ νμ. μΌλ¨ μ΄λ²€νΈ νμ μλ μ΄λ€ κ²μ΄ μμκΉ? μ΄λ²€νΈλ μ΄λ ν μ½λ κΈ°μ μΌλ‘ μ΄μ νλ μμλ μμλλ° λ€μ νλ μμλ μκΈ°λ κ²½μ°λ₯Ό μλ―Ένλ€. μ°λ¦¬μ νλ‘κ·Έλ¨μμ λ―Έμ¬μΌ μμ±μ΄ ν΄λΉνλ€. (μ΄μ νλ μμλ μμλλ° λ€μ νλ μμλ μκ²¨μΌ ν¨)
μ΄λ²€νΈ νμ μ μ μνλλ‘ νμ. μ°μ ν¬κ² 3κ°μ§ κ²½μ°λ‘ μ€λΈμ νΈ μμ±, μ€λΈμ νΈ μμ , νλ©΄ μ νμ΄ μλ€.
// define.h
enum class EVENT_TYPE {
CREATE_OBJECT,
DELETE_OBJECT,
SCENE_CHAGNE,
END,
};
μΆν μ΄λ²€νΈ κ΄λ¦¬μλ μΆ©λκ³Όμ μ°κ³λ νμνκ² λ μμ μΈλ°, μΆ©λνλλ° λ 물체 μ€ νλκ° μμ΄μ§ μν©μμ μμΈ μ²λ¦¬κ° νμνκΈ° λλ¬Έμ΄λ€. exitνμ§ λͺ»ν μ±λ‘ μ£½μ μ€λΈμ νΈλ colμ΄ 0λ³΄λ€ ν¬κ² λ¨μ λ¨μ 물체μ μΆ©λλ°μ€κ° κ³μ λ λ(μΆ©λ λ μν)λ‘ νμλλ μ€λ₯λ₯Ό λ²νλ€.
λ¬΄νΌ μ΄λ²€νΈ ν΄λμ€λ₯Ό μμ±νλ©΄ μλμ κ°λ€.
// EventManager.h
#pragma once
struct Event{
EVENT_TYPE even;
DWORD_PTR lParam;
DWORD_PTR wParam;
};
class EventManager {
SINGLE(EventManager)
private:
vector<Event> vecEvent;
void Excute(const Event& _eve);
public:
void update();
void AddEvent(const Event& _eve) { vecEvent.push_back(_eve); }
};
// EventManager.cpp
#include "pch.h"
#include "EventManager.h"
#include "Object.h"
#include "SceneManager.h"
#include "Scene.h"
EventManager::EventManager()
{
}
EventManager::~EventManager()
{
}
void EventManager::Excute(const Event& _eve)
{
switch (_eve.even)
{
case EVENT_TYPE::CREATE_OBJECT:
{
// lParam : Object Adress
// wParam : Group Type
Object* newObj = (Object*)_eve.lParam;
GROUP_TYPE type = (GROUP_TYPE)_eve.wParam;
SceneManager::Instance()->GetCurScene()->AddObject(newObj, type);
}
break;
case EVENT_TYPE::DELETE_OBJECT:
break;
case EVENT_TYPE::SCENE_CHAGNE:
break;
default:
break;
}
}
void EventManager::update()
{
// μ΄λ²€νΈλ₯Ό μ²λ¦¬
for (size_t i = 0; i < vecEvent.size(); ++i) {
Excute(vecEvent[i]);
}
vecEvent.clear(); // μ²λ¦¬ λλ μ΄λ²€νΈλ μμ
}
// Player.cpp
void Player::CreateMissile()
{
// ....
// νμ¬μ¬μμ λ°λ‘ μΆκ°νμ§ μκ³ (κΈ°μ‘΄ μ½λμμ ) μ΄λ²€νΈλ₯Ό μμ±νλ κ² -> ν¨μ νΈμΆ
CreateObject(missile,GROUP_TYPE::PROJ_PALYER);
}
// func.h - μμ£Ό μ¬μ©νλ ν¨μλ₯Ό μ¬κΈ°μ μμ±νλλ‘ νλ€.
// μ΄ μΉκ΅¬λ pch.hμ μ°Έμ‘°νλλ‘ ν¨
class Object;
void CreateObject(Object* _obj, GROUP_TYPE _group);
// func.cpp
#include "pch.h"
#include "func.h"
#include "EventManager.h"
void CreateObject(Object* _obj, GROUP_TYPE _group)
{
Event evn = {};
evn.even = EVENT_TYPE::CREATE_OBJECT;
evn.lParam = (DWORD_PTR)_obj;
evn.wParam = (DWORD_PTR)_group;
EventManager::Instance()->AddEvent(evn);
}
μ΄λ²€νΈλ νμ¬ νλ μμ΄ λ€ κ·Έλ €μ§κ³ λ€μ νλ μμ λν μ 보λ₯Ό κ°κ³ μμμΌλ‘ Core ν΄λμ€μμ 맨 λ§μ§λ§μ update μμΌμ£Όμ΄μΌ νλ€.
// Core.cpp
void Core::Progress()
{
// Manager update
TimeManager::Instance()->update();
KeyManager::Instance()->update();
SceneManager::Instance()->update();
ColliderManager::Instance()->update();
// Rendering
// νλ©΄ clear
Rectangle(mDC, -1, -1, ptResolution.x + 1, ptResolution.y + 1);
SceneManager::Instance()->render(mDC);
BitBlt(hDC, 0, 0, ptResolution.x, ptResolution.y, mDC, 0, 0, SRCCOPY);
// TimeManager::Instance()->render();
// μ΄λ²€νΈ μ§μ°μ²λ¦¬ (맨 λ§μ§λ§μ μνν΄μ λ€μ νλ μμ λ°μλμ΄μΌ ν¨)
EventManager::Instance()->update();
}
updateν¨μμμ ν΄λΉ νλ μμμ λ°μν μ΄λ²€νΈλ₯Ό λͺ¨μ μ²λ¦¬νλλ‘ νλ€. μ²λ¦¬λ μ΄λ²€νΈμ κ²½μ° λ²‘ν°μμ μμ μμΌμ£Όμ.
Excuteν¨μλ μ΄λ²€νΈ μ’ λ₯μ λ°λΌμ μ²λ¦¬νλλ‘ νλ€.
μ€λΈμ νΈ μμ±μμμ Event ꡬ쑰체μ κ° λ³μλ€μ μ΄λ²€νΈ νμ κ³Ό μ€λΈμ νΈ μ£Όμ, μ€λΈμ νΈ κ·Έλ£Ή νμ μ μλ―Ένλ€. μ΄λ μ¬λ¬ μν©μ λ°λΌ λ©λͺ¨λ¦¬λ₯Ό μ§μ ν μ μλλ‘ DWORD_PTRμ μ¬μ©νλ€.
μ€λΈμ νΈ μμ± μμ κ° μ€λΈμ νΈμ λν μ 보λ₯Ό λ°νμΌλ‘ νμ¬ μ¬μ μ€λΈμ νΈλ₯Ό μΆκ°νλλ‘ νλ€.
μ€λΈμ νΈ μμ μ μ‘°κΈ μ΄λ ΅κ² λμνλ€. μμ± λλ 'μ λ°μ΄νΈ → λ λ(그리기) → λ€μ νλ μ λ°μ' μ΄λ κ² μλνμμ§λ§, μμ ν λλ λ€μ νλ μ λ°μ λ¨κ³μμ μ€λΈμ νΈκ° μμ λμλ€λ μ΄λ²€νΈκ° λ°μνμ§λ§, λ€μ νλ μμμ κ·Έλ₯Ό λ°μνκ³ κ·Έλ¦¬λ λ¨κ³(μ λ°μ΄νΈ, λ λ)μμλ μ΄ μ€λΈμ νΈμ μ£Όμλ₯Ό κ·Έλλ‘ κ°κ³ μκΈ° λλ¬Έμ μ΄λ₯Ό μ κ·Ό(μ°Έμ‘°)νλ € μλ μ λ€μ λ¬Έμ κ° λ°μν μ μλ€.
λ°λΌμ μμ μ΄λ²€νΈκ° λ±λ‘λλ©΄ μ€λΈμ νΈλ₯Ό μμ νλ€λ νΈλ¦¬κ±°λ₯Ό λ°μν΄μΌ νλ€. νΈλ¦¬κ±°λ₯Ό λ°μνμ¬ λ€μ νλ μ μ λ€μκ² μ΄ μΉκ΅¬κ° κ³§ μμ λ¨μ μλ¦¬κ³ (Dead μν - μ£½μ μ€λΈμ νΈμ΄λ μμ ν μμ λμ§ μμ μν) μ΄λ₯Ό μ°Έμ‘°νκ³ μλ μ λ€μ΄ μ€λΉν μ μκ² νκ³ (μ°Έμ‘°ν κ²λ€ μ 리) κ·Έ λ€μ νλ μ(2νλ μ λ€)μμ μμ λμ΄ μμ΄μ§κ² ꡬνν΄μΌ νλ€.
→ μμ μμ λ μ΄λ²€νΈλ₯Ό λͺ¨μ κ²μ΄ νμνλ€ = vecDead
// EventManager.h
lass EventManager {
SINGLE(EventManager)
private:
vector<Event> vecEvent;
vector<Object*> vecDead; // μΆκ°
void Excute(const Event& _eve);
public:
void update();
void AddEvent(const Event& _eve) { vecEvent.push_back(_eve); }
};
// EventManager.cpp
void EventManager::Excute(const Event& _eve)
{
switch (_eve.even)
{
case EVENT_TYPE::CREATE_OBJECT:
{
// lParam : Object Adress
// wParam : Group Type
Object* newObj = (Object*)_eve.lParam;
GROUP_TYPE type = (GROUP_TYPE)_eve.wParam;
SceneManager::Instance()->GetCurScene()->AddObject(newObj, type);
}
break;
case EVENT_TYPE::DELETE_OBJECT:
{
// lParam : Object Adress
// wParam : Group Type
Object* deadObj = (Object*)_eve.lParam;
deadObj->SetDead();
vecDead.push_back(deadObj);
}
break;
case EVENT_TYPE::SCENE_CHAGNE:
break;
default:
break;
}
}
void EventManager::update()
{
// μ΄μ νλ μμ μμλ μ λ€ μ²λ¦¬z
for (size_t i = 0; i < vecDead.size(); ++i) {
delete vecDead[i];
}
vecDead.clear();
// μ΄λ²€νΈ μ²λ¦¬
for (size_t i = 0; i < vecEvent.size(); ++i) {
Excute(vecEvent[i]);
}
vecEvent.clear(); // μ²λ¦¬ λλ μ΄λ²€νΈλ μμ
}
μ€λΈμ νΈλ₯Ό μμ νλ μ΄λ²€νΈμμλ Objectλ₯Ό Dead μνλ‘ λ³κ²½νκ³ μμ μμ μ€λΈμ νΈλ₯Ό λͺ¨μλλ μΌμ΄λ€. κ·Έλ¦¬κ³ μ λ°μ΄νΈ ν¨μ λ΄μμ νμ¬ νλ μμ μ΄λ²€νΈλ₯Ό μ²λ¦¬νκΈ° μ μ μ΄μ νλ μμ μμ λ¨λ μ λ€μ μ²λ¦¬νλ κ²μ΄ νμνλ€.
μ€λΈμ νΈλ₯Ό Deadμνλ‘ λ³κ²½νκΈ°
// Object.h
#pragma once
class Collider;
class Object {
private:
wstring strName;
Vec2 vPos;
Vec2 vScale;
Collider* collider;
bool act; // μΆκ° : νμ±ν μν
public:
Object();
virtual ~Object();
void setPos(Vec2 _vPos) { vPos = _vPos; }
void setScale(Vec2 _vScale) { vScale = _vScale; }
Vec2 getPos() { return vPos; }
Vec2 getScale() { return vScale; }
void SetName(const wstring& _str) { strName = _str; }
const wstring& GetName() { return strName; }
bool IsDead() { return !act; } // μΆκ°
Collider* GetCollider() { return collider; }
void CreateCollider();
virtual void OnCollision(Collider* _other) {}
virtual void OnCollisionEnter(Collider* _other) {}
virtual void OnCollisionExit(Collider* _other) {}
public:
virtual void update() = 0;
virtual void render(HDC _hdc);
virtual void finalUpdate() final;
void commponentRender(HDC _hdc);
void SetDead() { act = false; } // μΆκ°. 무쑰건 μ΄λ²€νΈ ν΄λμ€λ§ μ¬μ©κ°λ₯
friend class EvenManager; // μΆκ°
};
μ€λΈμ νΈ λ΄μ μ΄ μ€λΈμ νΈκ° νμ±νλμ΄ μλμ§λ₯Ό μ μ μλ λ³μ(act)λ₯Ό λ§λ€κ³ κ΄λ ¨ μΈν°νμ΄μ€ ν¨μλ₯Ό μμ±νλ€. μ΄λ μ£½μλμ§ μλ €μ£Όλ ν¨μ IsDead()μ actλ₯Ό μ€μ νλ SetDead()λ₯Ό λ§λ λ€. νμ§λ§ λͺ¨λ μ€λΈμ νΈκ° μκΈ° μμ μ΄ μ£½μλμ§ μ΄μλμ§λ₯Ό μ νμ§ μκ³ λ¬΄μ‘°κ±΄ μ΄λ²€νΈ κ΄λ¦¬μλ§ μ€μ νλλ‘ privateμΌλ‘ μ€μ νκ³ μ΄λ²€νΈ κ΄λ¦¬μλ₯Ό μΉκ΅¬λ‘ ν΄μ£Όλ©΄ λλ€.
// Scene.cpp
void Scene::update()
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i) {
for (size_t j = 0; j < arrObj[i].size(); ++j) {
if (!arrObj[i][j]->IsDead()) {
arrObj[i][j]->update(); // NO update
}
}
}
}
void Scene::finalUpdate()
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i) {
for (size_t j = 0; j < arrObj[i].size(); ++j) {
arrObj[i][j]->finalUpdate();
// μμ λλ μ λ€μ΄ μΆ©λμ΄ κ³μ λμ΄μΌ νκΈ°μ ν΄μΌν¨
}
}
}
void Scene::render(HDC _hdc)
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i) {
vector<Object*>::iterator iter = arrObj[i].begin();
for (; iter != arrObj[i].end();) {
if (!(*iter)->IsDead()) {
(*iter)->render(_hdc);
++iter;
}
else // μμ λμ΄μΌ νλ κ²½μ°
{
iter = arrObj[i].erase(iter);
}
}
}
}
μ€λΈμ νΈμ νμ± μ¬λΆμ λ°λΌ updateμ renderν΄μ£Όμ΄μΌ νλ€. λ¨ finalUpdateλ μμ λλ μ€λΈμ νΈμ μΆ©λ체 μνκ° κ³μ updateλμ΄μΌ νκΈ°μ λ³κ²½νμ§ μμμΌ νλ€.
λͺ¬μ€ν°κ° λ―Έμ¬μΌμ λ§μΌλ©΄ μμ΄μ§λλ‘ ν΄λ³΄μ.
// Player.cpp
void Player::CreateMissile()
{
Vec2 missilePos = getPos();
missilePos.y -= getScale().y / 2.f;
Missile* missile = new Missile;
missile->SetName(L"Missile_player");
missile->setPos(missilePos);
missile->setScale(Vec2(25.f, 25.f));
missile->SetDir(Vec2(0.f, -1.f));
// νμ¬μ¬μμ λ°λ‘ μΆκ°νμ§ μκ³ μ΄λ²€νΈλ₯Ό μμ±νλ κ² -> ν¨μ νΈμΆ
CreateObject(missile,GROUP_TYPE::PROJ_PALYER);
}
// Monster.cpp
void Monster::OnCollisionEnter(Collider* _other)
{
Object* otherObj = _other->GetObj();
if (otherObj->GetName() == L"Missile_player") {
DeleteObject(this);
}
}
// TimeManager.cpp
void TimeManager::update()
{
QueryPerformanceCounter(&curCount);
dDT = (double)(curCount.QuadPart - prevCount.QuadPart) / (double)prequency.QuadPart;
prevCount = curCount;
#ifdef _DEBUG
// λλ²κ·Έ λͺ¨λμμ μ€λ¨μ μ€λ κ±Έμ΄λλ©΄
// μκ°μ΄ λ§λ μλκ² μ»€μ§ μ μμ
if (dDT > (1. / 60.))
dDT = (1. / 60.);
#endif
}
μ, λ§μ½μ μΆ©λνλλ° λͺ¬μ€ν°κ° ν λ²μ μ£½μ§ μλ κ²½μ°λ μ‘΄μ¬ν μ μλ€. μ΄λ λ―Έμ¬μΌμ΄λ μΆ©λνλ€κ³ νλ©΄ λͺ¬μ€ν°μ μΆ©λ μΉ΄μ΄ν°λ 1μ΄μμΌλ‘ 체ν¬λ°μ€κ° λ λ(μΆ©λνμ) λ¨μ μλ μλ€. μλμ μ½λ μ°Έκ³ .
// Scene_start.cpp
void Scene_Start::Enter()
{
// ...
for (int i = 0; i < monCount; ++i) {
// ...
monsterObj->SetName(L"Monster");
// ...
}
// ...
ColliderManager::Instance()->CheckGroup(GROUP_TYPE::MONSTER, GROUP_TYPE::PROJ_PALYER);
}
// Missile.cpp
Missile::Missile()
: theta(PI/4.f)
, dir(Vec2(1.f, 1.f))
{
dir.Normalize();
CreateCollider();
GetCollider()->SetScale(Vec2(15.f, 15.f)); // ν¬κΈ° μ€μ
}
void Missile::OnCollisionEnter(Collider* _other)
{
Object* other = _other->GetObj();
if (other->GetName() == L"Monster") {
DeleteObject(this);
}
}
μ΄ μ€λ₯λ₯Ό ν΄κ²°νκΈ° μν΄μλ μΆ©λ μμ μ λν΄ μκΈΈ μ μλ μν©μ μΆ©λ κ·Έλ£Ήμ μ λ°μ΄νΈ λΆλΆμμ κ³ λ €ν΄ μ£Όμ΄μΌ νλ€.
// ColliderManager.cpp
void ColliderManager::CollisionUpdateGroup(GROUP_TYPE _left, GROUP_TYPE _right)
{
// ...
if (IsCollision(leftCol, rightCol)) {
// νμ¬ μΆ©λ μ€μ΄λ€
if (iter->second) {
// μ΄μ μλ μΆ©λνκ³ μμλ€ - μΆ©λ μ€
if (vecLeft[i]->IsDead() || vecRight[j]->IsDead()) {
// κ·Όλ° λ μ€ νλκ° μμ μμ μ΄λΌλ©΄,
// μΆ©λ ν΄μ νλ€.
leftCol->OnCollisionExit(rightCol);
rightCol->OnCollisionExit(leftCol);
iter->second - false;
}
else {
leftCol->OnCollision(rightCol);
rightCol->OnCollision(leftCol);
}
}
else {
// μ΄μ μλ μΆ©λνμ§ μμλ€ - λ§ μΆ©λν¨
if (!vecLeft[i]->IsDead() || vecRight[j]->IsDead()) {
// κ·Όλ° λ μ€ νλκ° μμ μμ μ΄λΌλ©΄,
// = μΆ©λνλ €λ μκ° μμ λ κ² κ°μ
// μΆ©λ νμ§ μμ κ²μΌλ‘ μ·¨κΈ
leftCol->OnCollisionEnter(rightCol);
rightCol->OnCollisionEnter(leftCol);
iter->second = true;
}
}
}
else { // νμ¬ μΆ©λνκ³ μμ§ μλ€.
if (iter->second) {
// μ΄μ μλ μΆ©λνκ³ μμλ€ - μΆ©λμμ λ λκ².
leftCol->OnCollisionExit(rightCol);
rightCol->OnCollisionExit(leftCol);
iter->second = false;
}
}
// ...
}
λͺ¬μ€ν°μ νΉμ hpλ₯Ό κ±Έκ³ λ―Έμ¬μΌμ λΏμ λλ§λ€ νΌ 1μ κΉμ보λλ‘ νμ.
// Monster.cpp
void Monster::OnCollisionEnter(Collider* _other)
{
Object* otherObj = _other->GetObj();
if (otherObj->GetName() == L"Missile_player") {
hp -= 1;
if(hp <= 0)
DeleteObject(this);
}
}
5λ λ리면 λͺ¬μ€ν°κ° μ£½μ΄ μμ΄μ§λ€.
[ μ½λ ]
https://github.com/MiyeongEom/GameBasic/commit/ee48314c5fa33a9965351a064fe3a05e843e4f2b
~ EventManager · MiyeongEom/GameBasic@ee48314
MiyeongEom committed Jun 9, 2024
github.com