如何在cocos2d里面使用动画和spritesheet 3.0 C++版

2023-11-09 23:59

本文主要是介绍如何在cocos2d里面使用动画和spritesheet 3.0 C++版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    在游戏编程中,动画可谓必不可少,今天就向大家介绍cocos2d里面如何使Sprite加载动画,同时我们利用了SpriteSheet技术来简化操作及提高效率。

    本文是基于大神子龙山人翻译的博客修改而成,但原文是基于cocos2d 2.x版本及object-c语言的,因此我将它进一步加工成了C++语言,并尽量基于cocos2d 3.0的实现版本。由于本人也是cocos2d的初学者,因此文中有任何不妥之处,尽管拍砖!

   子龙山人博客:http://www.cnblogs.com/andyque/archive/2011/04/11/2012770.html

    英文原版地址:http://www.raywenderlich.com/1271/how-to-use-animations-and-sprite-sheets-in-cocos2d

   废话少说,让我们开始吧。

什么是SpriteSheet

      SpriteSheet,翻译为“精灵表单”。好吧,这个翻译也许并不那么直白。SpriteSheet的定义,见原文翻译:

      “如果你从来没有使用过spritesheet,你可以把它看作是一张巨大的图片,你可以把许许多多的sprite放进去。与spritesheet对应的,还有一个plist文件,这个文件指定了每个独立的sprite在这张“大图”里面的位置和大小,当你在代码之间需要使用这个sprite的时候,就可以很方面地使用plist文件中的这些信息来获取sprite。”

    SpriteSheet能够方便的帮我们管理众多Sprite,比如,你的游戏人物有一个射击的动作,你将射击分解为了4个帧的画面,每个画面,你可能都要创建一个精灵并依次渲染它们,这样,共渲染4次。而SpriteSheet却将4帧画面整合为一个SpriteSheet,当你需要显示连续的射击动画时,这4个画面会被当做一个大的SpriteSheet画面渲染1次!你需要做的仅是将存储在SpriteSheet中的帧画面取出并组成Action,并让你的Sprite来run这个action。感觉出来了吗,没有SpriteSheet,你需要渲染4次Sprite画面,而现在你只要渲染一次,大大提高了效率!原文解释如下。

    “为什么这会提高效率呢?因为cocos2d对它进行了优化!如果你使用spritesheet来获取sprite,那么当场景中有许多sprite的时候,如果这些sprite共享一个spritesheet,那么cocos2d就会使用一次OpenGL ES调用来渲染这些sprite。但是,如果是单个的sprite的话,那么就会有N次OpenGL ES call,这个代价是相当昂贵的”

如何运用SpriteSheet

    好了,既然SpriteSheet这么牛逼,那么我们具体应该如何使用它那?

    首先,SpriteSheet作为cocos2d的一种技术,需要有特殊的资源文件配合其实现。什么特殊资源文件呢,两部分:

    1、整合了所有帧画面的大png图片。大png图片如下所示,包含了熊散步动画的所有帧画面。

    2、描述大png图片信息的plist文件(plist文件包含描述信息,里面包含了图片在spritesheet中的位置、大小和名字等信息)。

    

    

    那我们怎么获取这两个文件呢,我们有工具 Zwoptex!

    工具不知怎么上传不到云盘,是mac版的,有需要可以留邮箱发送。

    具体怎么使用工具?看原文博客,有详细说明。但原文软件版本和我的版本并不一致,操作上略有不同。具体细节大家自己摸索咯(偷个懒)。

    OK,有了资源文件,我们就可以新建工程,来让我们的熊出来散散步吧~

    顺便介绍一下我的开发环境

    Xcode5-DP  and cocos2d-x-3.0beta2.

简单动画

    让我们先创建一个叫做WalkBear的cocos2d工程(具体创建方法可询问度娘或现在正关小黑屋的谷哥)。

    在HelloWorldScene.h 里面添加如下属性。

   

    CC_SYNTHESIZE_RETAIN(cocos2d::Sprite*, _bear, BearSprite);CC_SYNTHESIZE_RETAIN(cocos2d::Action*, _walkAction, WalkAction);CC_SYNTHESIZE_RETAIN(cocos2d::Action*, _moveAction, MoveAction);

        好了,这下我们有个了三个private属性了,分别为cocos2d::Sprite*类型的_bear(熊精灵) cocos2d::Action*类型的_walkAction(熊走路动画)、_moveAction(熊移动动作)。并分别定义了它们的get和set方法。

    啥?没看懂上面是什么意思?别忘了,cocos2d可是开源的,让我们一起看看CC_SYNTHESIZE_RETAIN宏定义(cocos2d的注释写的很详细,有不明白的地方可以直接看源码、注释)。

#define CC_SYNTHESIZE_RETAIN(varType, varName, funName)    \
private: varType varName; \
public: virtual varType get##funName(void) const { return varName; } \
public: virtual void set##funName(varType var)   \
{ \if (varName != var) \{ \CC_SAFE_RETAIN(var); \CC_SAFE_RELEASE(varName); \varName = var; \} \
} 

   这下明白了吧,其实我们运用宏   

CC_SYNTHESIZE_RETAIN(cocos2d::Sprite*, _bear, BearSprite);

   相当于写了如下一堆代码,

private: cocos2d::Sprite*  _bear;
public: virtual cocos2d::Sprite* getBearSprite(void) const { return _bear; } 
public: virtual void setBearSprite(cocos2d::Sprite* var) 
{ if (_bear != var)   // 注意,这里只有当原值与新值不相等时,才会赋值{ CC_SAFE_RETAIN(var); CC_SAFE_RELEASE(_bear); _bear = var; } 
} 

    好,那位看官又有问题了,那为啥不用宏CC_SYNTHESIZE,而用CC_SYNTHESIZE_RETAIN呢?这个…… 说实话,我也不是很清楚。(莫喷,毕竟我也是初学者啊)

    我的感觉是加上RETAIN(汉语为”保留“)表示告诉cocos2d的内存处理机制,这个对象是属于我的,你cocos2d在自动清理空闲内存的时候,别给我自动清了,哥留着有用。如果不加上retain,可能会导致cocos2d自动将你生成的对象认为没有用了而清理掉。这样你再想用它的时候,可就找不回来了。当然,这是我个人浅薄的理解半猜性质,希望能有大神进一步解释。

     在HelloWorld的构造函数里,我们初始化这三个变量为空指针。(nullptr是C++11标准中代替NULL的,记得加入头文件memory.h)

HelloWorld():_bear(nullptr), _walkAction(nullptr), _moveAction(nullptr), _walking(false){}

     好了,我们的演员(_bear)、剧本(_walkAction、_moveAction,当然现在时“空剧本”),都到位了,就让我们的熊动起来吧!

初级阶段 简单的动画

    在初级阶段,我们要实现熊的走路动画,当然,是向着一个方向傻傻的走,在高级点阶段里面,我们将实现触屏来指引熊移动方向的功能。

    在初级阶段里面,我们在init()方法里面添加代码。共分为5个步骤。

1)缓冲sprite帧和纹理

   SpriteFrameCache* shareSpriteBearFrameChache = SpriteFrameCache::getInstance();shareSpriteBearFrameChache->addSpriteFramesWithFile(“AnimBear.plist”);

在上面的代码里面,我们建立了一个SpriteFrameCache对象实例,同时,调用了其addSpriteFramesWithFile方法。该方法完成两件事情:

(1)寻找工程目录下面和输入的参数名字一样,但是后缀是.png的图片文件。然后把这个文件加入到共享的TextureCache中。(这我们这个例子中,就是加载AnimBear.png)

(2)解析plist文件,追踪所有的sprite在spritesheet中的位置,内部使用SpriteFrame对象来追踪这些信息


2) 创建一个精灵批处理结点

 SpriteBatchNode* spriteSheet = SpriteBatchNode::create("AnimBear.png");this->addChild(spriteSheet);

精灵批处理节点的说明,请看原文,其中的2.0的类名称,各位看官可自行对比。

  “接下来,创建CCSpriteBatchNode对象,把spritesheet当作参数传进去。spritesheet在cocos2d中的工作原理如下:

你创建一个CCSpriteBatchNode对象,通过传递一个包含所有sprite的spritesheet的名字作为参数,并把它加入到当前场景之中。

接下来,你从spritesheet中创建的任何sprite,你应该把它当作CCSpriteBatchNode的一个孩子加进去。只要sprite包含在spritesheet中,那么就没问题,否则会出错。

CCSpriteBatchNode可以智能地遍历它的所有的孩子结点,并通过一次OpenGL ES call来渲染这些孩子,而不是以前每个sprite都需要一个OpenGL call,这样渲染速度就会更快。

3) 收集帧列表

cocos2d::Vector<cocos2d::SpriteFrame*> walkAniFrams;for (int i = 1; i <=8; i++) {std::ostringstream os;os << "bear" << i << ".png";std::string strFrameNmae = os.str();walkAniFrams.pushBack(shareSpriteBearFrameChache->getSpriteFrameByName(strFrameNmae));}

    这里我们用一个循环,将之前存储在SpriteFrameCache中的动画帧都取出来,放在了一个vector容器里面。记住,它们已经在缓存里了,因为我们前面调用了addSpriteFramesWithFile方法。

4) 创建动画对象

Animation* walkAnim = Animation::createWithSpriteFrames(walkAniFrams, 0.1);

简单,只有一句话,我们将上一步存储动画帧的vector当做参数传进去,并指定了动画帧之间的播放间隔0.1秒(单位是秒吧)


5) 创建sprite并且让它run动画action

  创建精灵并显示

 _bear = Sprite::createWithSpriteFrameName("bear1.png");_bear->setPosition(Point(visibleSize.width/2, visibleSize.height/2));_walkAction = RepeatForever::create(Animate::create(walkAnim));_walkAction->retain();_bear->runAction(_walkAction);spriteSheet->addChild(_bear);

     在上面的代码里,我们首先创建了一个精灵对象。注意,我们这里创建精灵的方法,并没有使用creata方法,而是用了createWithSpriteFrameName。对于该方法,cocos2d里面是这样说明的

/*** Creates a sprite with an sprite frame name.** A SpriteFrame will be fetched from the SpriteFrameCache by spriteFrameName param.* If the SpriteFrame doesn't exist it will raise an exception.** @param   spriteFrameName A null terminated string which indicates the sprite frame name.* @return  A valid sprite object that is marked as autoreleased.*/

    这里就是说,我们用spriteframe当做初始化模板,创建了一个精灵。而这个当做模板的spriteframe,必须是已经存在于SpriteFrameCache中的。而这个SpriteFrameCache,就是我们之前在第一步中创建的shareSpriteBearFrameChache,它存储了关于熊的spritefame。

    创建好sprite对象之后,我们接着又创建了一个让熊表演的action对象,同时让熊精灵来run这个action。

    注意,在最后一步,我们把熊加个场景中—把它当作spritesheet的孩子加到spritesheet中去。注意,如果在这里我们没有把它加到spritsheet中,而是加到当前层里面的话。那么我们将得不到spritesheet为我们带来的性能提升!!!

     OK!编译运行吧,一只熊就在你手机上运行了!

高级阶段 让熊按照你的旨意行动

(待续)

源代码 http://pan.baidu.com/s/1mg8zV40


















这篇关于如何在cocos2d里面使用动画和spritesheet 3.0 C++版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/379229

相关文章

使用Dify访问mysql数据库详细代码示例

《使用Dify访问mysql数据库详细代码示例》:本文主要介绍使用Dify访问mysql数据库的相关资料,并详细讲解了如何在本地搭建数据库访问服务,使用ngrok暴露到公网,并创建知识库、数据库访... 1、在本地搭建数据库访问的服务,并使用ngrok暴露到公网。#sql_tools.pyfrom

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

Spring Cloud之注册中心Nacos的使用详解

《SpringCloud之注册中心Nacos的使用详解》本文介绍SpringCloudAlibaba中的Nacos组件,对比了Nacos与Eureka的区别,展示了如何在项目中引入SpringClo... 目录Naacos服务注册/服务发现引⼊Spring Cloud Alibaba依赖引入Naco编程s依

Java springBoot初步使用websocket的代码示例

《JavaspringBoot初步使用websocket的代码示例》:本文主要介绍JavaspringBoot初步使用websocket的相关资料,WebSocket是一种实现实时双向通信的协... 目录一、什么是websocket二、依赖坐标地址1.springBoot父级依赖2.springBoot依赖

Java使用Mail构建邮件功能的完整指南

《Java使用Mail构建邮件功能的完整指南》JavaMailAPI是一个功能强大的工具,它可以帮助开发者轻松实现邮件的发送与接收功能,本文将介绍如何使用JavaMail发送和接收邮件,希望对大家有所... 目录1、简述2、主要特点3、发送样例3.1 发送纯文本邮件3.2 发送 html 邮件3.3 发送带

Win32下C++实现快速获取硬盘分区信息

《Win32下C++实现快速获取硬盘分区信息》这篇文章主要为大家详细介绍了Win32下C++如何实现快速获取硬盘分区信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实现代码CDiskDriveUtils.h#pragma once #include <wtypesbase

使用DeepSeek搭建个人知识库(在笔记本电脑上)

《使用DeepSeek搭建个人知识库(在笔记本电脑上)》本文介绍了如何在笔记本电脑上使用DeepSeek和开源工具搭建个人知识库,通过安装DeepSeek和RAGFlow,并使用CherryStudi... 目录部署环境软件清单安装DeepSeek安装Cherry Studio安装RAGFlow设置知识库总

Python FastAPI入门安装使用

《PythonFastAPI入门安装使用》FastAPI是一个现代、快速的PythonWeb框架,用于构建API,它基于Python3.6+的类型提示特性,使得代码更加简洁且易于绶护,这篇文章主要介... 目录第一节:FastAPI入门一、FastAPI框架介绍什么是ASGI服务(WSGI)二、FastAP

Spring-AOP-ProceedingJoinPoint的使用详解

《Spring-AOP-ProceedingJoinPoint的使用详解》:本文主要介绍Spring-AOP-ProceedingJoinPoint的使用方式,具有很好的参考价值,希望对大家有所帮... 目录ProceedingJoinPoijsnt简介获取环绕通知方法的相关信息1.proceed()2.g

Maven pom.xml文件中build,plugin标签的使用小结

《Mavenpom.xml文件中build,plugin标签的使用小结》本文主要介绍了Mavenpom.xml文件中build,plugin标签的使用小结,文中通过示例代码介绍的非常详细,对大家的学... 目录<build> 标签Plugins插件<build> 标签<build> 标签是 pom.XML