仿《雷霆戰機》飛行射擊手遊開發--飛機(含源碼庫地址)

轉載請註明:http://www.javashuo.com/article/p-nstrhvck-z.htmlgit

 

本遊戲正式開放源代碼啦~~sql

代碼庫(可在附件中下載Windows下的試玩程序):https://git.oschina.net/thorqq/RaidenFree數據庫

下面咱們繼續分析這款遊戲。api

飛機

這是一款打飛機遊戲,因此主角固然是飛機。遊戲裏,飛機包括如下幾種:ide

  • 玩家飛機:玩家控制的主飛機
  • 僚機:在玩家飛機左右的小飛機,相對於玩家飛機的位置是固定不變的。
  • 普通敵機:不會變形的敵機
  • 變形敵機:飛到指定位置後變形,而後開始射擊。被擊落時,屏幕會震動
  • BOSS:從屏幕上方飛下來,飛到指定位置後變形,而後開始左右移動,同時開始射擊。boss能夠有屢次變形,當血量低於必定值時會觸發變形,同時攻擊力加強。Boss被擊落後,飛機上會產生屢次爆炸,屏幕會伴隨着震動。
  • 必殺僚機:必殺技。當玩家點擊必殺按鈕時,會從屏幕下方出現一個龐大的飛機,發射超級激光

飛機的基本屬性

  • 名字
  • 類型
  • 骨骼動畫(飛行、左右側飛、變形、暴走、尾部火焰)
  • 生命值
  • 攻擊值:當飛機與飛機相撞時,對對方飛機產生的傷害值
  • 碰撞體(剛體)的中心座標和大小(只有當子彈的碰撞體與飛機的碰撞體發生重疊時,纔會產生傷害)
  • 縮放比例
  • 血槽的樣式和位置
  • 飛機的初始位置(對於玩家飛機來講,通常是從屏幕下方飛入;對於敵機來講,通常是從上半個屏幕的某個地方飛出來)
  • 子彈(彈夾BulletGroup+子彈Bullet)
  • 僚機
  • 飛機爆炸幀動畫和音效
  • 擴展屬性(可擴展,用map來實現)

咱們用結構體TAircraftData來表示:函數

struct TAircraftData
{
    int id;
    std::string name;//名字
    std::string type;//類型,值爲AircraftType<br>     //飛機動畫即支持幀動畫,又支持骨骼動畫
    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; //飛機參數
}

基本方法

  • 初始化、復位、銷燬
  • 生命的減小或增長、判斷是否活着
  • 開始射擊、中止射擊、是否正在射擊
  • 飛行
  • 爆炸

高級方法

  • 開始自動射擊、中止自動射擊、自動改變子彈級別
  • 子彈升一個等級
  • 子彈升到最高等級
  • 子彈降一個等級
  • 是不是最高級別子彈
  • 是不是最低級別子彈
  • 獲取子彈等級
  • 重置子彈等級
  • 子彈用完發出的通知
  • 更新裝備
  • 防護效果的增長、去除

 詳細代碼以下:性能

//飛機的基類
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;
        }
    }
 
};

飛機池

    當界面上的飛機較多,而且頻繁出現、被擊落的時候,系統會不停的建立、銷燬飛機對象,這樣會嚴重影響遊戲的幀率,因此,咱們增長了一個簡單的飛機池:當飛機被擊落時,飛機對象並無被銷燬掉,而只是中止射擊、中止全部動畫並隱藏起來。當須要建立新的飛機時,會從池中查找有沒有對應的已回收的飛機,若是找到,則對此對象從新進行初始化。代碼以下:ui

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.javashuo.com/article/p-nstrhvck-z.htmlthis

源碼庫地址:https://git.oschina.net/thorqq/RaidenFree

相關文章
相關標籤/搜索