仿《雷霆战机》飞行射击手游开发–飞机(含源码库地址)

转发请申明:http://www.cnblogs.com/thorqq/p/6323156.html

你们对力量一无所知

 

引言

忆起上文,大家谈完了World和Level级别的逻辑操纵控制,就像分离组合的AController一样,UE在World的层系上也接纳了贰个分手的AGameMode来抽离了娱乐关卡逻辑,从而扶助了逻辑的三结合。本篇大家后续上涨八个层次,考虑在World之上,游戏还索要怎样逻辑控制?
临时不考虑别的效率类别(如社交系统,总结等种种),单从游戏性来谈谈,现在闭上眼睛,想象大家已经藉着UE的伟力搭建了好了二个个LevelWorld,嗯,就如《北边世界》一样,场景已经搭建好了,世界规则有趣的事也编写制定完善,今后内需干些什么?当然是始于派玩家进入玩啊!
世家都以老玩家了,想想我们以前玩的游乐项目:

  • 玩家数据是单人依然多少人
  • 网络环境是只本地依旧联网
  • 窗口彰显格局是单屏还是分屏
  • 输入格局是公家设施可能分别控制(比如各有手柄)
  • 唯恐还有其他差异

假若你是个开发娱乐引擎的,会怎么支持那个不一样的格局?以作者见识过的多数玩耍引擎,化解这些标题标思绪正是不消除,要嘛是限制功能,要嘛正是美名其曰让开发者自身灵活决定。不过想了须臾间,那也无法怪他们,终归很少有内燃机能像UE那样历史悠久同时又能取得足够多的嬉戏演习,才会有功力在GamePlay框架上镌刻。超越2/4斯特林发动机照旧更尊崇于达成各样绚丽的成效,至于怎么在上面进行游戏逻辑,那正是开发者本身的事了。三个引擎的功效是或不是强大,是基础比拼目标;而GamePlay框架作为最高层直面用户的连通接口,是三个引擎的颜面。所以有趣味游戏引擎商量的爱人们,区分1个引擎是或不是“优良”,第一个指标是看它是或不是设计了八个优雅的2二日游逻辑编写框架,一般唯有功底功效已经做得几近了的引擎开发者才会有生机去付出GamePlay框架,游戏引擎不止渲染!
言归正传,依照软件工程的见识,没有啥样难题是无法因而加二个直接层消除的,不行就加两层!所以既然大家在处理玩家格局的标题,理所当然的是加个直接层,将玩家那一个定义抽象出来。
那正是说怎样是玩家呢?狭义的讲,玩家正是实事求是的您,和您身旁的同伴。广义来说,依照图灵测试理论,如若您不能辨识另一方是AI依旧人,那她其实就跟玩家毫无分化,所以并不妨碍大家将互连网另一端的一条狗当作玩家。那么在嬉戏引擎看来,玩家正是输入的发起者。游戏说白了,也只是承受输入产生输出的三个主次。所以有稍许输入,那一个输入归多少组,就有微微个玩家。那里的输入不止包罗地面键盘手柄等输入设备的按键,也席卷网线里传过来的信号,是广义的该游戏能经受到的外场输入。注意输出并不是玩家的需求属性,四个玩家并不一定要求娱乐的出口,想象你闭上眼睛玩马里奥大概有个网络连接不断发送来支配信号然则从未接受反馈,固然看起来意义非常的小,但也真的不可能说那就不是游戏。
在UE的眼里,玩家也是如此广义的多个概念。本地的玩家是玩家,网络同步时就算看不见对方,可是对方的网络连接也能够当作是个玩家。当然的,本地玩家和网络玩家究竟依旧距离十分的大,所以UE里也对两岸进行了区别,才好更好的管制和平运动用到不一致场景中去,比如互连网玩家就跟当地设备的输入没多大关系了嘛。

本游戏正式开放源代码啦~~

UPlayer

