Skip to content

Instantly share code, notes, and snippets.

@copyrat90
Last active February 20, 2021 08:43
Show Gist options
  • Save copyrat90/45f2e8bc79650ea2c98b064f1f624e93 to your computer and use it in GitHub Desktop.
Save copyrat90/45f2e8bc79650ea2c98b064f1f624e93 to your computer and use it in GitHub Desktop.
std::function callback example (video game)
#include <iostream>
class Character
{
public:
Character(int maxHP) : m_maxHP(maxHP), m_currentHP(maxHP) {};
void Update()
{
if (m_isPoisoned)
{
std::cout << "독으로 70의 데미지를 입었다!\n";
m_currentHP -= 70;
}
else
{
std::cout << "아무 일도 일어나지 않았다.\n";
}
m_currentHP = (m_currentHP < 0) ? 0 : m_currentHP;
std::cout << "HP : " << m_currentHP << " / " << m_maxHP << "\n";
// 체력이 다 떨어지면 gm.GameOver() 를 호출하고 싶다. (Callback)
// gm 객체의 멤버함수를 호출해야하는데, gm 에 접근을 못하는 게 문제.
if (m_currentHP <= 0)
; // 어떻게 해야 할까?
}
void SetPlayerPoison(bool isPoisoned)
{
m_isPoisoned = isPoisoned;
std::cout << "3턴이 돼서 독에 걸렸다!\n";
}
bool GetPlayerPoison() const { return m_isPoisoned; }
private:
const int m_maxHP;
int m_currentHP;
bool m_isPoisoned = false;
};
class GameManager
{
public:
GameManager() : m_player(100) {}
void Update()
{
++m_turn;
std::cout << "==== 제 " << m_turn << "턴 ====\n";
if (m_turn >= 3 && !m_player.GetPlayerPoison())
m_player.SetPlayerPoison(true);
m_player.Update();
}
bool GetGameOverStatus() const { return m_isGameOver; }
private:
Character m_player {100};
int m_turn = 0;
bool m_isGameOver = false;
void GameOver(bool isPoisonDeath)
{
m_isGameOver = true;
if (isPoisonDeath)
std::cout << "독으로 인한 사망! 게임 오버!\n";
else
std::cout << "타격으로 인한 사망! 게임 오버!\n";
}
};
int main()
{
GameManager gm;
while (!gm.GetGameOverStatus())
gm.Update();
}
#include <iostream>
// std::function 을 위해 functional 헤더를 포함한다.
#include <functional>
class Character
{
public:
Character(int maxHP) : m_maxHP(maxHP), m_currentHP(maxHP) {};
void Update()
{
if (m_isPoisoned)
{
std::cout << "독으로 70의 데미지를 입었다!\n";
m_currentHP -= 70;
}
else
{
std::cout << "아무 일도 일어나지 않았다.\n";
}
m_currentHP = (m_currentHP < 0) ? 0 : m_currentHP;
std::cout << "HP : " << m_currentHP << " / " << m_maxHP << "\n";
// 체력이 다 떨어지면 gm.GameOver() 를 호출한다. (Callback)
if (m_currentHP <= 0)
c_onPlayerDeath(true);
}
void SetPlayerPoison(bool isPoisoned)
{
m_isPoisoned = isPoisoned;
std::cout << "3턴이 돼서 독에 걸렸다!\n";
}
bool GetPlayerPoison() const { return m_isPoisoned; }
// 플레이어 사망시 호출될 GameManager 쪽 멤버함수를 넣어준다.
void Set_OnPlayerDeath(std::function<void(bool)> onPlayerDeath)
{
// 매개변수는 어차피 없어질 스택변수니 복사보단 이동시키는 게 나을 듯.
c_onPlayerDeath = std::move(onPlayerDeath);
}
private:
const int m_maxHP;
int m_currentHP;
bool m_isPoisoned = false;
// Event Handler 를 받을 함수 객체 선언
std::function<void(bool)> c_onPlayerDeath;
};
class GameManager
{
public:
GameManager() : m_player(100)
{
// 플레이어 사망시 호출될 GameOver(bool) 멤버함수를 넣어준다.
// m_player 의 체력이 0이 되면,
// Character 쪽에서 gm.GameOver(bool) 를 되호출한다. (Callback)
// 이 때, 멤버함수는 std::bind(...) 로 아래 형식으로 전달해줘야 함.
// std::bind(전달할 멤버함수의 포인터, 대상 객체의 포인터, 함수 인자)
// 함수 인자는 std::placeholders::_N 으로, N은 1~30 사이이다.
m_player.Set_OnPlayerDeath(
std::bind(&GameManager::GameOver, this, std::placeholders::_1)
);
}
void Update()
{
++m_turn;
std::cout << "==== 제 " << m_turn << "턴 ====\n";
if (m_turn >= 3 && !m_player.GetPlayerPoison())
m_player.SetPlayerPoison(true);
m_player.Update();
}
bool GetGameOverStatus() const { return m_isGameOver; }
private:
Character m_player;
int m_turn = 0;
bool m_isGameOver = false;
void GameOver(bool isPoisonDeath)
{
m_isGameOver = true;
if (isPoisonDeath)
std::cout << "독으로 인한 사망! 게임 오버!\n";
else
std::cout << "타격으로 인한 사망! 게임 오버!\n";
}
};
int main()
{
GameManager gm;
while (!gm.GetGameOverStatus())
gm.Update();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment