cocos2d-x学习笔记(一)塔防类游戏道具系统开发(上)定时炸弹和轰炸的实现

来源:互联网 发布:日照市软件研发工程师 编辑:程序博客网 时间:2024/04/29 14:18

ufolr原创,转载请注明:

转载自ufolr的博客 原文连接:http://blog.csdn.net/ufolr/article/details/7300545


基于cocos2d的一款塔防游戏,需要一个道具系统,需求如下

我们来一一解决。

一、无消耗道具。

二、轰炸。

三、时间停止。

四、定时炸弹。

下面就切入正题,开始累码。

期望达到目的:直接加载相应工程文件在主程序上做尽量小的改动实现我们的系统。

    所以,单独给道具开一个类,单独给道具一个layer。

于是,在游戏主scene中添加我们的道具的layer:

在我们的Gamescene或者HelloWorld的CCScene* HelloWorld::scene()中加入:

Daoju *daoju = Daoju::node();scene->addChild(daoju);

然后在Daoju.h中声明我们的道具类:

#ifndef __DAOJU_H__#define __DAOJU_H__#include "cocos2d.h"using namespace cocos2d;//long millisecondNow() ;class Daoju :public cocos2d::CCLayer{public:virtual bool init();//点击按钮触发事件void ChufaZhadan(CCObject* pSender);//触发炸弹事件void ChufaBombs(CCObject* pSender);//触发轰炸事件//重写触摸相关虚函数virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);//炸弹安放点坐标cocos2d::CCPoint touchPoint;//播放炸弹及轰炸效果的动画的函数bool ZhadanAnimate(float zx, float zy);bool BombsAnimate(float bx, float by);//回调函数,这里用于在动画播放完后clean屏幕void animBombsOverCallBack();void animZhadanOverCallBack();LAYER_NODE_FUNC(Daoju);};#endif//__DAOJU__
接着就开始分别解决我们的一切需要,当然不包括生理需要偷笑

首先是触发炸弹和轰炸的触发,道具系统要求使用某道具——达到某效果。

按钮无疑是最直观的表现方式:按下某按钮——执行某功能。

所以我们先定义两个按钮——定时炸弹、轰炸:

首先是文件头:

#include "Daoju.h"#include "cocos2d.h"
然后别忘了使用命名空间:

USING_NS_CC;//using namespace cocos2d的宏定义,当然你也可以使用using namespace cocos2dusing namespace std;
紧接着我们在Daoju类的构造函数中初始化所需按钮:

bool Daoju::init(){//设定一张图片-定时炸弹CCMenuItemImage *pZhadanItem = CCMenuItemImage::itemFromNormalImage("ClockNormal.png","ClockSelected.png",this,menu_selector(Daoju::ChufaZhadan) );//按下按钮触发的函数pZhadanItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 100, 50) );//按钮锚点坐标也就是按钮的位置//把图片设置为menu对象CCMenu* pMenuZhadan = CCMenu::menuWithItems(pZhadanItem, NULL);pMenuZhadan->setPosition( CCPointZero );//将按钮添加到我们道具的layer中this->addChild(pMenuZhadan, 1);//然后下面同理,是“轰炸”道具的按钮//设定一张图片-轰炸CCMenuItemImage *pBombsItem = CCMenuItemImage::itemFromNormalImage("BombsNormal.png","BombsSelected.png",this,menu_selector(Daoju::ChufaBombs) );pBombsItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 200, 50) );CCMenu* pMenuBombs = CCMenu::menuWithItems(pBombsItem, NULL);pMenuBombs->setPosition( CCPointZero );this->addChild(pMenuBombs, 1);return true;}
做好了按钮之后,我们就要给按钮添加内容了,也就是在按钮调用的函数中实现我们的功能。

从上面的代码中我们看到,两个按钮分别调用了ChufaZhadan和ChufaBombs这两个函数来实现功能,

下面来实现这两个功能,ChufaZhadan

void Daoju::ChufaZhadan(CCObject* pSender){//开启炸弹模式zmode = true;//定义一个外部变量(需要在Daoju类的init方法前定义:bool zmod;),表示当前状态,当zmode为true时即在炸弹模式时点击屏幕将安放炸弹,否者不执行动作,安放炸弹的函数紧接着在后面给出}
然后我们需要一个实现,点击定时炸弹按钮,再点击屏幕,安放炸弹的功能。

利用上面的zmod值,我们可以判断是否点击了“定时炸弹按钮”,从而决定要不要执行安放动作:

安放动作解析:点击屏幕——获取点击点位置——在该位置放置炸弹。

//获取炸弹安放点坐标,绘制矩形(放置炸弹)void Daoju::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent){if (zmode == true){CCSetIterator it = pTouches->begin();CCTouch* touch = (CCTouch*)(*it);touchPoint=touch->locationInView(touch->view());touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);//转换坐标系float zx=touchPoint.x;//上面函数所获取的x坐标实际是touchPoint的x成员的值,这里将其赋给zx只是未来好看float zy=touchPoint.y;CCRect ZhadanKuang(touchPoint.x, touchPoint.y, 20, 50);//在点安放点画出一个矩形框,用于武器系统判断伤害范围,输出伤害ZhadanAnimate(zx, zy);//在安放点播放董事炸弹的动画zmode = false;//关闭炸弹模式,保证点击一次道具按钮只能执行一次安放}}
到这里定时炸弹的点击——安放功能就做好了,接着就是轰炸效果了;

比起定时炸弹,轰炸就简单多了,不需要去寻找轰炸的坐标,轰炸点是固定的,但轰炸是多点的;

于是我们就可以把轰炸看作是多个定时炸弹来做,开始点击按钮,触发函数:

void Daoju::ChufaBombs(CCObject* pSender){/***************轰炸矩形框位置*************/CCRect BombsKuang(100, 100, 20, 50);//在规定的5个位置画出矩形CCRect BombsKuang(200, 200, 20, 50);CCRect BombsKuang(200, 100, 20, 50);CCRect BombsKuang(100, 200, 20, 50);CCRect BombsKuang(300, 100, 20, 50);/***************轰炸动画位置*************/BombsAnimate(200,200);//在规定的5个位置播放动画,使用相同的动画,可以在5个点播放BombsAnimate(100,100);BombsAnimate(200,100);BombsAnimate(100,200);BombsAnimate(300,100);}
这样点击轰炸按钮时的动作也完成了,我们只需要把动画播放封装成传入坐标点——绘制动画的函数,也就是上面代码中的ZhadanAnimate和BombsAnimate:

ZhadanAnimate:

动画是的函数大部分是在加载资源,可以用循环和plist来减少代码量,但是如果资源图片每桢大小不一,用循环来做就不现实了。

这里手动加载,复制、粘贴,小修改偷笑

bool Daoju::ZhadanAnimate(float zx, float zy){CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage("Zhadan.png");//加载资源(图片起点_左上角,图片大小)  //读取资源中的每一帧,暂存到framCCSpriteFrame *frame0 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*0, 16, 16));//从总的资源图中剪下每一帧的资源,前两个值(16*0, 16*0)表示剪切起始点的坐标(也就是每一帧的左上角在资源图中的坐标),后两个值表示当前帧图片的长和高(16,16).如果每一帧都一样大(长、高固定),那么起始点可以写成(长*(行-1),(高*列-1),我们只需要改动行、列即可得到相应的坐标,同时代码也比较直观,出现问题也比较好找.CCSpriteFrame *frame1 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*0, 16, 16));CCSpriteFrame *frame2 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*1, 16, 16));CCSpriteFrame *frame3 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*1, 16, 16));CCSpriteFrame *frame4 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*2, 16, 16));CCSpriteFrame *frame5 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*2, 16, 16));CCSpriteFrame *frame6 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*3, 16, 16));CCSpriteFrame *frame7 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*3, 16, 16));//设置初始图片(第一帧)CCSprite* spZhadananim = CCSprite::spriteWithSpriteFrame(frame0);spZhadananim->setPosition(ccp(zx, zy));addChild(spZhadananim, 0, 200);//加到相应图层,设置标签为200,我们在回调函数中会利用标签找到对应的精灵,然后删除动画精灵//合成动画-炸弹等待CCMutableArray<CCSpriteFrame*> *animZhadanWaitFrames = new CCMutableArray<CCSpriteFrame*>(4);//animZhadanWaitFrames->addObject(frame0);//animZhadanWaitFrames->addObject(frame1);//animZhadanWaitFrames->addObject(frame2);//animZhadanWaitFrames->addObject(frame3);animZhadanWaitFrames->addObject(frame4);animZhadanWaitFrames->addObject(frame5);animZhadanWaitFrames->addObject(frame6);animZhadanWaitFrames->addObject(frame7);//合成动画-炸弹爆炸CCMutableArray<CCSpriteFrame*> *animZhadanExciteFrames = new CCMutableArray<CCSpriteFrame*>(4);animZhadanExciteFrames->addObject(frame0);animZhadanExciteFrames->addObject(frame1);animZhadanExciteFrames->addObject(frame2);animZhadanExciteFrames->addObject(frame3);//将4个动画侦生成CCAnimation对象,每0.1秒(float)播放一帧//生成炸弹等待动画CCAnimation *animationWait  = CCAnimation::animationWithFrames(animZhadanWaitFrames, 0.1f);CCAnimate *animateWait = CCAnimate::actionWithAnimation(animationWait, false);//动画模版生成动画//生成炸弹激发动画CCAnimation *animationExcit  = CCAnimation::animationWithFrames(animZhadanExciteFrames, 0.2f);CCAnimate *animateExcit = CCAnimate::actionWithAnimation(animationExcit, false);//此处值为false动画播放完是在最后一帧,为true则返回第一帧//创建回调ActionCCCallFunc *animOverCallBack = CCCallFunc::actionWithTarget(this, callfunc_selector(Daoju::animBombsOverCallBack));//依次执行ActionspZhadananim->runAction(CCSequence::actions(CCRepeat::actionWithAction( animateWait, 12),//第一段动画重复12次//CCDelayTime::actionWithDuration(0.001f), //暂停瞬间一般情况下不用CCRepeat::actionWithAction( animateExcit, 1), //第二段动画重复1次animOverCallBack,//回调函数,用于清屏,清除动画,否则动画播放玩后屏幕会残留在屏幕上(对应上面的值可能是最后一帧也可能是第一帧)NULL));animZhadanWaitFrames->release();//释放资源animZhadanExciteFrames->release();return true;}
累了很长一串代码来加载动画,这是我找的替代资源图(另存为保存,改名为Zhadan.png即可):定时炸弹
接着是我们清理屏幕的会掉函数,上面代码已经说明,动画播放完会停留在屏幕,我们可以手动清除。

回调函数:

void Daoju::animBombsOverCallBack(){CCSprite* animOver = (CCSprite*)this->getChildByTag(200);//利用之前给精灵贴撒谎能够的标签来找到对应精灵animOver->stopAllActions();//停止加到精灵上的所有ActionanimOver->removeFromParentAndCleanup(true);//清理加载到动画的相应精灵

接下来的我们还需要一个轰炸的动画,来表现我们轰炸道具的效果。

动画的代码与上面炸弹动画的方法基本一样,都是加载资源,利用动画模版生成动画,然后输出动画,然后在回调函数中清清理动画。

bool Daoju::BombsAnimate(float bx, float by){CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage("Zhadan.png");CCSpriteFrame *frame0 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*0, 16, 16));CCSpriteFrame *frame1 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*0, 16, 16));CCSpriteFrame *frame2 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*1, 16, 16));CCSpriteFrame *frame3 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*1, 16, 16));CCSpriteFrame *frame4 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*2, 16, 16));CCSpriteFrame *frame5 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*2, 16, 16));CCSpriteFrame *frame6 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*0, 16*3, 16, 16));CCSpriteFrame *frame7 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(16*1, 16*3, 16, 16));//(第一帧)CCSprite* spBombs = CCSprite::spriteWithSpriteFrame(frame0);spBombs->setPosition(ccp(bx, by));addChild(spBombs,0, 100);//合成动画-炸弹等待CCMutableArray<CCSpriteFrame*> *animBombsFrames = new CCMutableArray<CCSpriteFrame*>(8);animBombsFrames->addObject(frame0);animBombsFrames->addObject(frame1);animBombsFrames->addObject(frame2);animBombsFrames->addObject(frame3);animBombsFrames->addObject(frame4);animBombsFrames->addObject(frame5);animBombsFrames->addObject(frame6);animBombsFrames->addObject(frame7);CCAnimation *animationBombs  = CCAnimation::animationWithFrames(animBombsFrames, 0.1f);CCAnimate *animateBombs = CCAnimate::actionWithAnimation(animationBombs, false);//定义回调动作CCCallFunc *animOverCallBack = CCCallFunc::actionWithTarget(this, callfunc_selector(Daoju::animZhadanOverCallBack));//依次执行动作spBombs->runAction(CCSequence::actions(animateBombs, animOverCallBack, NULL));animBombsFrames->release();return true;}void Daoju::animZhadanOverCallBack(){CCSprite* animOver = (CCSprite*)this->getChildByTag(100);animOver->stopAllActions();animOver->removeFromParentAndCleanup(true);}

到此我们的道具中的轰炸和定时炸弹的代码就累完了,当然,与主程序中汇总的时候还肯定还会有一些小的修改。

但大体的思路和方法就是这样。

在这个例子中,我们使用了cocos2d-x引擎提供的虚函数ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);来获取触目点坐标。

使用了基本的CCMenu和动画生成功能。其实动画的代码量在一些情况下是可以简略的、我们将在下个次来详细研究cocos2d-x的动画播放。敬请期待...




原创粉丝点击