让大家假装自身是UE,初阶编写制定Player类吧。为了采纳上UObject的那多少个现有天性,所以必然是得从UObject继承了。那是还是不是是AActor呢?Actor是必须在World中才能存在的,而Player却是比World更高级中学一年级流的指标。玩游戏的长河中,LevelWorld在不停的切换,然而玩家的格局却是脱离不变的。其余,Player也不须求被摆放在Level中,也不须求各类Component组装,所以从AActor继承并不适于。这依旧保持简单吗:
图片 1
如图可知,Player和二个PlayerController关联起来,由此UE引擎就足以把输入和PlayerController关联起来,那也符合了前文说过的PlayerController接受玩家输入的描述。因为不管是当地玩家依然长途玩家,都是内需控制1个玩家Pawn的,所以本来也就必要为各种玩家分配贰个PlayerController,所以把PlayerController放在UPlayer基类里是合理合法的。

代码库(可在附属类小部件中下载Windows下的试玩程序):https://git.oschina.net/thorqq/RaidenFree

ULocalPlayer

然后是当地玩家,从Player中派生下来LocalPlayer类。对本地环境中,三个地面玩家关联着输入,也一般须求关联着输出(无输出的玩家究竟依然11分少见)。玩家对象的上层正是引擎了,所以会在GameInstance里保存有LocalPlayer列表。
图片 2
UE4里的ULocalPlayer也如图所见,ULocalPlayer比UPlayer多了Viewport相关的配备(Viewport相关的始末在渲染章节讲述),也好不简单用SpawnPlayerActor完毕了创造出PlayerController的功效。GameInstance里有LocalPlayers的音讯之后,就足以便宜的遍历访问,来贯彻跟当地玩家相关操作。
至于游戏的详细加载流程最近不多讲述(按常规在对应引擎流程章节讲述),今后简短询问一下LocalPlayer是怎么在玩耍的引擎的各类环节发挥功效的。UE在开始化GameInstance的时候,会先暗中同意成立出3个GameViewportClient,然后在内部再倒车到GameInstance的CreateLocalPlayer:

ULocalPlayer* UGameInstance::CreateLocalPlayer(int32 ControllerId, FString& OutError, bool bSpawnActor)
{
    ULocalPlayer* NewPlayer = NULL;
    int32 InsertIndex = INDEX_NONE;
    const int32 MaxSplitscreenPlayers = (GetGameViewportClient() != NULL) ? GetGameViewportClient()->MaxSplitscreenPlayers : 1;
    //已略去错误验证代码,MaxSplitscreenPlayers默认为4
    NewPlayer = NewObject<ULocalPlayer>(GetEngine(), GetEngine()->LocalPlayerClass);
    InsertIndex = AddLocalPlayer(NewPlayer, ControllerId);
    if (bSpawnActor && InsertIndex != INDEX_NONE && GetWorld() != NULL)
    {
        if (GetWorld()->GetNetMode() != NM_Client)
        {
            // server; spawn a new PlayerController immediately
            if (!NewPlayer->SpawnPlayActor("", OutError, GetWorld()))
            {
                RemoveLocalPlayer(NewPlayer);
                NewPlayer = NULL;
            }
        }
        else
        {
            // client; ask the server to let the new player join
            NewPlayer->SendSplitJoin();
        }
    }
    return NewPlayer;
}

可以看看,假诺是在Server格局,会直接创建出ULocalPlayer,然后创造出相应的PlayerController。而如若是Client(比如Play的时候选取NumberPlayer=2,则有叁个为Client),则会头阵送JoinSplit音信到服务器,在载入服务器上的Map之后,再为LocalPlayer成立出PlayerController。
而在各种PlayerController创造的历程中,在其里面会调用InitPlayerState:

void AController::InitPlayerState()
{
    if ( GetNetMode() != NM_Client )
    {
        UWorld* const World = GetWorld();
        const AGameModeBase* GameMode = World ? World->GetAuthGameMode() : NULL;
        //已省略其他验证和无关部分
        if (GameMode != NULL)
        {
            FActorSpawnParameters SpawnInfo;
            SpawnInfo.Owner = this;
            SpawnInfo.Instigator = Instigator;
            SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
            SpawnInfo.ObjectFlags |= RF_Transient;  // We never want player states to save into a map
            PlayerState = World->SpawnActor<APlayerState>(GameMode->PlayerStateClass, SpawnInfo );

            // force a default player name if necessary
            if (PlayerState && PlayerState->PlayerName.IsEmpty())
            {
                // don't call SetPlayerName() as that will broadcast entry messages but the GameMode hasn't had a chance
                // to potentially apply a player/bot name yet
                PlayerState->PlayerName = GameMode->DefaultPlayerName.ToString();
            }
        }
    }
}

这么LocalPlayer最后就和PlayerState对应了起来。而网络协同时别的玩家的PlayerState是经过Replicated过来的。
咱俩谈了那么久的玩家正是输入,映今后在每一种PlayerController接受Player的时候:

void APlayerController::SetPlayer( UPlayer* InPlayer )
{
    //[...]
    // Set the viewport.
    Player = InPlayer;
    InPlayer->PlayerController = this;
    // initializations only for local players
    ULocalPlayer *LP = Cast<ULocalPlayer>(InPlayer);
    if (LP != NULL)
    {
        // Clients need this marked as local (server already knew at construction time)
        SetAsLocalPlayerController();
        LP->InitOnlineSession();
        InitInputSystem();
    }
    else
    {
        NetConnection = Cast<UNetConnection>(InPlayer);
        if (NetConnection)
        {
            NetConnection->OwningActor = this;
        }
    }
    UpdateStateInputComponents();
    // notify script that we've been assigned a valid player
    ReceivedPlayer();
}

看得出,对于ULocalPlayer,APlayerController内部会开始InitInputSystem(),接着会创制相应的UPlayerInput,BuildInputStack等开头化出和Input相关的零部件对象。未来先精晓到LocalPlayer才是PlayerController发生的源头,也由此才有了Input就够了,特定的Input事件流程分析在此起彼伏章节再细述。

沉凝:为什么不在LocalPlayer里编写逻辑?
作为游戏开发者,相信大家都有那样个体会,往往在打闹逻辑代码中总会有二个本人的Player类,里面放着这么些玩家的有关数据和逻辑业务。然而在UE里为什么就丢掉了那般个布局?也没见UE在文书档案里有描述推荐你怎么开创和谐的Player。
这一个或然有七个原因,一是UE从FPS-Specify游戏起家,不像以后的各样手游有那三个重的玩家系统,在UE的眼中,Level和World才是最应该关切的对象,因而UE的观点就在于怎么在Level中处理好Player的逻辑,而非在World之外的额外操作。二是因为在1个World中,上文提到其实已经有了Pawn-PlayerController和PlayerState的重组了,表示、逻辑和数据都兼备了,也就没须求再在Level掺和进Player什么事了。当然你也得以明白为PlayerController正是Player在Level中的话事人。
全部留一线,日后好相见。即使如此,UE依然给了大家自定义ULocalPlayer子类的时机:

//class UEngine:
/** The class to use for local players. */
    UPROPERTY()
    TSubclassOf<class ULocalPlayer>  LocalPlayerClass;

    /** @todo document */
    UPROPERTY(globalconfig, noclear, EditAnywhere, Category=DefaultClasses, meta=(MetaClass="LocalPlayer", DisplayName="Local Player Class"))
    FStringClassReference LocalPlayerClassName;

您可以在配置中写上LocalPlayer的子类名称,让UE为你生成你的子类。然后再在里头写上有些一定玩家的多少和逻辑也未尝不可,不过那部分额外扩张的效应就得用C++来达成了。

上边大家后续分析那款游戏。

UNetConnection

老大有意思的是,在UE里,一个网络连接也是个Player:
图片 3
涵盖Socket的IpConnection也是玩家,甚至对于一些阳台的特定达成如OculusNet的连日也能够当作玩家,因为对此玩家,只要能提供输入信号,就能够作为贰个玩家。
追根溯源,UNetConnection的列表保存在UNetDriver,再到FWorldContext,最终也照样是UGameInstance,所以和LocalPlayer的列表一样,是在World上层的靶子。
本篇先前瞻一下结构,对于互联网部分不再细述。

飞机

那是一款手淫游戏,所以主演当然是飞机。游戏里,飞机包涵以下两种:

  • 玩家飞机:玩家操纵的主飞机
  • 僚机:在玩家飞机左右的小飞机,相对于玩家飞机的职位是永恒不变的。
  • 一般说来敌机:不会变形的敌机
  • 变形敌机:飞到内定地点后变形,然后初叶射击。被击落时,显示器会感动
  • BOSS:从显示屏上方飞下来,飞到钦定地点后变形,然后起始左右活动,同时开班射击。boss能够有反复变形,当血量低于一定值时会触发变形,同时攻击力增强。Boss被击落后,飞机上会发生数次放炮,荧屏会陪伴着激动。
  • 必杀僚机:必杀技。当玩家点击必杀按钮时,会从显示器下方出现3个巨大的飞行器,发射一级激光

