gpt4 book ai didi

c++ - 清除指针的回调(MCVE : auto eject traitor Soldier from Vehicle)

转载 作者:行者123 更新时间:2023-11-28 04:09:10 24 4
gpt4 key购买 nike

在我的游戏中,成为叛徒的士兵将自动炮塔坦克和很多持有人。 (MCVE)

一个士兵可以同时驻留在1个炮塔和1个坦克中。
士兵最多可以驻留在 1 个炮塔和最多 1 个坦克中。

这是 SoldierTurretTank 类(在实际情况下,它们在 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 实例的团队时,他都必须手动执行 ejection :-

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)。
TurretTank 中,我为 Soldier 创建了一个回调定义(Turret::ChangeTeamTank::ChangeTeam).

这是工作代码。
士兵 :-

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
}
};

炮塔:-

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;
}
}
}
};
};

坦克(类似于炮塔的):-

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。 TurretTank 之间的重复代码。
还不错,但在实际情况中,我有很多类似 Turret 的东西(存储指向 Soldier 的指针)和类似 Tank 的东西(存储 Soldier 的数组)。这将是很多代码重复。

<强>2。仍然表现不佳。每当我只是更改 Soldier 的团队设置时,我都必须迭代每个 TurretTank
这可以通过缓存父级 TurretTank 来解决,因此不需要迭代。
但是,在实际情况中,我有很多父类型,它们会很脏,例如:-

struct Soldier{
//... some field / functions ...
Turret* parentTurret;
Tank* parentTank;
SomeParentClass1* parent1;
SomeParentClass2* parent2; // bra bra bra.. ... dirty messy
};

我的随机想法(用处不大):智能指针(std::shared_ptr); std::unordered_map ;改变设计模式;使回调作为批处理提交;我正在使用实体组件系统。

最佳答案

正如您自己所说,有一个通用术语“支架”涵盖了坦克和炮塔。
在您的类(class)中建模。然后你可以在 soldier 中维护对它所在的任何内容的引用,并让它适本地处理士兵的退出/进入。这样一来,您只需搜索坦克中非常短的士兵名单,并且只搜索士兵实际坐在的那个坦克。

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 有点慷慨,当然可以在那里进行一些微调。
我将方法代码直接写入类中,您必须将其移动到代码文件或至少单独的实现中才能使其可编译;否则前向声明的 Soldier 类可能不够用。

关于c++ - 清除指针的回调(MCVE : auto eject traitor Soldier from Vehicle),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58177517/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com