cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(5)

来源:互联网 发布:69端口 编辑:程序博客网 时间:2024/05/22 10:48

今天介绍的是管道层

PipeLayer.h

PipeLayer.cpp

管道层主要实现的是管道从右边往左边平移,结束后移除,而且管道还要长短高低不一样,然后就是如何判断小鸟通过一个管道。先说管道的平移,这个很简单,用一个函数把两跟管道封装好,让它moveby或者moveto好了,平移结束后,用一个回调函数移除自己就够了,当然封装好管道后,我们要把每一个管道放到一个数组里,方便管理嘛;然后就是管道高低不一样这里用一张图表示:

最后就是小鸟通过管道判断,这里我们是判断一个完整的管道是否通过屏幕中心线(因为小鸟是固定在屏幕中心,上下移动的)。这个类大致就这些内容。

下面这张图解释了为什么管道停止移动后,要取消向上管道的物理模型,防止小鸟死亡后直接掉在管道上:


下面是代码分析:

//PipeLayer.h#pragma once#include "cocos2d.h"class PipeLayer:public cocos2d::Layer{public:PipeLayer();~PipeLayer();bool init();//添加一个移动的组合管道void addPipe(float);//管道移动结束后的回调函数void pipeMoveOver(cocos2d::Ref *);//管道停止移动void stopPipe();//计时器执行函数void update(float);//管道开始移动void startPipe();CREATE_FUNC(PipeLayer);private://管道数组一cocos2d::Array * pipe_arr;//管道数组二cocos2d::Array * pipe_arr2;bool btn;};


//PipeLayer.cpp#include "PipeLayer.h"#include "define.h"#include "NumberLayer.h"USING_NS_CC;PipeLayer::PipeLayer(){}PipeLayer::~PipeLayer(){//析构函数释放数组pipe_arr->release();pipe_arr2->release();}bool PipeLayer::init(){if (!Layer::init()){return false;}//两个数组初始化,其实只要一个数组就够了,楼主刚开始写的时候傻逼了//pipe_arr 这个数组是用来检测加分的//pipe_arr2 这个数组是为了方便统一处理管道pipe_arr=Array::create();//防止被自动释放pipe_arr->retain();pipe_arr2=Array::create();pipe_arr2->retain();btn=true;return true;}void PipeLayer::addPipe( float ){log("this pipe");//向上管道初始化auto pipe_up=Sprite::createWithSpriteFrameName("pipe_up.png");pipe_up->setPosition(Point(pipe_up->getContentSize().width/2,pipe_up->getContentSize().height/2));auto body_up=PhysicsBody::create();auto body_shape_up=PhysicsShapeBox::create(pipe_up->getContentSize());body_up->addShape(body_shape_up);body_up->setDynamic(false);body_up->setGravityEnable(false);body_up->setCategoryBitmask(1);body_up->setCollisionBitmask(-1);body_up->setContactTestBitmask(-1);pipe_up->setPhysicsBody(body_up);//向下管道初始化,这边的THROUGH_HEIGHT是两根管道之间的空隙auto pipe_down=Sprite::createWithSpriteFrameName("pipe_down.png");pipe_down->setPosition(Point(pipe_down->getContentSize().width/2,pipe_down->getContentSize().height/2+pipe_up->getContentSize().height+THROUGH_HEIGHT));auto body_down=PhysicsBody::create();auto body_shape_down=PhysicsShapeBox::create(pipe_down->getContentSize());body_down->addShape(body_shape_down);body_down->setDynamic(false);body_down->setGravityEnable(false);body_down->setCategoryBitmask(1);body_down->setCollisionBitmask(-1);body_down->setContactTestBitmask(-1);pipe_down->setPhysicsBody(body_down);//这边的node相当于一个容器把这两个管道封装在一个节点中并设置targetauto node=Node::create();node->addChild(pipe_up,0,PIPE_UP);node->addChild(pipe_down,0,PIPE_DOWN);node->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);//关于管道Y坐标的设置(就是管道上下长度不一样的处理),大家还是看图例,说不清楚//管道是从右边移动到左边,所以PIPE_X的值肯定比游戏的width要大这里设定是300int range=rand()%PIPE_RANGE;node->setPosition(Point(PIPE_X,PIPE_Y+range));//管道移动的时间,距离,以及方向auto moveby=MoveBy::create(PIPE_TIME,PIPE_VELOCITY);//管道移动结束后执行的回调函数auto callback=CallFuncN::create(CC_CALLBACK_1(PipeLayer::pipeMoveOver,this));//把管道移动和结束后的回调放到列队中auto sequence=Sequence::create(moveby,callback,NULL);node->runAction(sequence);this->addChild(node);//把管道放到两个数组中pipe_arr->addObject(node);pipe_arr2->addObject(node);//启动计时器,这个计时器是用来判断得分的//也就是小鸟是否通过管道//只要启动一次就够了,所以这边有个btnif (btn){this->scheduleUpdate();btn=false;}}//移动结束后,从这个类和数组中移除管道void PipeLayer::pipeMoveOver(Ref * r){Sprite * sp=(Sprite* )r;this->removeChild(sp);pipe_arr2->removeObject(sp);}//停止管道移动(小鸟死亡后)void PipeLayer::stopPipe(){this->unschedule(schedule_selector(PipeLayer::addPipe));this->unscheduleUpdate();//这里取消了向上管道的物理结构//这样子做是为了当小鸟撞到向下管道死亡了,不跌落在向上管道上//见图例Ref * p;CCARRAY_FOREACH(pipe_arr2,p){auto n=(Node*)p;//管道停止移动n->stopAllActions();//向上管道取消物理结构n->getChildByTag(PIPE_UP)->getPhysicsBody()->setEnable(false);}}//积分void PipeLayer::update(float){auto origin=Director::getInstance()->getVisibleOrigin();auto visibleSize=Director::getInstance()->getVisibleSize();//如果管道数量为0,则直接返回if (pipe_arr->count()<=0){return;}//取管道数组中的第一个管道(也就是第一生成的管道)//它在管道运动的最前面Node * tn=(Node*)pipe_arr->getObjectAtIndex(0);//如果管道整体过了场景的一半,那就加分//同时在这个数组中,移除了这个管道//这样,位于这个管道后的下一管道就变成最前面的管道了//如://index: 0 1 2 3 4//array: A B C D E//       ↑//     这是序列为0的管道A,当它过完场景中点时,它在数组中就被移除了,然后就变成//index: 0 1 2 3 4//arrat: B C D E F//管道B就变成序列0了,然后再检测if ( tn->getPositionX()<(visibleSize.width/2-52)){log("X:%f",tn->getContentSize().width);pipe_arr->removeObjectAtIndex(0);CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("sounds/sfx_point.mp3");NumberLayer::getInstance()->addScore();}}//管道开始移动void PipeLayer::startPipe(){this->schedule(schedule_selector(PipeLayer::addPipe),PIPE_FRE);}


结束


0 0
原创粉丝点击