总结

本篇大家抽象出了Player的定义,并基于使用情形派生出了LocalPlayer和NetConnection那五个子类,从此Player就不再是2个空洞的概念,而是UE里的逻辑实体。UE能够依照变化的Player对象的数码和类型的不等,在此上贯彻出分化的玩家操纵情势,LocalPlayer作为源头Spawn出PlayerController继而PlayerState正是实证之一。而在互联网协同时,把1个互连网连接看作是多少个玩家这几个概念,把在World之上的输入实体用Player统一了起来,从而能够兑现出灵活的地点远程分歧玩家形式策略。
固然,UPlayer却像是深藏在UE里的暗中功臣,UE也并不引进直接在Player里编制程序,而是选择Player作为源头,来发生构建一多如牛毛有关的机制。但对于我们娱乐开发者而言,知道并询问UE里的Player的定义,是把现实生活同游戏世界串联起来的很首要的节骨眼。大家在2个个World里发展仰望,还是能够明了的看见2个个LocalPlayer或NetConnection就好像在目送着那片环球,是她们为World注入了血气。
一度到头了?并不曾,大家一连开拓进取逆风飞翔,终将得见游戏里的神:GameInstance。

飞机的主干性格

  • 名字
  • 类型
  • 骨骼动画(飞行、左左侧飞、变形、暴走、尾部火焰)
  • 生命值
  • 攻击值:当飞机与飞机相撞时,对对方飞机发生的加害值
  • 碰撞体(刚体)的大旨坐标和尺寸(唯有当子弹的碰撞体与飞机的碰撞体产生重叠时,才会爆发有剧毒)
  • 缩放比例
  • 血槽的体裁和职位
  • 飞机的启幕地点(对于玩家飞机来说,一般是从荧屏下方飞入;对于敌机来说,一般是从上半个荧屏的某些地点飞出去)
  • 子弹(弹夹BulletGroup+子弹Bullet)
  • 僚机
  • 飞机爆炸帧动画和音效
  • 壮大属性(可扩张,用map来完成)

作者们用结构体TAircraftData来表示:

struct TAircraftData
{
    int id;
    std::string name;//名字
    std::string type;//类型,值为AircraftType
     //飞机动画即支持帧动画,又支持骨骼动画
    std::vector<std::string> styleArray;  //飞机动画
    float aniDura; //动画帧时长
    std::string armatureName; //骨骼动画名称

    int hp;           //当前生命值
    int maxHp;        //最大生命值
    float defence;    //防御
    int attack;       //攻击

    float bodyCenterX; //刚体中心坐标
    float bodyCenterY;
    float bodySizeW;   //刚体尺寸
    float bodySizeH;
    float scale;       //缩放比例

    std::string hpBgStyle; //血槽背景样式
    std::string hpStyle;   //血槽样式
    float hpPosX;          //血槽的位置
    float hpPosY;          //血槽的位置

    std::vector<std::vector<int>*> bulletIdArray;  //多种子弹

    std::vector<std::string> fireFameNameArray; //尾部火焰动画,图片列表
    float fireAniDura; //动画帧时长
    int   fireOnTop;
    float fireOffsetX;//火焰中心点相对于飞机底部中心点的偏移。如果等于0,则只有一个火焰;否则是两个火焰
    float fireOffsetY;

    float startPosX;  //飞机的起始位置
    float startPosY;

    std::vector<int> wingmanArray; //僚机

    std::vector<std::string> blastStyleArray; //飞机爆炸的动画
    float blastAniDura;
    int blastMusicId; //飞机爆炸的音效id

    std::map<std::string, std::string> paramMap; //飞机参数
}

引用

UE4.14


基本格局

  • 初始化、复位、销毁
  • 生命的回落或追加、判断是不是活着
  • 开端射击、结束射击、是或不是正在射击
  • 飞行
  • 爆炸

搜狐专栏:InsideUE4

高等方法

  • 早先活动射击、截至活动射击、自动改变子弹级别
  • 子弹升1个等级
  • 子弹升到最高阶段
  • 子弹降二个等级
  • 是不是是最高级别子弹
  • 是或不是是最低级别子弹
  • 得到子弹等级
  • 重置子弹等级
  • 子弹用完发生的通知
  • 创新配备
  • 防卫机能的扩大、去除

 详细代码如下:

