Cocos2d-x《雷电大战》(4)-策略模式实现不同子弹切换!!
林炳文Evankaka原创作品。转载请注明出处http://www.52php.cn/tag/http://blog.csdn.net/evankaka 本文从设计模式中的策略模式入手,主讲了飞机大战中英雄飞机切换不同的子弹。这里分为三种子弹。第一种:每次发一个子弹,垂直发射;第二种:每次发两个子弹,两个都是垂直发射:第三种;每次发三个子弹,两边的子弹有一定的角度,而中间的子弹垂直发射;设计模式是游戏开发经常用到的思想,建议有兴趣的同学可以好好研究下!好了,下面开始吧。 效果如下: Cocos2d-x版本:3.4 工程环境:VS30213 一、策略模式(Stragegy Pattern)1、简介Strategy模式也叫策略模式是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略)。Strategy模式主要用来平滑地处理算法的切换 。 2、意图定义一系列的算法,把它们一个个封装起来,并且它们可相互替换。使得算法可独立于使用它的客户而变化。 3、适用性
二.子弹类与子弹管理类的代码编写首先来看下本文的类UML图:这里的思路是把子弹发射当成是一个函数,基类子弹中定义成虚函数,然后实现类子弹中HeroBulletOne、HeroBulletTwo、HeroBulletThree分别实现不同的发射功能。然后在子弹管理类中HeroBulletLayer中有一个私有的成员变量BulletStyle *mBulletStyle.当需要切换不同的子弹时,就将new不同的HeroBulletOne或HeroBulletTwo或HeroBulletThree,赋给mBulletStyle。 下面我们来看看代码吧!!! 2.1 首先是子弹的基类:BulletStyle.h,这里注意到virtual void shootBullet(float dt){}为虚函数,表示这里要根据的子类不同,发射不同的子弹数目;/** *功能 创建子弹的基类 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #pragma once #ifndef __BulletStyle_H__ #define __BulletStyle_H__ #include "cocos2d.h" USING_NS_CC; class BulletStyle : public cocos2d::Node{ public: ~BulletStyle(); /** * 移除所有的东西 */ void removeAllObject(); /** *移除超出屏幕可视范围的子弹或者碰撞后的子弹清除 *@param pNode 要删除的子弹 */ void removeBullet(Node* pNode); /** *根据传入的飞机,子弹跟随发射 *@param plane为传入飞机,可为英雄飞机或敌机 */ virtual void createBullet(Node* plane); /** *发射子弹,在其中进行子弹的渲染和子弹的飞行动作,默认为单子弹 *@param dt子弹间隔发时间 */ virtual void shootBullet(float dt){} protected: //子弹容器 Vector <Sprite *> vecBullet; //批次渲染节点 SpriteBatchNode* bulletBatchNode; //传入的飞机 Node* plane; }; #endif实现文件BulletStyle.cpp /** *功能 创建子弹的基类 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #include "BulletStyle.h" BulletStyle::~BulletStyle(){ //removeAllObject(); } /** * 移除所有的东西 */ void BulletStyle::removeAllObject(){ bulletBatchNode->removeAllChildren(); vecBullet.clear(); this->removeAllChildren(); } /** * 移除子弹,将子弹从容器中移除,同时也从SpriteBatchNode中移除 */ void BulletStyle::removeBullet(Node* pNode) { if (NULL == pNode) { return; } Sprite* bullet = (Sprite*)pNode; bulletBatchNode->removeChild(bullet,true); vecBullet.eraSEObject(bullet); } /** *根据传入的飞机,子弹跟随发射 *@param plane为传入飞机,可为英雄飞机或敌机 */ void BulletStyle::createBullet(Node* plane){ this->plane = plane; //创建BatchNode节点 bulletBatchNode = SpriteBatchNode::create("bullet1.png"); this->addChild(bulletBatchNode); //每隔0.2S调用一次发射子弹函数 schedule(schedule_selector(BulletStyle::shootBullet),0.2f);//注意,这里的发射方法留给子类来实现!!! } 2.2 只发射一个子弹的类HeroBulletOne.h,注意,直接继承/** *功能 每次只发射一个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #pragma once #ifndef __HeroBulletOne_H__ #define __HeroBulletOne_H__ #include "cocos2d.h" #include "BulletStyle.h" USING_NS_CC; class HeroBulletOne : public BulletStyle { public: virtual void shootBullet(float dt); }; #endif实现文件: /** *功能 每次只发射一个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #include "HeroBulletOne.h" void HeroBulletOne::shootBullet(float dt) { Size winSize = Director::getInstance()->getWinSize(); auto PlanePos = plane->getPosition(); //从缓存中创建子弹 auto spritebullet = Sprite::createWithTexture(bulletBatchNode->getTexture()); //将创建好的子弹添加到BatchNode中进行批次渲染 bulletBatchNode->addChild(spritebullet); //将创建好的子弹添加到容器 vecBullet.pushBack(spritebullet); Point bulletPos = (Point(PlanePos.x,PlanePos.y + plane->getContentSize().height / 2 + 20)); spritebullet->setPosition(bulletPos); spritebullet->setScale(0.8f); float flyVelocity = 500;//运行速度,可以自己控制,每秒所走的像素 float flyLen = winSize.height - PlanePos.y; float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间 //子弹运行的距离和时间,从飞机处开始运行到屏幕顶端 auto actionMove = MoveTo::create(realFlyDuration,Point(bulletPos.x,winSize.height)); //子弹执行完动作后进行函数回调,调用移除子弹函数 auto actionDone = CallFuncN::create( CC_CALLBACK_1(HeroBulletOne::removeBullet,this)); //子弹开始跑动 Sequence* sequence = Sequence::create(actionMove,actionDone,NULL); spritebullet->runAction(sequence); } 2.3 发射二个子弹的类HeroBulletTwo.h,注意,直接继承/** *功能 每次发射二个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #pragma once #ifndef __HeroBulletTwo_H__ #define __HeroBulletTwo_H__ #include "cocos2d.h" #include "BulletStyle.h" USING_NS_CC; class HeroBulletTwo : public BulletStyle { public: virtual void shootBullet(float dt); }; #endif实现文件: /** *功能 每次发射二个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #include "HeroBulletTwo.h" void HeroBulletTwo::shootBullet(float dt) { Size winSize = Director::getInstance()->getWinSize(); auto PlanePos = plane->getPosition(); //从缓存中创建子弹 auto spritebullet1 = Sprite::createWithTexture(bulletBatchNode->getTexture()); auto spritebullet2 = Sprite::createWithTexture(bulletBatchNode->getTexture()); //将创建好的子弹添加到BatchNode中进行批次渲染 bulletBatchNode->addChild(spritebullet1); bulletBatchNode->addChild(spritebullet2); //将创建好的子弹添加到容器 vecBullet.pushBack(spritebullet1); vecBullet.pushBack(spritebullet2); Point bulletPos1 = (Point(PlanePos.x - plane->getContentSize().width / 4,PlanePos.y + plane->getContentSize().height / 2+10 )); Point bulletPos2 = (Point(PlanePos.x + plane->getContentSize().width / 4,PlanePos.y + plane->getContentSize().height / 2+10)); spritebullet1->setPosition(bulletPos1); spritebullet1->setScale(0.8f); spritebullet2->setPosition(bulletPos2); spritebullet2->setScale(0.8f); float flyVelocity = 500;//运行速度,可以自己控制,每秒所走的像素 float flyLen = winSize.height - PlanePos.y; float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间 //子弹运行的距离和时间,从飞机处开始运行到屏幕顶端 auto actionMove1 = MoveTo::create(realFlyDuration,Point(bulletPos1.x,winSize.height)); auto actionMove2 = MoveTo::create(realFlyDuration,Point(bulletPos2.x,winSize.height)); //子弹执行完动作后进行函数回调,调用移除子弹函数 auto actionDone = CallFuncN::create( CC_CALLBACK_1(HeroBulletTwo::removeBullet,this)); //子弹开始跑动 Sequence* sequence1 = Sequence::create(actionMove1,NULL); spritebullet1->runAction(sequence1); Sequence* sequence2 = Sequence::create(actionMove2,NULL); spritebullet2->runAction(sequence2); } 2.4 发射三个子弹的类HeroBulletThree.h,注意,直接继承/** *功能 每次发射三个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #pragma once #ifndef __HeroBulletThree_H__ #define __HeroBulletThree_H__ #include "cocos2d.h" #include "BulletStyle.h" USING_NS_CC; class HeroBulletThree : public BulletStyle { public: virtual void shootBullet(float dt); }; #endif实现文件: /** *功能 每次发射三个子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.14 */ #include "HeroBulletThree.h" void HeroBulletThree::shootBullet(float dt) { Size winSize = Director::getInstance()->getWinSize(); auto PlanePos = plane->getPosition(); double angle = M_PI * 80 / 180;//旋轉的角度 //从缓存中创建子弹 auto spritebullet = Sprite::createWithTexture(bulletBatchNode->getTexture()); auto spritebullet1 = Sprite::createWithTexture(bulletBatchNode->getTexture()); spritebullet1->setRotation(-angle); auto spritebullet2 = Sprite::createWithTexture(bulletBatchNode->getTexture()); spritebullet2->setRotation(angle); //将创建好的子弹添加到BatchNode中进行批次渲染 bulletBatchNode->addChild(spritebullet); bulletBatchNode->addChild(spritebullet1); bulletBatchNode->addChild(spritebullet2); //将创建好的子弹添加到容器 vecBullet.pushBack(spritebullet); vecBullet.pushBack(spritebullet1); vecBullet.pushBack(spritebullet2); Point bulletPos = (Point(PlanePos.x,PlanePos.y + plane->getContentSize().height / 2 + 20)); Point bulletPos1 = (Point(PlanePos.x - plane->getContentSize().width / 4-10,PlanePos.y + plane->getContentSize().height / 2+10 )); Point bulletPos2 = (Point(PlanePos.x + plane->getContentSize().width / 4+10,PlanePos.y + plane->getContentSize().height / 2+10)); spritebullet->setPosition(bulletPos); spritebullet->setScale(0.8f); spritebullet1->setPosition(bulletPos1); spritebullet1->setScale(0.8f); spritebullet2->setPosition(bulletPos2); spritebullet2->setScale(0.8f); float flyVelocity = 500;//运行速度,可以自己控制,每秒所走的像素 float flyLen = winSize.height - PlanePos.y; float flyLen1 = PlanePos.x / cos(angle);//按照度來算 float flyLen2 = (winSize.width - PlanePos.x) / cos(angle); float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间 float realFlyDuration1 = flyLen1 / flyVelocity;//实际飞行的时间 float realFlyDuration2 = flyLen2 / flyVelocity;//实际飞行的时间 //子弹运行的距离和时间,从飞机处开始运行到屏幕顶端 auto actionMove = MoveTo::create(realFlyDuration,winSize.height)); auto actionMove1 = MoveTo::create(realFlyDuration1,Point(0,PlanePos.x*tan(angle) + PlanePos.y)); auto actionMove2 = MoveTo::create(realFlyDuration2,Point(winSize.width,(winSize.width - PlanePos.x)*tan(angle) + PlanePos.y)); //子弹执行完动作后进行函数回调,调用移除子弹函数 auto actionDone = CallFuncN::create( CC_CALLBACK_1(HeroBulletThree::removeBullet,NULL); spritebullet->runAction(sequence); Sequence* sequence1 = Sequence::create(actionMove1,NULL); spritebullet2->runAction(sequence2); } 2.5、子弹管理器编写/** *功能 管理子弹、切换不同的子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #pragma once #ifndef __HeroBulletLayer_H__ #define __HeroBulletLayer_H__ #include "cocos2d.h" #include "BulletStyle.h" #include "HeroBulletOne.h" #include "HeroBulletTwo.h" #include "HeroBulletThree.h" class HeroBulletLayer : public cocos2d::Layer { public: HeroBulletLayer(Node* heroPlane); virtual bool init(); //根据英雄飞机创建子弹 static HeroBulletLayer* create(Node* heroPlane); //改变子弹 void changeBullet(int bulletNumber); public: Node* heroPlane;//传入的英雄飞机 BulletStyle *mBulletStyle;//子弹类型 int bulletNumber;//当前子弹编号 }; #endif实现文件: /** *功能 管理子弹、切换不同的子弹 *作者 林炳文(ling20081005@126.com 博客:http://blog.csdn.net/evankaka) *时间 2015.3.31 */ #include "HeroBulletLayer.h" HeroBulletLayer::HeroBulletLayer(Node* heroPlane) { this->heroPlane = heroPlane; mBulletStyle = NULL; bulletNumber = 1; } /** *创建子弹的静态方法 *@param heroPlane为英雄飞机 */ HeroBulletLayer* HeroBulletLayer::create(Node* heroPlane){ HeroBulletLayer* pRet = new HeroBulletLayer(heroPlane); if (pRet&&pRet->init()){ pRet->autorelease(); return pRet; } else{ delete pRet; pRet = NULL; return NULL; } } bool HeroBulletLayer::init() { bool bRet = false; do { CC_BREAK_IF(!Layer::init()); mBulletStyle = new HeroBulletOne(); mBulletStyle->autorelease(); mBulletStyle->createBullet(heroPlane); this->addChild(mBulletStyle); bRet = true; } while (0); return bRet; } /** *切换不同的子弹 *@param number 表示子弹的数目 */ void HeroBulletLayer::changeBullet(int number){ switch (number) { case 1: if (bulletNumber != 1){ this->removeChild(mBulletStyle,true); mBulletStyle = new HeroBulletOne(); bulletNumber = 1; mBulletStyle->createBullet(heroPlane); mBulletStyle->autorelease(); this->addChild(mBulletStyle); } break; case 2: if (bulletNumber != 2){ this->removeChild(mBulletStyle,true); mBulletStyle = new HeroBulletTwo(); bulletNumber = 2; mBulletStyle->createBullet(heroPlane); mBulletStyle->autorelease(); this->addChild(mBulletStyle); } break; case 3: if (bulletNumber != 3){ this->removeChild(mBulletStyle,true); mBulletStyle = new HeroBulletThree(); bulletNumber = 3; mBulletStyle->createBullet(heroPlane); mBulletStyle->autorelease(); this->addChild(mBulletStyle); } break; default: break; } } 2.6、调用方法游戏入口主文件 GameMain.h添加头文件#include "HeroBulletLayer.h"//这是子弹管理的层增加变量: HeroBulletLayer *mHeroBulletLayer; 然后是实现方法中GameMain.cpp的init()函数中增加 //加子弹 mHeroBulletLayer = HeroBulletLayer::create(mHeroPlane); this->addChild(mHeroBulletLayer,1);注意mHeroPlane是你的英雄飞机类,是上文中可以跟随手指运动的手机,不懂看这里, Cocos2d-x《雷电大战》(2)-精灵随手指移动,你点哪我走哪! 这里还没写成单例模式的,后头会再来改! 然后就是切换子弹啦: 你只需要在要切换子弹的地方: 发射一个子弹 mHeroBulletLayer->changeBullet(1);发射二个子弹 mHeroBulletLayer->changeBullet(2);发射三个子弹 mHeroBulletLayer->changeBullet(3); 这里我为了测试,设置成每个5秒自动切换子弹类型: GameMain.h加个变量 int number;//表示当前子弹的类型 GameMain.cpp中init()函数中增加: //每隔5S改變一次子子彈類型 number = 1; schedule(schedule_selector(GameMain::changeBullet),5.0f); 下面是定时器的方法 void GameMain::changeBullet(float dt){ if (number == 1){ mHeroBulletLayer->changeBullet(2); number = 2; } else if (number == 2){ mHeroBulletLayer->changeBullet(3); number = 3; } else if (number == 3) { mHeroBulletLayer->changeBullet(1); number = 1; } CCLOG("CHANGE"); } 效果: 这里它会自动每隔5s切换不同的子弹,由于上传图片的限制。只能这样了。 三、总结是不是很方便呢?当我需要增加一个子弹类型时,我只需要继承BulletStyle.然后重写函数shootBullet(float dt) 即可。然后在需要更改子弹的位置bool HeroBulletLayer::changeBullet(int number)增加每4种子弹。第5种子弹......这样就增加了代码的复用性,而且很容易懂。也省去了一大堆的if-else判断。林炳文Evankaka原创作品。转载请注明出处http://www.52php.cn/tag/http://blog.csdn.net/evankaka (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |