~cpp
class GameObject { ... };
class SpaceShip: public GameObject { ... };
class SpaceStation: public GameObject { ... };
class Asteroid: public GameObject { ... };
~cpp
void checkForCollision(GameObject& object1, GameObject& object2)
{
if (theyJustCollided(object1, object2)) {
processCollision(object1, object2);
}
else {
...
}
}
~cpp dispatch [출발시키다] 다중 프로그래밍 시스템에서 다음에 처리될 작업을 선택하여 실행시키는 것. 즉, 대기 열에서 기다리고 있는 프로세스를 선택하여 중앙 처리 장치의 사용 권한을 부여하는 작업. 출처:한메 myQuickFind 컴용어 사전
~cpp
class GameObject {
public:
virtual void collide(GameObject& otherObject) = 0;
...
};
class SpaceShip: public GameObject {
public:
virtual void collide(GameObject& otherObject);
...
};
~cpp
// 충돌 객체의 종류를 알수가 없다면, 예외를 던진다.
class CollisionWithUnknownObject { // 던질 예외 객체
public:
CollisionWithUnknownObject(GameObject& whatWeHit);
...
};
void SpaceShip::collide(GameObject& otherObject)
{
const type_info& objectType = typeid(otherObject); // 충돌의 형을 알아 낸다.
if (objectType == typeid(SpaceShip)) {
SpaceShip& ss = static_cast<SpaceShip&>(otherObject);
SpaceShip-SpaceShip 간의 충돌 수행;
}
else if (objectType == typeid(SpaceStation)) {
SpaceStation& ss = static_cast<SpaceStation&>(otherObject);
SpaceShip-SpaceStation 간의 충돌 수행;
}
else if (objectType == typeid(Asteroid)) {
Asteroid& a = static_cast<Asteroid&>(otherObject);
SpaceShip-Asteroid 간의 충돌 수행;
}
else {
throw CollisionWithUnknownObject(otherObject);
}
}
~cpp
class SpaceShip; // 이름 선언
class SpaceStation;
class Asteroid;
class GameObject {
public:
virtual void collide(GameObject& otherObject) = 0;
virtual void collide(SpaceShip& otherObject) = 0;
virtual void collide(SpaceStation& otherObject) = 0;
virtual void collide(Asteroid& otherobject) = 0;
...
};
class SpaceShip: public GameObject {
public:
virtual void collide(GameObject& otherObject);
virtual void collide(SpaceShip& otherObject);
virtual void collide(SpaceStation& otherObject);
virtual void collide(Asteroid& otherobject);
...
};
~cpp
void SpaceShip::collide(GameObject& otherObject)
{
otherObject.collide(*this);
}
~cpp
void SpaceShip::collide(SpaceShip& otherObject)
{
SpaceShip-SpaceShip 간의 충돌을 수행한다.;
}
void SpaceShip::collide(SpaceStation& otherObject)
{
SpaceShip-SpaceStation 간의 충돌을 수행한다.;
}
void SpaceShip::collide(Asteroid& otherObject)
{
SpaceShip-Asteroid 간의 충돌을 수행한다.;
}
~cpp
class GameObject {
public:
virtual void collide(GameObject& otherObject) = 0;
...
};
class SpaceShip: public GameObject {
public:
virtual void collide(GameObject& otherObject);
virtual void hitSpaceShip(SpaceShip& otherObject);
virtual void hitSpaceStation(SpaceStation& otherObject);
virtual void hitAsteroid(Asteroid& otherobject);
...
};
void SpaceShip::hitSpaceShip(SpaceShip& otherObject)
{
SpaceShip-SpaceShip 간의 충돌 수행;
}
void SpaceShip::hitSpaceStation(SpaceStation& otherObject)
{
SpaceShip-SpaceStation 간의 충돌 수행;
}
void SpaceShip::hitAsteroid(Asteroid& otherObject)
{
SpaceShip-Asteroid 간의 충돌 수행;
}
~cpp
class SpaceShip: public GameObject {
private:
typedef void (SpaceShip::*HitFunctionPtr)(GameObject&);
static HitFunctionPtr lookup(const GameObject& whatWeHit);
...
};
~cpp
void SpaceShip::collide(GameObject& otherObject)
{
HitFunctionPtr hfp = lookup(otherObject); // 호출할 함수를 찾는다.
if (hfp) { // 함수를 찾았으면 호출한다.
(this->*hfp)(otherObject);
}
else {
throw CollisionWithUnknownObject(otherObject);
}
}
~cpp
class SpaceShip: public GameObject {
private:
typedef void (SpaceShip::*HitFunctionPtr)(GameObject&);
typedef map<string, HitFunctionPtr> HitMap;
...
};
SpaceShip::HitFunctionPtr
SpaceShip::lookup(const GameObject& whatWeHit)
{
static HitMap collisionMap;
...
}
~cpp
SpaceShip::HitFunctionPtr
SpaceShip::lookup(const GameObject& whatWeHit)
{
static HitMap collisionMap; // 초기화 관련은 다음 주제에서 살핀다.
// 검색 결과의 iterator를 생성한다. (Item 35참고)
HitMap::iterator mapEntry= collisionMap.find(typeid(whatWeHit).name());
// 현재 map의 인자들이 있는가 살핀다.
if (mapEntry == collisionMap.end()) return 0;
// 짝지어진 함수 포인터를 반환한다.
return (*mapEntry).second;
}
~cpp
// An incorrect implementation
SpaceShip::HitFunctionPtr
SpaceShip::lookup(const GameObject& whatWeHit)
{
static HitMap collisionMap;
collisionMap["SpaceShip"] = &hitSpaceShip;
collisionMap["SpaceStation"] = &hitSpaceStation;
collisionMap["Asteroid"] = &hitAsteroid;
...
}
~cpp
class SpaceShip: public GameObject {
private:
static HitMap initializeCollisionMap();
...
};
SpaceShip::HitFunctionPtr
SpaceShip::lookup(const GameObject& whatWeHit)
{
static HitMap collisionMap = initializeCollisionMap();
...
}
~cpp
class SpaceShip: public GameObject {
private:
static HitMap * initializeCollisionMap();
...
};
SpaceShip::HitFunctionPtr
SpaceShip::lookup(const GameObject& whatWeHit)
{
static auto_ptr<HitMap> collisionMap(initializeCollisionMap());
...
}
~cpp
SpaceShip::HitMap * SpaceShip::initializeCollisionMap()
{
HitMap *phm = new HitMap;
(*phm)["SpaceShip"] = &hitSpaceShip;
(*phm)["SpaceStation"] = &hitSpaceStation;
(*phm)["Asteroid"] = &hitAsteroid;
return phm;
}
~cpp
// 않좋은 생각
SpaceShip::HitMap * SpaceShip::initializeCollisionMap()
{
HitMap *phm = new HitMap;
(*phm)["SpaceShip"] = reinterpret_cast<HitFunctionPtr>(&hitSpaceShip);
(*phm)["SpaceStation"] = reinterpret_cast<HitFunctionPtr>(&hitSpaceStation);
(*phm)["Asteroid"] = reinterpret_cast<HitFunctionPtr>(&hitAsteroid);
return phm;
}
~cpp
class GameObject { // this is unchanged
public:
virtual void collide(GameObject& otherObject) = 0;
...
};
class SpaceShip: public GameObject {
public:
virtual void collide(GameObject& otherObject);
// 함수의 모든 인자를 GameObject 로 바꾸었다.
virtual void hitSpaceShip(GameObject& spaceShip);
virtual void hitSpaceStation(GameObject& spaceStation);
virtual void hitAsteroid(GameObject& asteroid);
...
};
~cpp
SpaceShip::HitMap * SpaceShip::initializeCollisionMap()
{
HitMap *phm = new HitMap;
(*phm)["SpaceShip"] = &hitSpaceShip;
(*phm)["SpaceStation"] = &hitSpaceStation;
(*phm)["Asteroid"] = &hitAsteroid;
return phm;
}
~cpp
void SpaceShip::hitSpaceShip(GameObject& spaceShip)
{
SpaceShip& otherShip = dynamic_cast<SpaceShip&>(spaceShip);
SpaceShip-SpaceShip 간의 충돌 수행;
}
void SpaceShip::hitSpaceStation(GameObject& spaceStation)
{
SpaceStation& station = dynamic_cast<SpaceStation&>(spaceStation);
SpaceShip-SpaceStation 간의 충돌 수행;
}
void SpaceShip::hitAsteroid(GameObject& asteroid)
{
Asteroid& theAsteroid = dynamic_cast<Asteroid&>(asteroid);
SpaceShip-Asteroid 간의 충돌 수행;
}
~cpp
#include "SpaceShip.h"
#include "SpaceStation.h"
#include "Asteroid.h"
namespace { // 이름 없는 namespace(이름 공간)? 아래 설명을 보자.
// 충돌 처리 함수 첫번째
void shipAsteroid(GameObject& spaceShip, GameObject& asteroid);
void shipStation(GameObject& spaceShip, GameObject& spaceStation);
void asteroidStation(GameObject& asteroid, GameObject& spaceStation);
...
// 두번째 충돌 처리 함수들, 첫번째 인자를 바꾸어서 delegate 하는 것이다.
void asteroidShip(GameObject& asteroid, GameObject& spaceShip)
{ shipAsteroid(spaceShip, asteroid); }
void stationShip(GameObject& spaceStation, GameObject& spaceShip)
{ shipStation(spaceShip, spaceStation); }
void stationAsteroid(GameObject& spaceStation, GameObject& asteroid)
{ asteroidStation(asteroid, spaceStation); }
...
// 형/함수 로 관련 배열 만든느 과정, 설명 부분 참고
typedef void (*HitFunctionPtr)(GameObject&, GameObject&);
typedef map< pair<string,string>, HitFunctionPtr > HitMap;
pair<string,string> makeStringPair(const char *s1, const char *s2);
HitMap * initializeCollisionMap();
HitFunctionPtr lookup(const string& class1, const string& class2);
} // namespace 끝
void processCollision(GameObject& object1, GameObject& object2)
{
HitFunctionPtr phf = lookup(typeid(object1).name(),typeid(object2).name());
if (phf) phf(object1, object2);
else throw UnknownCollision(object1, object2);
}
~cpp
// 두가지의 char* 리터럴로 pair<string,string> 객체를 생성한다.
// 이는 initializeCollisionMap에서 사용된다. 반환 인자의 최적화는 Item 20을 참고하라.
namespace { // 이름 없는 namespace(이름 공간) 다시? 글에 설명 참고
pair<string,string> makeStringPair(const char *s1, const char *s2)
{ return pair<string,string>(s1, s2); }
} // namespace 끝
namespace { // 아직도 이름없는 namespace(이름공간) ? 글에 설명 참고
HitMap * initializeCollisionMap()
{
HitMap *phm = new HitMap;
(*phm)[makeStringPair("SpaceShip","Asteroid")] = &shipAsteroid;
(*phm)[makeStringPair("SpaceShip", "SpaceStation")] = &shipStation;
...
return phm;
}
} // end namespace
~cpp
namespace { // 밑에 설명한다 밑어 주세요.
HitFunctionPtr lookup(const string& class1, const string& class2)
{
static auto_ptr<HitMap> collisionMap(initializeCollisionMap());
// make_pair에 관해 글에 설명한다.
HitMap::iterator mapEntry = collisionMap->find(make_pair(class1, class2));
if (mapEntry == collisionMap->end()) return 0;
return (*mapEntry).second;
}
} // namespace 끝
~cpp HitMap::iterator mapEntry = collisionMap->find(pair<string,string>(class1, class2));
~cpp void shipAsteroid(GameObject& spaceShip, GameObject& asteroid);
~cpp
class CollisionMap {
public:
typedef void (*HitFunctionPtr)(GameObject&, GameObject&);
void addEntry(const string& type1, const string& type2,
HitFunctionPtr collisionFunction,
bool symmetric = true); // 아래 설명 참고
void removeEntry(const string& type1, const string& type2);
HitFunctionPtr lookup(const string& type1, const string& type2);
// 이 함수는 map의 참조를 반환한다. Item 26참고
static CollisionMap& theCollisionMap();
private:
// 사역으로 묶는 것은 map을 여러게 만드는걸 방지 (Item 26참고)
CollisionMap();
CollisionMap(const CollisionMap&);
};
~cpp
void shipAsteroid(GameObject& spaceShip,
GameObject& asteroid);
CollisionMap::theCollisionMap().addEntry("SpaceShip",
"Asteroid",
&shipAsteroid);
void shipStation(GameObject& spaceShip,
GameObject& spaceStation);
CollisionMap::theCollisionMap().addEntry("SpaceShip",
"SpaceStation",
&shipStation);
void asteroidStation(GameObject& asteroid,
GameObject& spaceStation);
CollisionMap::theCollisionMap().addEntry("Asteroid",
"SpaceStation",
&asteroidStation);
~cpp
class RegisterCollisionFunction {
public:
RegisterCollisionFunction(
const string& type1,
const string& type2,
CollisionMap::HitFunctionPtr collisionFunction,
bool symmetric = true)
{
CollisionMap::theCollisionMap().addEntry(type1, type2,
collisionFunction,
symmetric);
}
};
~cpp
RegisterCollisionFunction cf1("SpaceShip", "Asteroid",
&shipAsteroid);
RegisterCollisionFunction cf2("SpaceShip", "SpaceStation",
&shipStation);
RegisterCollisionFunction cf3("Asteroid", "SpaceStation",
&asteroidStation);
...
int main(int argc, char * argv[])
{
...
}
~cpp
class Satellite: public GameObject { ... };
~cpp
void satelliteShip(GameObject& satellite,
GameObject& spaceShip);
void satelliteAsteroid(GameObject& satellite,
GameObject& asteroid);
~cpp
RegisterCollisionFunction cf4("Satellite", "SpaceShip",
&satelliteShip);
RegisterCollisionFunction cf5("Satellite", "Asteroid",
&satelliteAsteroid);