在我的游戏中,成为叛徒的Soldier
将自动从Turret
,Tank
和许多持有人中退出。 (MCVE)
一个Soldier
可以同时位于1个Turret
和1个Tank
中。
一个Soldier
最多可以驻留1个Turret
和1个Tank
。
这是Soldier
,Turret
和Tank
类(在实际情况下,它们位于3个文件中):-
#include <iostream>
#include <string>
#include <vector>
struct Soldier{
private: int team=0;
public: void setTeam(int teamP){
team=teamP;
//should insert callback
}
};
struct Turret{
Soldier* gunner=nullptr;
//currently it is so easy to access Turret's gunner
};
struct Tank {
std::vector<Soldier*> passenger;
//currently it is so easy to access Tank's passenger by index
};
std::vector<Soldier*> global_soldier;
std::vector<Turret*> global_turret;
std::vector<Tank*> global_tank;
这是
main()
。当前,只要程序员想设置任何
Soldier
实例的团队,他就必须手动进行弹出:-int main(){
Soldier soldier1; global_soldier.push_back(&soldier1);
Turret turret1; global_turret.push_back(&turret1);
turret1.gunner=&soldier1;
//v game loop
soldier1.setTeam(2);
//v manual ejection (should be callback?)
for(auto& ele: global_turret){
if(ele->gunner==&soldier1){
ele->gunner=nullptr;
}
}
for(auto& ele: global_tank){
for(auto& elePass: ele->passenger){
if(elePass==&soldier1){
elePass=nullptr;
}
}
}
//^ manual ejection
std::cout<<"should print 1="<<(turret1.gunner==nullptr)<<std::endl;
}
每次调用
Soldier::setTeam(int)
(维护问题)和性能问题后,这会导致大量样板代码。如何解决?
我不想失去的当前优势:-
-很容易进入炮塔的炮手,并且按索引是坦克的乘客之一。
我的解决方法(MCVE)
在
Soldier
中,我创建了一个回调中心(callback_changeTeams
)。在
Turret
和Tank
中,我创建对Soldier
的回调定义(Turret::ChangeTeam
和Tank::ChangeTeam
)。这是工作代码。
Soldier
:-class Soldier;
struct Callback{
public: virtual void changeTeam_virtual(Soldier* soldier)=0;
};
std::vector<Callback*> callback_changeTeams;
struct Soldier{
private: int team=0;
public: void setTeam(int teamP){
if(team==teamP){
}else{
team=teamP;
for(auto callback :callback_changeTeams)
callback->changeTeam_virtual(this);
}
//should insert callback
}
};
Turret
:-struct Turret;
std::vector<Turret*> global_turret;
struct Turret{
Soldier* gunner=nullptr;
struct ChangeTeam : public Callback{
public: virtual void changeTeam_virtual(Soldier* soldier){
for(auto& ele: global_turret){
if(ele->gunner==soldier){
ele->gunner=nullptr;
}
}
}
};
};
Tank
(类似于炮塔):-struct Tank;
std::vector<Tank*> global_tank;
struct Tank {
std::vector<Soldier*> passenger;
struct ChangeTeam : public Callback{
public: virtual void changeTeam_virtual(Soldier* soldier){
for(auto& ele: global_tank){
for(auto& elePass: ele->passenger){
if(elePass==soldier){
elePass=nullptr;
}
}
}
}
};
};
主:-
std::vector<Soldier*> global_soldier;
int main(){
Turret::ChangeTeam turretCallback;
Tank::ChangeTeam tankCallback;
callback_changeTeams.push_back(&turretCallback);
callback_changeTeams.push_back(&tankCallback);
Soldier soldier1; global_soldier.push_back(&soldier1);
Turret turret1; global_turret.push_back(&turret1);
turret1.gunner=&soldier1;
//v game loop
soldier1.setTeam(2);
//v should be callback
std::cout<<"should print 1="<<(turret1.gunner==nullptr)<<std::endl;
}
缺点:
1.
Turret
和Tank
之间的重复代码。还不错,但是实际上,我有很多类似
Turret
的类型(存储指向Soldier
的指针)和类似Tank
的类型(存储Soldier
数组)。这将是很多代码重复。2.仍然表现不佳。
每当我更改
Turret
的团队设置时,我都必须迭代每个Tank
和Soldier
。可以通过缓存父
Turret
和Tank
解决此问题,因此不需要迭代。但是,在实际情况下,我有很多父类型,并且会很脏。 :-
struct Soldier{
//... some field / functions ...
Turret* parentTurret;
Tank* parentTank;
SomeParentClass1* parent1;
SomeParentClass2* parent2; // bra bra bra.. ... dirty messy
};
我的随机想法(没什么用):智能指针(
std::shared_ptr
); std::unordered_map
;更改设计模式;使回调批量提交;我正在使用实体组件系统。 最佳答案
正如您自己指出的那样,有一个通用术语“持有人”涵盖了坦克和炮塔。
在您的班级中建模。
然后,您可以在士兵内部维护对其中内容的引用,并让其适当地处理士兵的出入。
这样,您只需要搜索坦克中非常短的士兵列表,并且仅搜索士兵实际所在的一个坦克即可。
struct Soldier;
struct Holder
{
public:
virtual void AddSoldier(Soldier* Entering)=0;
virtual void ExitSoldier(Soldier* Exiting)=0;
}
struct Turret:
public holder
{
public:
virtual void AddSoldier(Soldier* Entering)
{
gunner=Entering;
AttachedTo->AddSoldier(Entering);
}
virtual void ExitSoldier(Soldier* Exiting)
/* this only covers the complete way of exiting,
add another method for moving only into the tank */
{ if(gunner=Exiting)
{
gunner=nullptr;
}
if(AttachedTo)
{
AttachedTo->ExitSoldier(Exiting);
}
}
Soldier* gunner=nullptr;
Tank* AttachedTo;
};
struct Tank
: public holder
{
virtual void AddSoldier(Soldier* Entering)
{
/* push Entering,
if not in already */
}
virtual void MoveSoldierToTurretIfFree(Soldier* NewGunner)
{/* you know .. */}
virtual void ExitSoldier(Soldier* Exiting)
{
AttachedTurret->ExitSoldier(Exiting);
/* find and remove Exiting,
tolerating if already left */
}
std::vector<Soldier*> passenger;
struct turret* AttachedTurret;
};
struct Soldier{
private: int team=0;
Holder* Within;
public: void setTeam(int teamP){
team=teamP;
//should insert callback
}
void IsTraitor (void)
{
Within->ExitSolder(this);
Within=nullptr;
}
};
我对
public
有点慷慨,可以确定并希望在那里进行一些微调。我将方法代码直接编写到类中,您必须将其移动到代码文件或至少单独的实现中才能使其可编译;否则,向前宣布的士兵职业可能不够。
关于c++ - 回调以清理指针(MCVE:从车辆自动弹出叛徒士兵),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58177517/