cocos2dx3.3开发FlappyBird总结十三:数字特效类

由于显示得分其实是数字精灵的组合,因此需要先设计一个存储数字精灵数列的类:

#ifndef __EngryBird__NumberSeries__
#define __EngryBird__NumberSeries__

#include "cocos2d.h"

/**
 * This class is for ScoreNumber, and it will store a list of sprite frames.
 * With it, you can load number sprite with name format and get sprite frame
 * with index.
 */
class NumberSeries : public cocos2d::Ref {
public:
  /**
   * The default constructor
   */
  NumberSeries();

  /**
   * The default destructor
   */
  ~NumberSeries();

  /**
   * The init method, will init the super init method first
   *
   * @return true if succeeded, otherwise false
   */
  virtual bool init();

  CREATE_FUNC(NumberSeries);

  /**
   * Load sprite frame with a format name
   *
   * @param format The name format, eg. "number1_%d"
   * @param base The begin index
   */
  void loadNumber(const char *foramt, int base = 0);

  /**
   * Get sprite frame with an index
   *
   * @param index The index in the _numberVector
   *
   * @return a sprite frame object
   */
  cocos2d::SpriteFrame* at(int index);

private:
  /**
   * Store number sprite frames
   */
  cocos2d::Vector<cocos2d::SpriteFrame *> _numberVector;
};

#endif /* defined(__EngryBird__NumberSeries__) */

这个类只有一个成员变量,_numberVector,存储的是一组数字精灵帧,这样就可以通过数字作为下标,直接获取对应的精灵帧。

在初始化时:

bool NumberSeries::init() {
  _numberVector = cocos2d::Vector<SpriteFrame *>(kMaxNumberCount);

  return true;
}

因此数字就是0~9这几个,所以是固定的,写成一个宏常量

下面这个方法是获取得分组合精灵,如得分为42,则把对应的精灵帧4和2加入到组合中,

void NumberSeries::loadNumber(const char *foramt, int base) {
  for (int i = base; i < kMaxNumberCount + base; ++i) {
    char name[20];
    sprintf(name, foramt, i);

    auto frame = AtlasLoader::getInstance()->getSpriteFrame(name);
    _numberVector.pushBack(frame);
  }
}

base表示从什么数字开始,这样写是因为有的精灵的名称不是从0开始的,如bird_045~bird_088,那么base就是45了

获取数字精灵帧的时候,传数字过来,就是获取对应的数字精灵帧了,

SpriteFrame* NumberSeries::at(int index) {
  if (index >= 0 && index < _numberVector.size()) {
    return _numberVector.at(index);
  }

  return NULL;
}

考虑代码的健壮性,增加了范围的判断

下面是数字特效类了,设计为全局共享类,
首先,显示的方式为居中,居左,居右,因此先设计一个枚举来表示。

/**
 * The alignment
 */
typedef enum {
  kGravityDirectionCenter = 1,
  kGravityDirectionLeft,
  kGravityDirectionRight
} GravityDirection;

看看加载得分精灵方法:

bool ScoreNumber::loadNumber(const char *name, const char *format, int base) {
  auto series = NumberSeries::create();
  series->loadNumber(format, base);

  _numberContainer.insert(name, series);

  return true;
}

这里_numberContainer是一个Map类型的容器,用于存储得分,因为游戏不断重复的话,同样的得分,就可以直接获取,而不用重复了。

下面这个方法是把数字得分转换成精灵数字,并调整方向:

Node* ScoreNumber::convert(const char *name, int number, GravityDirection direction) {
// 首先根据key,取得数字组合
  auto series = _numberContainer.at(name);
  auto zero = Sprite::createWithSpriteFrame(series->at(0));
  // 如果得分为0,直接显示
  if (number == 0) {
    zero->setAnchorPoint(Vec2(0.5, 0));

    return zero;
  }

  // seperate the number and load number sprite into the node
  // 使用node节点来容纳数字精灵
  auto node = Node::create();
  float totalWidth = 0.0f;
  while (number) {
  // 循环获取每一位数字,然后获取对应的精灵,添加到node中并计算
  // node的总宽
    int tmp = number % 10;
    auto sprite = Sprite::createWithSpriteFrame(series->at(tmp));

    totalWidth += sprite->getContentSize().width;
    node->addChild(sprite);

    number /= 10;
  }

  // set the content size of node
  node->setContentSize(Size(totalWidth, zero->getContentSize().height));

  // caculate the width of each number
  float perWidth = totalWidth / node->getChildrenCount();
  ssize_t index = 0;
  float anchorX = 0;
  bool isMinus = true;

  if (direction == kGravityDirectionCenter) {
    anchorX = 0.5f;
    index = node->getChildrenCount() / 2;
  } else if (direction == kGravityDirectionRight) {
    anchorX = 1.0f;
    index = node->getChildrenCount();
  } else if (direction == kGravityDirectionLeft) {
    anchorX = 0.0f;
    isMinus = false;
    index = 0;
  }

  // 获取显示的方式来调整精灵的位置
  for (auto child : node->getChildren()) {
    child->setAnchorPoint(Vec2(anchorX, 0));

    float posX = perWidth * (isMinus ? index-- : index++);
    child->setPositionX(posX);
  }

  return node;
}

