怪物在地图上的位置是不变的,但它们都有对应的原地站立时的动画。大家可能想到使用前面创建的动画管理器来创建动画模板,然后播放各个怪物精灵的动画。这样做没错,但是想想就觉得麻烦:如果有100种怪物的话,难道要定义100个动画模板吗?答案是否定的。那么该如何实现怪物原地站立的动画呢?从提供的怪物图片素材可以发现:每个怪物的动作由4帧动画组成,且每帧尺寸一致,都正好是一个图块的大小。是否可以定时地更新怪物对应的图块,从而产生动画的效果?结论是可以。cocos2d-x工程下test项目中的TMXReadWriteTest例子演示了如何动态改变TileMap上的图块,以及用定时器不停地重复更新图块的工作。关键代码如下:

//创建定时器,反复更新图块
schedule(schedule_selector(TMXReadWriteTest::repaintWithGID), 2.0f);void TMXReadWriteTest::repaintWithGID(float dt)
{//获取TileMap地图对象CCTMXTiledMap* map = (CCTMXTiledMap*)getChildByTag(kTagTileMap);//获取第0层CCTMXLayer *layer = (CCTMXLayer*)map->getChildByTag(0);CCSize s = layer->getLayerSize();//遍历一行for( int x=0; x<s.width;x++) {//倒数第二行int y = (int)s.height-1;//获取指定位置当前的图块IDunsigned int tmpgid = layer->tileGIDAt( ccp((float)x, (float)y) );//更新指定位置的图块IDlayer->setTileGID(tmpgid+1, ccp((float)x, (float)y));}
}

明白了上面的代码我们就对实现怪物动画有清晰的思路了:创建一个定时器,在定时器中遍历所有怪物,令其图块ID加一,如果动画完成,则将图块ID置回初始的数值。

下面请大家思考一下如何遍历所有怪物呢?由于遍历方法需要在定时器中调用,就必须尽可能优化其速度。TestCpp中的例子使用了二维数组的遍历。但设想一下,如果地图很大,遍历起来会很耗时。另外,怪物的分布是稀疏的,二维数组中的大部分元素都有可能为空。所以直接在定时器中遍历地图上的每个格子是不明智的。

那么我们可以在地图初始化完毕后,先做一个预处理:将每个怪物的方位,初始时的图块ID存放到一个数组中。然后在定时器中遍历这个数组就可以了。

首先创建一个Enemy类,用于存放怪物的方位和初始的图块ID,将来还会存放怪物的属性等信息:

#ifndef __ENEMY_H__
#define __ENEMY_H__#include "cocos2d.h"using namespace cocos2d;class Enemy:public CCObject
{
public:Enemy(void);~Enemy(void);//怪物在TileMap上的方位CCPoint position;//怪物的图块IDint startGID;
};#endif

然后修改GameMap的初始化方法,遍历TileMap上的所有怪物,生成Enemy对象,添加到一个CCArray中。随后启动一个定时器,每隔0.2s更新一次怪物动画。首先在GameMap.h里面声明一个变量,即怪物层,添加代码“CC_PROPERTY_READONLY(CCTMXLayer*,enemyLayer,EnemyLayer);”,然后在“protected:”下面添加需要用到的数组和方法,代码如下:

//Enemy数组
CCArray* enemyArray;//更新怪物图块
void updateEnemyAnimation(float dt);

接下来在GameMap.cpp文件里面实现怪物层的getter方法:

//返回怪物层
CCTMXLayer *GameMap::getEnemyLayer()
{return enemyLayer;
}

现在我们可以修改初始化方法了,修改后的代码如下:

//TiledMap额外的初始化方法
void GameMap::extraInit()
{//开启各个图层的纹理抗锯齿enableAnitiAliasForEachLayer();//初始化地板层和墙壁层对象floorLayer=this->layerNamed("floor");wallLayer=this->layerNamed("wall");//获取怪物层enemyLayer=this->layerNamed("enemy");CCSize s=enemyLayer->getLayerSize();enemyArray=CCArray::create();//遍历enemy层,将存在的怪物保存到数组中for(int x=0;x<s.width;x++){for(int y=0;y<s.height;y++){int gid=enemyLayer->tileGIDAt(ccp(x,y));if(gid!=0){Enemy* enemy=new Enemy();//保存怪物坐标enemy->position=ccp(x,y);//保存怪物起始的图块IDenemy->startGID=gid;//添加怪物对象到数组enemyArray->addObject(enemy);}}}//别忘了retain()enemyArray->retain();//用于更新敌人动画schedule(schedule_selector(GameMap::updateEnemyAnimation),0.2f);
}

在updateEnemyAnimation中,需要遍历enemyArray,并计算下一帧对应的图块ID,具体代码如下:

//更新怪物的图块
void GameMap::updateEnemyAnimation(float dt)
{//遍历保存所有怪物对象的数组CCObject* pObject;Enemy* enemy;CCARRAY_FOREACH(enemyArray,pObject){enemy=(Enemy*)pObject;if(enemy!=NULL){//获取怪物当前的图块IDint gid=enemyLayer->tileGIDAt(enemy->position);gid++;//如果结束,设置为起始图块IDif(gid-enemy->startGID>3){gid=enemy->startGID;}//给怪物设置新的图块enemyLayer->setTileGID(gid,enemy->position);}else{break;}}
}

