在我的游戏中,成为叛徒的Soldier将自动从TurretTank和许多持有人中退出。 (MCVE

一个Soldier可以同时位于1个Turret和1个Tank中。
一个Soldier最多可以驻留1个Turret和1个Tank

这是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实例的团队,他就必须手动进行弹出:-

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)。

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

2.仍然表现不佳。
每当我更改Turret的团队设置时,我都必须迭代每个TankSoldier
可以通过缓存父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;更改设计模式;使回调批量提交;我正在使用实体组件系统。

最佳答案

正如您自己指出的那样,有一个通用术语“持有人”涵盖了坦克和炮塔。
在您的班级中建模。
然后,您可以在士兵内部维护对其中内容的引用,并让其适当地处理士兵的出入。
这样,您只需要搜索坦克中非常短的士兵列表,并且仅搜索士兵实际所在的一个坦克即可。

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/

10-11 22:23