//飞机的基类
class Aircraft : public GameObject, public IBulletUseUpListener
{
public:
    Aircraft();
    virtual ~Aircraft();

    virtual bool init(Node* parent, const TAircraftData* pData, const TAircraftLevelData* pLevelData = nullptr);
    virtual void reset();
    virtual void destory();

    virtual void reduceHp(int hp);
    virtual void recoverHp(int hp);
    virtual bool isAlive();

    virtual void startShoot();
    virtual void stopShoot();
    virtual bool isShooting();

    virtual void autoShoot();
    virtual void stopAutoShoot();
    virtual void autoChangeBulletGrade();

    //自动飞行
    virtual void fly(){};

    //爆炸
    virtual void blast();

    //更新装备
    bool updateEquip();

    //子弹升级
    virtual bool upgradeBullet();
    virtual bool upgradeMaxBullet();
    //子弹降级
    virtual bool downgradeBullet();
    //是否暴走
    virtual bool isMaxLevelBullet();
    //是否最低级子弹
    virtual bool isMinLevelBullet();
    //获取子弹等级
    virtual int getBulletLevel();
    //重置子弹级别
    virtual bool resetBulletLevel();

    //子弹用完通知
    virtual void bulletUseUp() override;

    //量子护盾
    void addShield();
    void removeShield();
    //防御效果结束
    virtual void defenceDone(float dt);

    //碰撞检测
    virtual bool isCollsion(const Rect& rect, Rect* pCollsionRect = nullptr);

    //获取攻击、防御、导弹、僚机、综合性能
    inline int getAttrAttack(){ return m_iAttrAttack; }
    inline int getAttrArmor() { return m_iAttrArmor; }
    inline int getAttrMissile(){ return m_iAttrMissile; }
    inline int getAttrWingman() { return m_iAttrWingman; }
    inline int getAttrTotal() { return m_iAttrTotal; }

    void calculateAttr();

    inline int getId()
    {
        return m_data.id;
    }

    inline int getLevelId()
    {
        if (m_data.pAircraftLevelData)
        {
            return m_data.pAircraftLevelData->id;
        }
        else
        {
            return -1;
        }
    }

    inline int getHp()
    {
        return m_data.hp;
    }

    inline void setHp(int hp)
    {
        m_data.hp = hp;
    }

    inline int getMaxHp()
    {
        return m_data.maxHp;
    }

    inline void setMaxHp(int max)
    {
        m_data.maxHp = max;
    }

    inline int getAttack()
    {
        //两机相撞时,对对方产生的伤害就是自己的血量
        return getHp();
    }

    inline void setAttack(int a)
    {
        m_data.attack = a;
    }

    void setNoDie(bool b);

    inline bool isNoDie()
    {
        return m_bNoDie;
    }

    inline Vector<BulletGroup*>* getBulletGroupArray()
    {
        return &m_bulletGroupArray;
    }

    inline EAircraftType getAircraftType()
    {
        return m_eAircraftType;
    }

    inline const std::string& getAttr(const std::string& key)
    {
        static std::string empty = "";
        auto it = m_data.paramMap.find(key);
        if (it != m_data.paramMap.end())
        {
            return it->second;
        }
        else
        {
            return empty;
        }
    }

    inline int getAircraftLevelId()
    {
        if (m_data.pAircraftLevelData)
        {
            return m_data.pAircraftLevelData->id;
        }
        else
        {
            return -1;
        }
    }

    Vector<Aircraft*>* getOtherSidePlane() const;
    void setOtherSidePlane(Vector<Aircraft*>* const planes);

    //回收
    virtual void recycle();
    //重用
    virtual void reuse();
    //是否已回收(是否可用)
    bool isRecycled();

protected:
    virtual void setBulletGrade(unsigned grade){ m_iBulletGrade = grade; }
    virtual void setAttackAdjust(float adjust){ m_fAttackAdjust = adjust; }
    virtual void setMissileAdjust(float adjust){ m_fMissileAdjust = adjust; }
    virtual void setBulletSpeedAdjust(float adjust){ m_fBulletSpeedAdjust = adjust; }

