ufolr原创,转载请注明:
转载自ufolr的博客 原文连接:http://blog.youkuaiyun.com/ufolr/article/details/7300545
我们来一一解决。
一、无消耗道具。
二、轰炸。
三、时间停止。
四、定时炸弹。
下面就切入正题,开始累码。
期望达到目的:直接加载相应工程文件在主程序上做尽量小的改动实现我们的系统。
所以,单独给道具开一个类,单独给道具一个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 cocos2d
using 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");
//加载资源(图片起点_左上角,图片大小)
//读取资源中的每一帧,暂存到fram
CCSpriteFrame *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则返回第一帧
//创建回调Action
CCCallFunc *animOverCallBack = CCCallFunc::actionWithTarget(this, callfunc_selector(Daoju::animBombsOverCallBack));
//依次执行Action
spZhadananim->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();//停止加到精灵上的所有Action
animOver->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的动画播放。敬请期待...