还有,别忘了写Enemy.cpp文件,它要对.h里面声明的构造函数和析构函数进行实现,代码如下:

#include "Enemy.h"Enemy::Enemy(void)
{
}Enemy::~Enemy(void)
{
}

现在我们编译运行,发现地图上的怪物们都动起来了。注意,在GameMap的析构方法里要释放enemyArray和定时器:

//析构函数
GameMap::~GameMap(void)
{this->unscheduleAllSelectors();enemyArray->release();
}

改写《魔塔》后篇02:添加怪物动画相关推荐

  1. 改写《魔塔》后篇01:在地图上绘制怪物

    目前我们的勇士只能在空旷的地图上来回乱转,既不能与怪物进行战斗,也无法拾取物品,也不能和NPC对话等.这一篇的目的就是向游戏内添加更多的元素,丰富游戏内容,增加可玩性. 魔塔的地图上充满了强弱不一的怪 ...

  2. unity人物旋转移动代码_游戏诞生之日02 - 美术篇 快速制作人物动画

    在上一篇<游戏诞生之日01 - 美术篇 快速搭建和渲染游戏的第一个场景>里,我们得到了一个静态渲染的游戏场景. 接下来我们需要加入人物动画,为游戏注入活力. 第五块拼图 - 动画素材从哪里 ...

  3. 【翻译】西川善司的「实验做出的游戏图形」「GUILTY GEAR Xrd -SIGN-」中实现的「纯卡通动画的实时3D图形」的秘密,后篇...

    http://www.4gamer.net/games/216/G021678/20140714079/ 连载第2回的本回,  Arc System Works开发的格斗游戏「GUILTY GEAR ...

  4. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不 通.如果大家开发的是WinForm中的事件,之前的定义可能没有什 ...

  5. Android添加item动画,RecyclerView基础篇-Item添加动画

    Android_Banner.jpg 简介 本节中我们介绍下给RecyclerView中的Item添加动画. 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画 和打开列表滑动时 ...

  6. android长按加入购物车,《Android APP可能有的东西》之UI篇:加入购物车动画

    很多电商app的加入购物车的动作会要求加上动画效果:飞进购物车,想来也合理,在listview界面时商品快速加入购物车,一直toast用户加入成功好像不太正常,所以添加一个动画,用户自然就懂了,而且也 ...

  7. python深浅拷贝 面试_Python面试宝典之基础篇-02

    原标题:Python面试宝典之基础篇-02 我觉得你如果正在找工作,我的Python面试宝典几期教程,你一定得花时间看完了! 题目006:说说Python中的浅拷贝和深拷贝. 点评:这个题目本身出现的 ...

  8. 【Agni-s Philosophy】使用的图形技术解说(后篇)Volume渲染和粒子处理

    在2012年11月举办的[SQUARE ENIX 开放会议 2012]的第2天,进行了新世代游戏引擎[Luminous Studio]制作的实时技术演示作品[Agni's Philosophy]中使用 ...

  9. 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——02

    本系列相关链接 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇--01 (20210103-20210110) https://blog.csdn.net/wei198621/article/de ...

最新文章

  1. Eclipse注释模板 注释快捷键
  2. 推荐给大家看的设计书
  3. 7999元大疆最新无人机,支持第一人称视角极速拍摄,网友:不是航拍,是直接起飞...
  4. oracle tax 中国税,oracle_TAX_税基础设置操作手册.doc
  5. Linux 调优方案, 修改最大连接数(ulimit命令)
  6. php怎么实现md5加密,php如何进行md5加密
  7. Oracle数据库管理系统:大数据的备份
  8. http1.0 http1.1 http2 之间的区别
  9. 表必须要有主键吗_玄关隔断什么材质好?玄关隔断必须要做吗?
  10. Flutter进阶—实现动画效果(九)
  11. mysql交换分区_对MySQL交换分区的实践
  12. 通信系统仿真中的几个能量归一化问题
  13. 一粒云盘发布v3.5版本
  14. 华为服务器系统图标,服务器图标
  15. python nlpir_Python 中文分词 NLPIR 快速搭建
  16. 疫情下,嵌入式er该怎么进行职业规划,难点在哪?
  17. thinkphp5地址的获取和修改接口过程
  18. 【论文笔记_知识蒸馏_目标检测_2022】Decoupled Knowledge Distillation
  19. 驾校学员信息管理系统
  20. # 2gether 在一起 # 一份生日Party邀请函待查收

热门文章

  1. Python实现小游戏--2048
  2. Qt 如何改变图标颜色
  3. 【原创】Newlife.XCode的常见功能使用(一)查询与数据初始化
  4. Redis 4.0.11配置说明
  5. 【IEEE_Verilog-12.4】generate的用法
  6. 电子学会 2019年12月 青少年软件编程Python编程等级考试一级真题解析(选择题+判断题)
  7. Python绘制基尼系数图
  8. 基于JAVA社区留守儿童帮扶系统演示录像2020计算机毕业设计源码+数据库+lw文档+系统+部署
  9. PKUWC2019 赛前模拟赛总结
  10. Tensorflow(2.0+) 对五类医学图像进行分类