第二节:添加无限移动背景与英雄飞机
一、新建文件
删除HelloWorldScene.h与HelloWorldScene.cpp文件,新建FlaPlane类如下,cpp文件同样的创建方法,这里注意FlyPlane的位置一定要在classes文件夹下,名字随意,最好和项目名保持一致。
二、修改AppDelegate.cpp
AppDelegate.cpp中会有两处红线错误,第一个地方是头文件,改成
#include "FlyPlane.h"
第二个地方改成
auto scene = FlyPlane::createScene();
这里的错误很好理解,因为HelloWorld层类已经被删除了。
修改bool AppDelegate::applicationDidFinishLaunching() 函数代码,如下:
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLView::create("FlyPlane");
director->setOpenGLView(glview);
}
//glview设置设备尺寸 和 屏幕拉升解决策略--适应宽度
glview->setFrameSize(480,640);
glview->setDesignResolutionSize(480,640,ResolutionPolicy::FIXED_WIDTH);
//FileUtils添加查找资源树
cocos2d::FileUtils::getInstance()->addSearchPath("ui");
// turn on display FPS
director->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / 60);
// create a scene. it's an autorelease object
auto scene = FlyPlane::createScene();
// run
director->runWithScene(scene);
return true;
}
#include "cocos2d.h"
//可以加USING_NS_CC不用写cocos2d
class FlyPlane : public cocos2d::Layer {
public:
CREATE_FUNC(FlyPlane);
bool init();
static cocos2d::Scene* createScene();
//定时器函数必须是void返回类型,必须有一个float类型的参数,刷新图片必用
void update(float);
};
四、修改FlyPlane.cpp文件
#include "GameScene.h"
cocos2d::Scene* GameScene::createScene() {
//1、auto是c++11的新特性,是自动根据变量的值确定变量的类型,类似var
//2、大多数时候,cocos中的类想获取它的对象,不建议去new,而是调用它的create方法(oc语法导致)
//调用cocos2d空间中scene类的静态create方法,用scene连接
cocos2d::Scene* scene = cocos2d::Scene::create();
//GameScene是一个层
auto gameLayer = GameScene::create();
//只有场景中的元素才能被渲染
scene->addChild(gameLayer);
return scene;
}
bool GameScene::init() {
cocos2d::Layer::init();
//使用精灵集中的帧,需要两步:1.将【plist】读取到缓存中,2.通过帧名称创建精灵并显示
cocos2d::SpriteFrameCache::getInstance()->
addSpriteFramesWithFile("shoot_background.plist");
auto bg1 = cocos2d::Sprite::createWithSpriteFrameName("background.png");
//this表示scene,即GameScene
this->addChild(bg1, -1, 1);
//设置锚点
bg1->setAnchorPoint(cocos2d::Point(0, 0));
//texture:纹理,通过精灵找到对应的纹理,并开启抗锯齿
bg1->getTexture()->setAliasTexParameters();
auto bg2 = cocos2d::Sprite::createWithSpriteFrameName("background.png");
this->addChild(bg2, -1, 2);
bg2->setAnchorPoint(cocos2d::Point(0, 0));
bg2->getTexture()->setAliasTexParameters();
//添加英雄战机
cocos2d::SpriteFrameCache::getInstance()->
addSpriteFramesWithFile("shoot.plist");
auto hero = cocos2d::Sprite::createWithSpriteFrameName("hero1.png");
this->addChild(hero, 3, 3);
hero->setPositionX(bg1->getContentSize().width / 2);
hero->setPositionY(100);
//定时器。scheduleUpdate每帧调用一次update函数
scheduleUpdate();
auto touchListener = cocos2d::EventListenerTouchOneByOne::create();
auto VISIBLE_SIZE = cocos2d::Director::getInstance()->getVisibleSize();
touchListener->onTouchBegan = [=](cocos2d::Touch* touch, cocos2d::Event*) {
this->m_vec = hero->getPosition() - touch->getLocation();
bool isContain = hero->getBoundingBox().containsPoint(touch->getLocation());
return isContain;
};
float minX = hero->getContentSize().width/2;
float maxX = VISIBLE_SIZE.width - minX;
float minY = hero->getContentSize().height/2;
float maxY = VISIBLE_SIZE.height - minY;
touchListener->onTouchMoved = [=](cocos2d::Touch* touch, cocos2d::Event*) {
auto VISIBLE_SIZE = cocos2d::Director::getInstance()->getVisibleSize();
auto desP = touch->getLocation() + this->m_vec;
hero->setPosition(MAX(minX,MIN(desP.x, maxX)), MAX(minY,MIN(desP.y, maxY)));
//hero->runAction(cocos2d::MoveTo::create(0.5f, touch->getLocation()));
};
touchListener->onTouchEnded = [](cocos2d::Touch* touch, cocos2d::Event*){
};
//
hero->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener,hero);
return true;
}
void GameScene::update(float dt) {
//通过tag获取背景精灵
auto bg1 = this->getChildByTag(1);
auto bg2 = this->getChildByTag(2);
//auto hero = this->getChildByTag(3);
bg1->setPositionY(bg1->getPositionY() - 5);
bg2->setPositionY(bg1->getPositionY() + bg1->getContentSize().height);
if(bg2->getPositionY() <= 0) { //bg1掉完了,将bg1的Y归0
bg1->setPositionY(0);
}
}
运行发现背景图片已经可以连续的向下滚动了。
五、添加英雄战机
1.在classes文件夹中添加公用数据头文件,新建一个头文件CommonData.h,添加代码
#define VISIBLE_SIZE cocos2d::Director::getInstance()->getVisibleSize()
如下:
在FlyPlane.cpp中添加头文件
#include "CommonData.h"
修改bool FlyPlane::init()函数
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, -1, 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, 0, 3);
//定时器。scheduleUpdate每帧调用一次update函数
scheduleUpdate();
return true;
}
现在,背景和英雄飞机就设置成功了。
注:关于bool FlyPlane::init()函数何时会被调用的问题。
1、先看到项目入口APPDelegete.cpp文件中的applicationDidFinishLaunching()函数,发现有这样一行代码
auto scene = FlyPlane::createScene();
这时就会调用FlyPlane的静态函数createScene()
2、研究FlyPlane的静态函数createScene(),又发现有这样一行代码
auto layer = FlyPlane::create();
我们发现FlyPlane.h头文件中没有create()函数,那么为什么不报错呢?
这是因为我们的FlyPlane.h头文件中有个CREATE_FUNC(FlyPlane)函数,我们按F12进行查看发现CREATE_FUNC(FlyPlane)是个宏函数
#define CREATE_FUNC(__TYPE__) \ //__TYPE__表示占位符,这里表示FlyPlane
static __TYPE__* create() \ //这里发现create()就是CREATE_FUNC(FlyPlane)
{ \
__TYPE__ *pRet = new __TYPE__(); \ //FlyPlane *pRet = new FlyPlane();
if (pRet && pRet->init()) \ //这里就调用了FlyPlane->init()
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \ //稳定安全的创建回收函数
} \
}
通过注释可以看出只要调用FlyPlane的create()静态函数,只要没有调用过init()函数,就会调用init()函数,这就是init()被调用的方法。