下一步,先说明一下用到的宏

时间: 2024-11-08 21:34:31

cocos2dx3.3开发FlappyBird总结十三:数字特效类的相关文章

cocos2dx3.3开发FlappyBird总结四:资源管理类

游戏中需要全局管理很多的资源,如图片.音频文件等.下面我们设计一个骨骼资源管理类,名叫:AtlasLoader,设计为全局共享类,用于载入资源和通过资源名称获取精灵帧. 下面先上头文件: #ifndef __EngryBird__AtlasLoader__ #define __EngryBird__AtlasLoader__ #include "cocos2d.h" /** * The struct of the atlas file */ typedef struct tag_atl

cocos2dx3.3开发FlappyBird总结十二:状态层设计

状态层是比较复杂的了,状态层需要与游戏层通信,因此也需要为游戏层先设计一个代理类,以便状态层遵守游戏层的代理,这样游戏层就可以在游戏开始.得分.结束时,告诉状态层做出相应的状态表现了. 游戏层的代理类: /** * The delegate between status layer and game layer */ class GameStatusDelegate { public: /** * When the game start, this method will be called *

cocos2dx3.3开发FlappyBird总结十一:控制层功能设计

控制层的任务就是监听触摸事件,然后回调代理方法.控制层并不具体处理任务事情,只是抛给代理处理,因此需要先设计一个代理. 代理只是一个方法,那就是触摸: /** * The delegate between option layer and game layer */ class OptionDelegate { public: /** * When touch the option layer, it will be called */ virtual void onTouch() = 0; }

cocos2dx3.3开发FlappyBird总结十七:结束语

教程到此也该结束了,如果您是认真看完此教程的有缘人,相信您一定会成为本行业的精英,但是我希望大家都能有开源精神,把自己的总结,自己领悟出来的知识,共享出来,大家一起学习,少走弯路. 本人Github:https://github.com/632840804 本人QQ:632840804 本人Email:huangyibiao520@163.com 写代码不易,写教程亦不易,且写且看且珍惜!!! 写代码不易,写教程亦不易,且写且看且珍惜!!! 写代码不易,写教程亦不易,且写且看且珍惜!!! 如果遇

cocos2dx3.3开发FlappyBird总结五:说说屏幕适配

官方网站中有一篇教程,是关于适配问题的,笔者也是通过阅读后,才了解一些,希望大家好好阅读,必定受益匪浅: http://cn.cocos2d-x.org/tutorial/show?id=2360 此处笔者采用的是ResolutionPolicy::EXACT_FIT,即完全显示. 由于背景图片资源的宽高为288:512,因此这里把设计分辨率为288:512,在bool AppDelegate::applicationDidFinishLaunching()中修改相应地方: if(!glview

cocos2dx3.3开发FlappyBird总结九:欢迎场景(WelcomeScene)

欢迎场景的任务是无限滚动地面,小鸟原地挥动翅膀,显示开始游戏按钮,点击时才开始玩游戏. 先上图: 这个场景中,有一个标题:FlappyBird 一只小鸟,小鸟的颜色是随机生成三种中的一种 一个开始按钮 无限滚动的地面 在初始化时,生成当前时间来显示白天还是黑夜背景. // Get the current time, judge whether now is day or night time_t t = time(NULL); tm *localTime = localtime(&t); int

cocos2dx3.3开发FlappyBird总结七:说说游戏流程

整个游戏的执行流程是这样的: 初始载入LoadingScene: 这一步会把所有图片资源和音频资源都载入到内存中,当然这不是一种好的方式,不过这里项目较小,资源少,这种方式是可行的. 当资源载入完成时,会进入到下一步. 下一步:切换到WelcomeScene,即显示欢迎界面,用户点击玩游戏按钮,进入到GameScene,这个是游戏主场景.玩家输了以后,可以不断重玩. GameScene:主场景,由背景层.控制层.状态层和游戏层组成,背景层只是显示背景,控制层只是处理触摸事件,状态层是与游戏层交互

cocos2dx3.3开发FlappyBird总结八:载入场景LoadingScene

载入场景的目的是预加载资源,也就是在场景进入时,把资源加载到内存中: // 重写onEnter方法,场景载入时,会调用此方法,此外我们还需要调一下父类的方法,这个是API说明的,照做就行. // 方法其实功能是很简单的,就是先显示一张splash图片,然后异步加载图片资源,这个addImageAsync方法是引擎内部提供的API,可异步加载,这样就不会阻塞主线程了. void LoadingScene::onEnter() { Layer::onEnter(); // Add the splas

cocos2dx3.3开发FlappyBird总结十五:记录玩家得分

在游戏结束时,需要更新和获取最新得分. 设计一个工具类,只有类方法,这样外部就能很方便地获取和更新值. /** * This is a help class, using to operate the user information conveniencely */ class RecordTool { public: /** * Get the best score with a key, store in the UserDefault */ static int getBestScore