    virtual bool initBody(Node* parent, const TAircraftData* pData);
    virtual bool initPosition(Node* parent, const TAircraftData* pData);
    virtual bool initFire(Node* parent, const TAircraftData* pData);
    virtual bool initHpBar(Node* parent, const TAircraftData* pData);
    virtual bool initBullet(Node* parent, const TAircraftData* pData);
    virtual bool initWingman(Node* parent, const TAircraftData* pData);

    //添加尾部的左右两个火焰动画
    bool addFire(float offsetX, float offsetY, bool isFlipped);

protected:
    EAircraftType m_eAircraftType;
    TAircraftData m_data;
    const TAircraftData* m_pDataCopy;

    //战机所有的装备
    const TEquipmentData* m_pEquipAircraft;
    const TEquipmentData* m_pEquipArmature;
    const TEquipmentData* m_pEquipMissile;
    const TEquipmentData* m_pEquipWingman;

    int m_iBulletGrade;
    float m_fAttackAdjust;
    float m_fMissileAdjust;
    float m_fBulletSpeedAdjust;

    float m_fVipRelifeAttrAdjust;

    float m_fDefence;           //防御系数
    float m_fDefenceDura;       //防御持续时间
    int m_iCurBulletGrade; //当前子弹等级
    bool m_bNoDie;              //无敌
    cocostudio::Armature* m_pDefenceBall;     //护盾球
    HpBar* m_pHpBar;            //血槽精灵
    Vector<BulletGroup*> m_bulletGroupArray;  //多种子弹
    Vector<Aircraft*>    m_wingmanArray;      //僚机精灵
    Vector<Aircraft*>*   m_otherSideArray;    //对方飞机。对于玩家来说就是敌机,对于敌机来说就是玩家

    int m_iAttrAttack;
    int m_iAttrArmor;
    int m_iAttrMissile;
    int m_iAttrWingman;
    int m_iAttrTotal;

    bool m_bRecycled;

    bool m_bAutoShoot;
    int m_orignBulletGrade;
};

  为了创设差异的飞机对象,大家扩充三个飞行器工厂。工厂的create函数中TAircraftData参数是从配置(sqlite数据库)中取获得的。

template<typename T>
class PlaneCreator
{
public:
    static T* create(Node* parent, const TAircraftData* data)
    {
        T *pRet = new(std::nothrow) T();
        if (pRet && pRet->init(parent, data))
        {
            pRet->autorelease();
            return pRet;
        }
        else
        {
            delete pRet;
            pRet = NULL;
            return NULL;
        }
    }

};

UE4深入学习QQ群: 456247757(非新手入门群,请先读书完官方文书档案和摄像教程)

民用原创,未经授权,谢绝转发!

飞机池

   
当界面上的飞行器较多,并且反复现身、被击落的时候,系统会不停的创导、销毁飞机对象,那样会严重影响游戏的帧率,所以,大家扩张了3个简单易行的飞机池:当飞机被击落时,飞机对象并从未被销毁掉,而只是结束射击、结束全部动画并逃匿起来。当供给创建新的飞行器时,会从池中追寻有没有对应的已回收的飞机,如若找到,则对此目标重新开始展览起始化。代码如下:

class AircraftPool
{
public:
    static AircraftPool* getInstance();

    //获取一架飞机
    template<typename T>
    T* get(Node* parent, const TAircraftData* pAircraftData, const TAircraftLevelData* pAircraftLevelData)
    {
        //AircraftPool 只在急速模式下使用。其他两种模式反而会增加内存
        if (GameData::getInstance()->getValueToInt(GAMEDATA::MODE) != ModeBase::ModeRapid)
        {
            return PlaneCreator<T>::create(parent, pAircraftData, pAircraftLevelData);
        }

        auto it = m_aircraftMap.find(pAircraftLevelData->id);
        std::vector<Aircraft*>* pArray = nullptr;
        if (it != m_aircraftMap.end())
        {
            pArray = it->second;
        }
        else
        {
            pArray = new std::vector<Aircraft*>;
            m_aircraftMap.insert(std::map<int, std::vector<Aircraft*>*>::value_type(pAircraftLevelData->id, pArray));
        }

        //查找可用的飞机
        for (Aircraft* p : *pArray)
        {
            if (p && p->isRecycled())
            {
                p->reuse();
                T* ret = dynamic_cast<T*>(p);
                if (ret)
                {
                    parent->addChild(ret);
                    return ret;
                }
                else
                {
                    DEBUG_LOG("fuck error type of aircraft");
                }
            }
        }

        //没找到,新建一个
        auto p = PlaneCreator<T>::create(parent, pAircraftData, pAircraftLevelData);
        p->retain();
        for (unsigned i = 0; i < pArray->size(); i++)
        {
            if ((*pArray)[i] == nullptr)
            {
                (*pArray)[i] = p;
                return p;
            }
        }

        pArray->push_back(p);
        return p;
    }

