• Cocos2d-x3.0游戏实例《不要救我》三——背景滚动周期


    好。让我们来解释一下这个无限循环滚动的背景。这方面的知识一直讲到烂。我以前的文章还介绍了。所以不是那么特别清楚。

    笨木头花心贡献,啥?花心?不呢,是用心~

    转载请注明,原文地址:http://www.benmutou.com/blog/archives/823

    文章来源:笨木头与游戏开发

    为什么是循环滚动背景?

    用循环滚动背景,事实上是由于我想偷懒,由于这样我仅仅须要准备一张图片就能够了。

    我们终于要创建这种背景,如图:

    Cocos2d-x3.0游戏实例之《别救我》第三篇-滚动背景

     

     

    背景是在滚动的,大家有没有看到?(小若:看你妹,这是jpg,不是gif)

    大家是不是非常在意以下的那多出来的一条锯齿?它可不是坐标错位了,这是一个伏笔(还伏笔,你以为写小说啊。)。

    本篇教程会用到的图片资源到这里下载:http://download.csdn.net/detail/musicvs/7392931

    创建2张连续的背景图片

    要实现循环滚动的背景,须要2张同样的图片实现,图片首尾相接。

    我们要创建一个新的类。叫做BackgroundLayer,用来实现滚动背景。

    创建2张同样的背景图片,非常easy,代码例如以下:

    1. Size visibleSize = Director::getInstance()->getVisibleSize();
    2.  /* 背景图片 */
    3.  m_bg1 = Sprite::create("background.jpg");
    4.  m_bg1->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.5f));
    5.  this->addChild(m_bg1);
    6.  m_bg2 = Sprite::create("background.jpg");
    7.  m_bg2->setPosition(Point(visibleSize.width * 0.5f, -visibleSize.height * 0.5f));
    8.  this->addChild(m_bg2);
    m_bg1和m_bg2都是Sprite对象。由于后面要用到。所以直接作为类的成员属性,方便调用。

    m_bg1是屏幕居中。m_bg2要紧接着m_bg1的以下,大家感受一下。

    创建边缘锯齿

    先跑一下题,我们把边缘锯齿也给加入好:

    1. /* 创建边缘锯齿 */
    2.  auto border = Sprite::create("border.png");
    3.  Size borderSize = border->getContentSize();
    4.  auto border1 = createBorder(Point(borderSize.width * 0.5f, borderSize.height * 0.5f));
    5.  this->addChild(border1);
    6.  auto border2 = createBorder(Point(visibleSize.width - borderSize.width * 0.5f, borderSize.height * 0.5f));
    7.  border2->setFlippedX(true);
    8.  this->addChild(border2);
    9.  auto border3 = createBorder(Point(visibleSize.width * 0.5f, visibleSize.height * 0.15f));
    10.  borderSize = border3->getContentSize();
    11.  border3->setRotation(90.0f);
    12.  this->addChild(border3);
    一共三个锯齿,左右各一个。下方一个。

    createBorder是自己定义函数,代码例如以下:

    1. Sprite* BackgroundLayer::createBorder(Point pos)
    2. {
    3.     auto border = Sprite::create("border.png");
    4.     Size borderSize = border->getContentSize();
    5.     auto body = PhysicsBody::createBox(borderSize);
    6.     body->setDynamic(false);
    7.     body->setCategoryBitmask(1);    // 0001
    8.     body->setCollisionBitmask(1);   // 0001
    9.     body->setContactTestBitmask(1); // 0001
    10.     border->setPhysicsBody(body);
    11.     border->setPosition(pos);
    12.     return border;
    13. }
    好,这个函数要略微解释一下。这里使用PhysicsBody的createBox函数创建实体盒子刚体。由于边缘不是空心的。

    然后调用了setDynamic函数,让刚体成为静态物体,也就是说。物理世界不会对它起产生影响了,它不会被撞飞。随你怎么撞,它都纹丝不动~

    可是,它会对其它物理对象产生影响。比方有人撞了它,那个人就可能会反弹~

    接着,有三个非常特别的函数:setCategoryBitmask、setCollisionBitmask、setContactTestBitmask。

    这三个函数是用于物体间的碰撞检測的,用来作为推断条件,要解释它们须要不小的篇幅,所以我就不解释了(小若:有没有墙?我想撞一下)

    本游戏在碰撞检測方面极其简单,所以不理解这三个函数都全然没有影响。由于游戏里的全部对象都能产生碰撞,没有什么特别的地方。

    假设以后有机会。我再单独写一篇文章来介绍吧(或者大家百度一下)

    眼下的代码

    好,来看看眼下为止BackgroundLayer的代码,头文件例如以下:

    1. #ifndef BackgroundLayer_H
    2. #define BackgroundLayer_H
    3. #include "cocos2d.h"
    4. USING_NS_CC;
    5. class BackgroundLayer : public Layer
    6. {
    7. public:
    8.     BackgroundLayer();
    9.     ~BackgroundLayer();
    10.     CREATE_FUNC(BackgroundLayer);
    11.     virtual bool init();
    12. private:
    13.     Sprite* m_bg1;
    14.     Sprite* m_bg2;
    15.     Sprite* createBorder(Point pos);
    16. };
    17. #endif
    Cpp文件例如以下:
    1. #include "BackgroundLayer.h"
    2. BackgroundLayer::BackgroundLayer(){}
    3. BackgroundLayer::~BackgroundLayer(){}
    4. bool BackgroundLayer::init()
    5. {
    6.     if (!Layer::init())
    7.     {
    8.         return false;
    9.     }
    10.     Size visibleSize = Director::getInstance()->getVisibleSize();
    11.     /* 背景图片 */
    12.     m_bg1 = Sprite::create("background.jpg");
    13.     m_bg1->setPosition(Point(visibleSize.width * 0.5f, visibleSize.height * 0.5f));
    14.     this->addChild(m_bg1);
    15.     m_bg2 = Sprite::create("background.jpg");
    16.     m_bg2->setPosition(Point(visibleSize.width * 0.5f, -visibleSize.height * 0.5f));
    17.     this->addChild(m_bg2);
    18.     /* 创建边缘锯齿 */
    19.     auto border = Sprite::create("border.png");
    20.     Size borderSize = border->getContentSize();
    21.     auto border1 = createBorder(Point(borderSize.width * 0.5f, borderSize.height * 0.5f));
    22.     this->addChild(border1);
    23.     auto border2 = createBorder(Point(visibleSize.width - borderSize.width * 0.5f, borderSize.height * 0.5f));
    24.     border2->setFlippedX(true);
    25.     this->addChild(border2);
    26.     auto border3 = createBorder(Point(visibleSize.width * 0.5f, visibleSize.height * 0.15f));
    27.     borderSize = border3->getContentSize();
    28.     border3->setRotation(90.0f);
    29.     this->addChild(border3);
    30.     return true;
    31. }
    32. Sprite* BackgroundLayer::createBorder(Point pos)
    33. {
    34.     auto border = Sprite::create("border.png");
    35.     Size borderSize = border->getContentSize();
    36.     auto body = PhysicsBody::createBox(borderSize);
    37.     body->setDynamic(false);
    38.     body->setCategoryBitmask(1);    // 0001
    39.     body->setCollisionBitmask(1);   // 0001
    40.     body->setContactTestBitmask(1); // 0001
    41.     border->setPhysicsBody(body);
    42.     border->setPosition(pos);
    43.     return border;
    44. }
    先測试一下

    我们来先測试一下代码的执行情况吧,我们给TollgateScene加入BackgroundLayer层,改动一下TollgateScene的scene函数:

    1. Scene* TollgateScene::scene()
    2. {
    3.     auto scene = Scene::createWithPhysics();
    4.     /* 这里省略了非常多代码 */
    5.     /* 背景层 */
    6.     auto backgroundLayer = BackgroundLayer::create();
    7.     scene->addChild(backgroundLayer, 0);
    8.     auto layer = TollgateScene::create();
    9.     scene->addChild(layer, 10);
    10.     return scene;
    11. }
     

    OK。这样就能够了。再次执行代码,正常情况下,如图所看到的:

    Cocos2d-x3.0游戏实例之《别救我》第三篇-滚动背景

     

    (小若:这就是一開始的那张图吧?连图片地址都一样好吧)

    如今地图是不会滚动的,没意思,我们来開始滚床单…不,不好意思。习惯了(邪恶)。是滚动背景才对。

    统一控制游戏逻辑

    地图滚动,事实上就是不断改变2张地图的坐标,要不断改变坐标。就要用schedule来实现,schedule能够在游戏每一帧或者每隔一段时间的时候执行一次逻辑,这个假设不了解的,能够看看我的另外几篇关于schedule的文章:

    【木头Cocos2d-x 032】我是定时器(第01章)—我爱单线程之schedule介绍

    【木头Cocos2d-x 033】我是定时器第02章—HelloWorld之scheduleUpdate

    【木头Cocos2d-x 034】我是定时器(第03章)—真正的定时器之schedule

    【木头Cocos2d-x 035】我是定时器(第04章)—停止update和触发器

    木头我有一个坏习惯,那就是把游戏中全部的逻辑都用一个schedule来完毕,这么说有点模糊,直接看代码吧。

    首先给TollgateScene加入一个logic函数:

    1. class TollgateScene : public Layer
    2. {
    3. public:
    4.     ~TollgateScene();
    5.     static Scene* scene();
    6.     CREATE_FUNC(TollgateScene);
    7.     virtual bool init();
    8.     virtual void onExit() override;
    9. private:
    10.     void logic(float dt);
    11.     BackgroundLayer* m_backgroundLayer;
    12. };
    13. #endif
     

    以及我偷偷加入了一个BackgroundLayer成员变量,大实用处,不要着急~

    然后改动一下TollgateScene的scene函数:

    1. Scene* TollgateScene::scene()
    2. {
    3.     auto scene = Scene::createWithPhysics();
    4.     /* 这里省略了非常多代码 */
    5.     /* 背景层 */
    6.     auto backgroundLayer = BackgroundLayer::create();
    7.     scene->addChild(backgroundLayer, 0);
    8.     auto layer = TollgateScene::create();
    9.     scene->addChild(layer, 10);
    10.     layer->m_backgroundLayer = backgroundLayer;
    11.     return scene;
    12. }
     

    留意最后一句代码(小若:是倒数第二句!

    )。好吧。倒数第二句,我们保留了BackgroundLayer的引用。也许这样保持引用是比較糟糕的做法,也许用getChildByTag的方式来获取BackgroundLayer会好一些,但由于这对象要使用非常多次,我选择了直接保存引用。

    大家依据个人喜好来决定吧~

    OK,最重要的,看看TollgateScene的logic函数实现。有点复杂,大家要有心理准备:

    1. void TollgateScene::logic(float dt)
    2. {
    3.     m_backgroundLayer->logic(dt);
    4. }
     

    (小若:= =哇,好复杂啊,全然看不懂….(蛇精病))

    我想,大家已经理解我之前说的,统一控制逻辑的意思了吧?由TollgateScene场景来调用各个层的logic函数。这样非常方便。要停止逻辑的时候,仅仅要由TollgateScene控制一下就能够了,不须要对各个层单独地进行控制。

    OK,别忘了。在TollgateScene的init函数加上schedule的调用:

    1. bool TollgateScene::init()
    2. {
    3.     if (!Layer::init())
    4.     {
    5.         return false;
    6.     }
    7.     this->schedule(schedule_selector(TollgateScene::logic));
    8.     return true;
    9. }
     

    BackgroundLayer背景层的逻辑

    好了,我们还得为BackgroundLayer加入一个logic逻辑处理函数,头文件加入函数声明:

    1. class BackgroundLayer : public Layer
    2. {
    3. public:
    4.     BackgroundLayer();
    5.     ~BackgroundLayer();
    6.     CREATE_FUNC(BackgroundLayer);
    7.     virtual bool init();
    8.     void logic(float dt);
    9. private:
    10.     Sprite* m_bg1;
    11.     Sprite* m_bg2;
    12.     Sprite* createBorder(Point pos);
    13. };
     

    BackgroundLayer的logic函数实现例如以下,这个就真的有点小复杂了:

    1. void BackgroundLayer::logic(float dt) {
    2.     int posY1 = m_bg1->getPositionY(); // 背景地图1的Y坐标
    3.     int posY2 = m_bg2->getPositionY(); // 背景地图2的Y坐标
    4.     int iSpeed = 3;    // 地图滚动速度
    5.     /* 两张地图向上滚动(两张地图是相邻的,所以要一起滚动。否则会出现空隙) */
    6.     posY1 += iSpeed;
    7.     posY2 += iSpeed;
    8.     /* 屏幕宽 */
    9.     int iVisibleHeight = Director::getInstance()->getVisibleSize().height;
    10.     /* 当第1个地图全然离开屏幕时,让第2个地图全然出如今屏幕上。同一时候让第1个地图紧贴在第2个地图后面 */
    11.     if (posY1 > iVisibleHeight * 1.5f) {
    12.         posY2 = iVisibleHeight * 0.5f;
    13.         posY1 = -iVisibleHeight * 0.5f;
    14.     }
    15.     /* 同理。当第2个地图全然离开屏幕时,让第1个地图全然出如今屏幕上。同一时候让第2个地图紧贴在第1个地图后面 */
    16.     if (posY2 > iVisibleHeight * 1.5f) {
    17.         posY1 = iVisibleHeight * 0.5f;
    18.         posY2 = -iVisibleHeight * 0.5f;
    19.     }
    20.     m_bg1->setPositionY(posY1);
    21.     m_bg2->setPositionY(posY2);
    22. }
     

    原理我就不解释了。大家看看代码凝视。然后自己在纸上画一画,非常好理解的。反正目的就是让两张背景不断往上移动。一旦图片全然离开屏幕,就让它回到屏幕下方,然后又继续往上移动。

    好了,如今执行游戏,就能看到背景在滚动了~

    OK。接下来,我们已正式加入了主角。

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Django中MySQL读写分离技术
    BBS+Blog项目开发
    数据算法 --hadoop/spark数据处理技巧 --(5.移动平均 6. 数据挖掘之购物篮分析MBA)
    数据算法 --hadoop/spark数据处理技巧 --(3.左外连接 4.反转排序)
    数据算法 --hadoop/spark数据处理技巧 --(1.二次排序问题 2. TopN问题)
    mysql ---- Host '' is not allowed to connect to this MySQL server
    win 8.0.12
    Transformer 和 Transformer-XL——从基础框架理解BERT与XLNet
    Transformer 详解
    XLNet:运行机制及和Bert的异同比较
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4822009.html
Copyright © 2020-2023  润新知