技术(7)——让函数根据一个以上的对象类型来决定如何虚化

假设要做一个太空中各种天体的碰撞,其中涉及宇宙飞船、太空战、小行星等天体。

定义如下:

class GameObject
{
public:
	virtual void collideResult()=0;
	virtual ~GameObject()=0;
};

GameObject::~GameObject() { }

class SpaceShip:public GameObject
{
public:
	void collideResult()
	{
		cout<<"SpaceShip::collideResult()"<<endl;
	}
};

class SpaceStation:public GameObject
{
public:
	void collideResult()
	{
		cout<<"SpaceStation::collideResult()"<<endl;
	}
};

class Asteroid:public GameObject
{
public:
	void collideResult()
	{
		cout<<"Asteroid::collideResult()"<<endl;
	}
};

collideResult是各种不同的天体碰撞后各自产生的后果。

采取的方法是:使用“非成员函数”的碰撞处理函数

void ProcessCollision(GameObject* object1,GameObject* object2)
{
	string type1=typeid(*object1).name();
	string type2=typeid(*object2).name();
	CollisionMap::HitFunctionPtr ptr=CollisionMap::theCollisionMap()->lookup(type1,type2);
	if(ptr!=NULL)
		(*ptr)(*object1,*object2);
}


 上函数中的CollisionMap就是存放游戏对象和相应的碰撞处理函数的map结构,仿真的是虚函数表。

class CollisionMap
{
public:
	typedef void (*HitFunctionPtr)(GameObject&,GameObject&);
	typedef map<pair<string,string>,HitFunctionPtr> HitMap;
	
	void addEntry(const string& type1,const string& type2,HitFunctionPtr collisionFunction,bool sysmetric=true);
	void removeEntry(const string& type1,const string& type2);
	HitFunctionPtr lookup(const string& type1,const string& type2);
	static CollisionMap* theCollisionMap();
private:
	CollisionMap() {}
	CollisionMap(const CollisionMap&);
	static HitMap collisionMap;

	pair<string,string> makeStringPair(const string& str1,const string& str2);
};

CollisionMap::HitMap CollisionMap::collisionMap;

CollisionMap* CollisionMap::theCollisionMap()
{
	static CollisionMap cm;
	return &cm;
}

pair<string,string> CollisionMap::makeStringPair(const string& str1,const string& str2)
{
	return make_pair(str1,str2);
}

void CollisionMap::addEntry(const string& type1,const string& type2,HitFunctionPtr collisionFunction,bool sysmetric)
{
	pair<string,string> hitObjects=makeStringPair(type1,type2);
	collisionMap.insert(pair<pair<string,string>,HitFunctionPtr>(hitObjects,collisionFunction));
	if(sysmetric)
	{
		pair<string,string> hitObjects=makeStringPair(type2,type1);
		collisionMap.insert(pair<pair<string,string>,HitFunctionPtr>(hitObjects,collisionFunction));
	}
}

void CollisionMap::removeEntry(const string& type1,const string& type2)
{
	pair<string,string> hitObjects=makeStringPair(type1,type2);
	HitMap::iterator iter=collisionMap.find(hitObjects);
	if(iter!=collisionMap.end())
		collisionMap.erase(iter);
}

CollisionMap::HitFunctionPtr CollisionMap::lookup(const string& type1,const string& type2)
{
	pair<string,string> hitObjects=makeStringPair(type1,type2);
	HitMap::iterator iter=collisionMap.find(hitObjects);
	if(iter!=collisionMap.end())
		return (*iter).second;
	else
		return NULL;
}

因为一个系统中,只有一个这样的对象函数表,采用的是单实例的设计模式。

为了防止在这个函数表使用之前一定得到初始化,采用如下的措施:

class RegisterCollisionFunction
{
public:
	RegisterCollisionFunction(const string& type1,const string& type2,CollisionMap::HitFunctionPtr collisionFunction,bool sysmetric=true)
	{
		CollisionMap::theCollisionMap()->addEntry(type1,type2,collisionFunction,sysmetric);
	}
};

void shipAsteroid(GameObject& spaceShip,GameObject& asteroid)
{
	spaceShip.collideResult();
	asteroid.collideResult();
	cout<<"SpaceShip collide with Asteroid"<<endl;
}

void shipStation(GameObject& spaceShip,GameObject& station)
{
	spaceShip.collideResult();
	station.collideResult();
	cout<<"Spaceship collide with SpaceStation"<<endl;
}

void asteroidStation(GameObject& asteroid,GameObject& station)
{
	asteroid.collideResult();
	station.collideResult();
	cout<<"Asteroid collide with SpaceStation"<<endl;
}

void shipShip(GameObject& spaceShip1,GameObject& spaceShip2)
{
	spaceShip1.collideResult();
	spaceShip2.collideResult();
	cout<<"SpaceShip collide with Space Ship"<<endl;
}

void asteroidAsteroid(GameObject& asteroid1,GameObject& asteroid2)
{
	asteroid1.collideResult();
	asteroid2.collideResult();
	cout<<"Asteroid collide with Asteroid"<<endl;
}

void stationStation(GameObject& station1,GameObject& station2)
{
	station1.collideResult();
	station2.collideResult();
	cout<<"SpaceStation collide with Collide"<<endl;
}

RegisterCollisionFunction cf1("class SpaceShip","class Asteroid",&shipAsteroid);
RegisterCollisionFunction cf2("class SpaceShip","class SpaceStation",&shipStation);
RegisterCollisionFunction cf4("class SpaceShip","class SpaceShip",&shipShip);
RegisterCollisionFunction cf3("class Asteroid","class SpaceStation",&asteroidStation);
RegisterCollisionFunction cf5("class Asteroid","class Asteroid",&asteroidAsteroid);
RegisterCollisionFunction cf6("class SpaceStation","class SpaceStation",&stationStation);

因为这些碰撞函数都是全局变量,一定会在进入main函数之前初始化。

测试程序如下:

int _tmain(int argc, _TCHAR* argv[])
{
	SpaceShip object1;
	SpaceStation object2;
	ProcessCollision(&object1,&object2);
	 
	return 0;
}

在处理函数中,首先调用第一个对象的collisionResult,然后调用第二个对象的collisionResult,然后提示哪两个对象发生了碰撞。

至此,采用这样的技术实现了让ProcessCollision函数根据两个对象的动态类型实现虚化。

根据多个参数实现虚化的技术类似。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值