    //回收一架飞机
    void recycle(Aircraft* pAircraft);

    //清空pool
    void release();

protected:
    AircraftPool();

private:
    static AircraftPool* m_pInstance;

    std::map<int, std::vector<Aircraft*>*> m_aircraftMap;
};

AircraftPool* AircraftPool::m_pInstance = nullptr;

AircraftPool* AircraftPool::getInstance()
{
    if (!m_pInstance)
    {
        m_pInstance = new AircraftPool();
    }

    return m_pInstance;
}

AircraftPool::AircraftPool()
{
}

//回收一架飞机
void AircraftPool::recycle(Aircraft* pAircraft)
{
    //如果在池中,则回收;否则直接销毁
    auto it = m_aircraftMap.find(pAircraft->getAircraftLevelId());
    std::vector<Aircraft*>* pArray = nullptr;
    if (it != m_aircraftMap.end())
    {
        pArray = it->second;
        for (Aircraft* p : *pArray)
        {
            if (p == pAircraft)
            {
                p->recycle();
                return;
            }
        }
    }

    pAircraft->destory();
}

//清空pool
void AircraftPool::release()
{
    for (auto it : m_aircraftMap)
    {
        bool bInUse = false;
        std::vector<Aircraft*>* pArray = it.second;
        for (Aircraft* p : *pArray)
        {
            if (p && p->isRecycled())
            {
                p->destory();
                p->release();
            }
            else if (p)
            {
                bInUse = true;
                DEBUG_LOG("Aircraft[%d] can't release", p->getId());
                //CCASSERT(false, "Release error aircraft");
            }
        }

        if (!bInUse)
        {
            pArray->clear();
            delete pArray;
        }
    }

    m_aircraftMap.clear();
}

//////////////////////////////////////////////////////////
//下面是Aircraft对象中的回收、重用等方法
//回收
void Aircraft::recycle()
{
    if (m_bRecycled)
    {
        return;
    }

    setNoDie(false);
    //for (int i = 0; i < m_bulletGroupArray.size(); i++)
    //{
    //  m_bulletGroupArray.at(i)->setPlane(NULL);
    //}
    stopShoot();

    for (int i = 0; i < m_wingmanArray.size(); i++)
    {
        //m_wingmanArray.at(i)->recycle();
        AircraftPool::getInstance()->recycle(m_wingmanArray.at(i));
    }

    pause();

    m_bRecycled = true;
}

//重用
void Aircraft::reuse()
{
    if (!m_bRecycled)
    {
        return;
    }

    if (m_pHpBar)
    {
        m_pHpBar->setMaxValue(m_data.maxHp);
        m_pHpBar->setCurValue(m_data.maxHp);
    }
    m_data.hp = m_data.maxHp;

    //for (int i = 0; i < m_bulletGroupArray.size(); i++)
    //{
    //  m_bulletGroupArray.at(i)->setPlane(this);
    //}
    m_iCurBulletGrade = 0;

    for (int i = 0; i < m_wingmanArray.size(); i++)
    {
        m_wingmanArray.at(i)->reuse();
    }

    if (m_pArmature)
    {
        m_pArmature->setColor(Color3B::WHITE);
        m_pArmature->getAnimation()->play(GlobalData::getInstance()->getArmatureData(m_data.armatureName)->defaultAction);
    }
    else
    {
        this->setColor(Color3B::WHITE);
    }

    resume();

    m_bRecycled = false;
}

//是否已回收(是否可用)
bool Aircraft::isRecycled()
{
    return m_bRecycled;
}

  

转发请注脚:http://www.cnblogs.com/thorqq/p/6323156.html

源码库地址:https://git.oschina.net/thorqq/RaidenFree

发表评论

电子邮件地址不会被公开。 必填项已用*标注