第四节:添加英雄子弹
实现这个功能需要如下考虑:
1、每隔一小段时间就创建一个子弹在英雄机顶,并将其加入一个sprite*的容器中,并添加在flyplane层中显示出来。
2、创建出来的子弹每帧刷新都增加Y坐标让其看起来向上移动。
3、子弹出界,回收清除。 (打中敌人也要从容器中和flyplane对象中清除,以后再考虑)。
综合这几点修改FlyPlane.h 和 FlyPlane.cpp文件
一、FlyPlane.h
- #include "cocos2d.h"
- class FlyPlane : public cocos2d::Layer {
- public:
- CREATE_FUNC(FlyPlane);
- bool init();
- static cocos2d::Scene* createScene();
- //定时器函数必须是void返回类型,必须有一个float类型的参数
- void update(float);
- private:
- cocos2d::Point m_vec;
- //英雄子弹集合
- std::vector<cocos2d::Sprite*> h_bullets;
- //创建子弹
- void createBullet(float);
- };
- #include "FlyPlane.h"
- #include "CommonData.h"
- cocos2d::Scene* FlyPlane::createScene() {
- //1、auto是c++11的新特性,是自动根据变量的值确定变量的类型,类似var
- //2、大多数时候,cocos中的类想获取它的对象,不建议去new,而是调用它的create方法(oc语法导致)
- //调用cocos2d空间中scene类的静态create方法,返回一个cocos2d::Scene*对象给scene连接
- //‘场景’是一个自动关联的对象
- auto scene = cocos2d::Scene::create();
- auto layer = FlyPlane::create();
- //把层添加到场景里
- scene->addChild(layer);
- return scene;
- }
- bool FlyPlane::init() {
- //一定要先调用父类初始函数
- if( !cocos2d::Layer::init() ) {
- return false;
- }
- //使用精灵集需要两步
- //1、将美工做好的plist文件读取到缓存中
- //2、通过帧名字创建精灵并显示
- cocos2d::CCSpriteFrameCache::getInstance()->
- addSpriteFramesWithFile("shoot_background.plist");
- auto bg1 = cocos2d::Sprite::createWithSpriteFrameName("background.png");
- //把精灵bg1加到FlyPlane层中,第二个参数ZOrder表示距离用户的距离,第三个参数tag设为1
- this->addChild(bg1,-1,1);
- //默认锚点为(0.5,0.5),只会显示一半的图,必须设置锚点为(0,0)
- bg1->setAnchorPoint(cocos2d::Point(0,0));
- //texture:纹理,通过精灵找到对应的纹理,并开启抗锯齿
- bg1->getTexture()->setAliasTexParameters();
- auto bg2 = cocos2d::Sprite::createWithSpriteFrameName("background.png");
- this->addChild(bg2,2);
- bg2->setAnchorPoint(cocos2d::Point(0,0));
- bg2->getTexture()->setAliasTexParameters();
- //添加英雄
- cocos2d::CCSpriteFrameCache::getInstance()->
- addSpriteFramesWithFile("shoot.plist");
- auto hero = cocos2d::Sprite::createWithSpriteFrameName("hero1.png");
- hero->setPosition(VISIBLE_SIZE.width / 2,100);
- this->addChild(hero,3,3);
- //为英雄添加飞行动作,动作由动画组成,所以得到动作对象前,需要先得到动画对象
- //一、创建动画对象
- //1.1通过create得到动画对象
- auto animation = cocos2d::Animation::create();
- //1.2添加这个动画所要用的精灵帧
- animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->
- getSpriteFrameByName("hero1.png"));
- animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->
- getSpriteFrameByName("hero2.png"));
- //1.3设置切换时间
- animation->setDelayPerUnit(0.2f);
- //1.4循环次数,默认为1,设为-1使其无限循环
- animation->setLoops(-1);
- //二、根据动画对象创建动作对象
- auto animate = cocos2d::Animate::create(animation);
- //三、让hero执行这个动作
- hero->runAction(animate);
- //用单个处理事件添加鼠标监听事件
- auto listener = cocos2d::EventListenerTouchOneByOne::create();
- //用lambda表达式处理分解事件
- //Lambda表达式:
- // {} 类似于普通函数的函数体
- // () 类似于普通函数的参数列表
- // [] 默认Lambda表达式不能访问外部的变量,如果想访问外部变量,就通过中括号传进来
- listener->onTouchBegan = [=](cocos2d::Touch* touch,cocos2d::Event*) {
- auto touchPos = touch->getLocation();
- bool isContain = hero->getBoundingBox().containsPoint(touchPos);
- if(isContain) {
- m_vec = hero->getPosition() - touchPos;//my_vector,记录touchPos指向hero的向量
- }
- return isContain;
- };
- const float leftMinX = hero->getContentSize().width / 2; //英雄的X最小值(左边界线)
- const float rightMaxX = VISIBLE_SIZE.width - hero->getContentSize().width / 2;//英雄X最大值(右边界线)
- const float downMinY = hero->getContentSize().height / 2; //英雄Y最小值(下边界线)
- const float upMaxY = VISIBLE_SIZE.height - hero->getContentSize().height / 2; //英雄Y最大值(上边界线)
- listener->onTouchMoved = [=](cocos2d::Touch* touch,cocos2d::Event*) {
- auto touchPos = touch->getLocation() + m_vec;
- //让英雄跟着手指动并且不超出边界
- hero->setPosition(cocos2d::Point(MAX(leftMinX,MIN(rightMaxX,touchPos.x)),MAX(downMinY,MIN(upMaxY,touchPos.y))));
- };
- //将监听器添加到事件分配器上
- this->getEventDispatcher()->
- addEventListenerWithSceneGraPHPriority(listener,hero);
- //定时添加子弹
- schedule(schedule_selector(FlyPlane::createBullet),0.1f);
- //定时器。scheduleUpdate每帧调用一次update函数
- scheduleUpdate();
- return true;
- }
- void FlyPlane::update(float) {
- auto bg1 = this->getChildByTag(1);
- auto bg2 = this->getChildByTag(2);
- //bg1下落,bg2跟随
- bg1->setPositionY(bg1->getPositionY() - 5);
- bg2->setPositionY(bg1->getPositionY() + bg1->getContentSize().height);
- if(bg2->getPositionY() <= 0) {
- bg1->setPositionY(0);
- }
- for(std::vector<cocos2d::Sprite*>::iterator iter = this->h_bullets.begin(); iter != this->h_bullets.end();) {
- (*iter)->setPositionY((*iter)->getPositionY() + 12); //更新子弹位置
- if((*iter)->getPositionY() > VISIBLE_SIZE.height) { //判断子弹是否越界,越界则清除,双开(容器清除,FlyPlane层中清除)
- this->removeChild((*iter));
- iter = h_bullets.erase(iter);
- } else {
- ++iter;
- }
- }
- }
- void FlyPlane::createBullet(float) {
- auto hero = this->getChildByTag(3);
- auto bullet = cocos2d::Sprite::createWithSpriteFrameName("bullet1.png");//初始子弹在shoot.plist中名字叫bullet1
- bullet->setPosition(hero->getPosition() + cocos2d::Point(0,hero->getContentSize().height / 2));//子弹初始位置
- this->addChild(bullet,0); //zorder为0,高于背景层-1,低于英雄的3
- //每创建一个子弹就存在容器中
- h_bullets.push_back(bullet);
- }
最主要更新的两段代码就是创建子弹代码
- void FlyPlane::createBullet(float) {
- auto hero = this->getChildByTag(3);
- auto bullet = cocos2d::Sprite::createWithSpriteFrameName("bullet1.png");//初始子弹在shoot.plist中名字叫bullet1
- bullet->setPosition(hero->getPosition() + cocos2d::Point(0,0); //zorder为0,高于背景层-1,低于英雄的3
- //每创建一个子弹就存在容器中
- h_bullets.push_back(bullet);
- }
以及子弹容器遍历判断的代码
- for(std::vector<cocos2d::Sprite*>::iterator iter = this->h_bullets.begin(); iter != this->h_bullets.end();) {
- (*iter)->setPositionY((*iter)->getPositionY() + 12); //更新子弹位置
- if((*iter)->getPositionY() > VISIBLE_SIZE.height) { //判断子弹是否越界,越界则清除,双开(容器清除,FlyPlane层中清除)
- this->removeChild((*iter));<span>
- iter = h_bullets.erase(iter);
- } else {
- ++iter;
- }
- }
运行效果图如下: