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

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

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

下面我们继续分析这款游戏。

飞机
这是一款打飞机游戏,所以主角当然是飞机。游戏里,飞机包括以下几种:

玩家飞机:玩家控制的主飞机
僚机:在玩家飞机左右的小飞机,相对于玩家飞机的位置是固定不变的。
普通敌机:不会变形的敌机
变形敌机:飞到指定位置后变形,然后开始射击。被击落时,屏幕会震动
BOSS:从屏幕上方飞下来,飞到指定位置后变形,然后开始左右移动,同时开始射击。boss可以有多次变形,当血量低于一定值时会触发变形,同时攻击力增强。Boss被击落后,飞机上会产生多次爆炸,屏幕会伴随着震动。
必杀僚机:必杀技。当玩家点击必杀按钮时,会从屏幕下方出现一个庞大的飞机,发射超级激光
飞机的基本属性
名字
类型
骨骼动画(飞行、左右侧飞、变形、暴走、尾部火焰)
生命值
攻击值:当飞机与飞机相撞时,对对方飞机产生的伤害值
碰撞体(刚体)的中心坐标和大小(只有当子弹的碰撞体与飞机的碰撞体发生重叠时,才会产生伤害)
缩放比例
血槽的样式和位置
飞机的初始位置(对于玩家飞机来说,一般是从屏幕下方飞入;对于敌机来说,一般是从上半个屏幕的某个地方飞出来)
子弹(弹夹BulletGroup+子弹Bullet)
僚机
飞机爆炸帧动画和音效
扩展属性(可扩展,用map来实现)
我们用结构体TAircraftData来表示:

struct TAircraftData
{
int id;
std::string name;//名字
std::string type;//类型,值为AircraftType
     //飞机动画即支持帧动画,又支持骨骼动画
std::vectorstd::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
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;
}
}

};
飞机池
当界面上的飞机较多,并且频繁出现、被击落的时候,系统会不停的创建、销毁飞机对象,这样会严重影响游戏的帧率,所以,我们增加了一个简单的飞机池:当飞机被击落时,飞机对象并没有被销毁掉,而只是停止射击、停止所有动画并隐藏起来。当需要创建新的飞机时,会从池中查找有没有对应的已回收的飞机,如果找到,则对此对象重新进行初始化。代码如下:

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值