Cocos2d-iphone 新版最佳实践 (cocos2d Best Practices)

2024-06-10 12:18

本文主要是介绍Cocos2d-iphone 新版最佳实践 (cocos2d Best Practices),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自:http://www.cocos2dchina.com/archives/229

提高性能(Improving performance)

使用此指南作为参考:性能测试(performance tests)

Xcode Thumb

针对ARMv6需关闭XCode的Thumb编译,但是对于ARMv7可以打开。

  • Thumb编译使用最小的汇编大小,在浮点运算的时候可能出现比较大的误差
  • Thumb代码比非Thumb代码慢得多。
  • 更改此项目的设置 在这里可以找到

CCDirector

Director:

  • 使用DisplayLink, DisplayLink是最佳的Director,但只适用于SDK 3.1或更高版本。如果DisplayLink的是不存在的,使用MainLoop或ThreadMainLoop。
      // must be called before any other call to the director// 必须先调用它。才能使用其他的Directorif( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )[CCDirector setDirectorType:kCCDirectorTypeMainLoop];
    
  • 或者使用NSTimer CCDirector,其最低的时间间隔是1/240(最快的帧频)
      // If you are using "NSTimer" Director you could set a very low interval// 如果您正在使用的是"NSTimer"Director,可以设置一个非常低的时间间隔[[CCDirector sharedDirector] setAnimationInterval:1/240.0];
    

纹理地图集(Texture Atlas)

在可能的情况下,尽量使用纹理地图集:

  • 使用CCSpriteFrameCache或者使用CCTextureCache获取CCSprite对象的纹理。
  • 使用CCSpriteBatchNode创建批量CCSprite对象
  • 使用CCLabelBMFont或CCLabelAtlas,而不是CCLabelTTF
  • 使用CCTMXTileMap或CCTileMapAtlas呈现tiles

这些Atlas版本对象,通过现有的技术以及牺牲代码的复杂性为代价,换取更快的渲染效果。
Atlas版本使用AtlasManager保存一个很大的图片在多个Frame里面,各个Atlas对象引用一个帧的大图。这样可以节省的纹理数量和加速了OpenGL ES的调用。

地图集 = 一本书的插图或者图表。在这种情况下,意味你只需要将一张大图像加载到OpenGL纹理,就可以拥有一系列较小的图像。而不是所有小图像各自加载到自己的纹理。

纹理(Textures)

在可能的情况下,尽量使用4位或16位的纹理

  • 16位的纹理,使用PNG/GIF/BMP/TIFF图像
  • 4位或2位的纹理:尽量使用PVRTC纹理。
  • 32位的纹理,在没有办法时使用

加载纹理时,加入这行在前面,设置纹理的格式:

[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444];

作为背景图片,可以删除Alpha通道,使用RGB565格式。该格式具有更好视觉品质,优于RGBA4444。

提示:
仅仅简单的通过设置像素格式来减少颜色不利于材质的质量而且资源本身的大小依旧会很大

抖动 需要处理,网上没有发现好的解释

PVR纹理 压缩了图像,GPU支持的格式,更多好处请google。

PVR格式可以创建RGBA8888,RGBA4444,RGBA5551和RGB565纹理

使用PVR精灵的方法:

CCSprite *sprite = [CCSprite spriteWithFile: @"sprite.pvr"];

粒子(Particles)

有2种类型的粒子:Quad和Point粒子系统。Point粒子系统似乎在1、2代设备上要快一点,但是第三代设备和ipad上要慢得多。

所以最好在设备上运行检查一下,或者最懒的做法使用Quad粒子。

优化内存(Reducing Memory)

  • 使用16位或者4位的纹理(请参阅提高性能 Improving performance)
  • 使用 CCTextureCache
    • CCTextureCache缓存所有图像
    • 即使图像已不再使用,它将保留在内存
    • 将其从内存中删除

方法:

// textures with retain count 1 will be removed
// you can add this line in your scene#dealloc method
[[CCTextureCache sharedTextureCache] removeUnusedTextures]; // since v0.8// removes a certain texture from the cache
CCTexture2D *texture = [sprite texture];
[[CCTextureCache sharedTextureCache] removeTexture: texture]]; // available in v0.7 too// removes all textures... only use when you receive a memory warning signal
[[CCTextureCache sharedTextureCache] removeAllTextures];    // available in v0.7 too

定时器(Timers)

  • 尽量不要使用Cocoa的NSTimer,相反使用cocos2d的自己的调度。
  • 如果使用Cocos2d调度,将拥有以下功能:
    • 自动暂停/恢复
    • CCLayer(CCScene,CCSprite,CCNode)进入舞台时,定时器将被自动激活,离开舞台时,它会自动停用。
    • target/selector 会传入一个时间差

/**********************************************************/
// OK OK OK OK OK
/**********************************************************/
-(id) init
{if( (self=[super init] ) ) {// schedule a callback[self scheduleUpdate];  // available since v0.99.3[self schedule: @selector(tick2:) interval:0.5];}return self;
}-(void) update: (ccTime) dt
{// bla bla bla
}-(void) tick2: (ccTime) dt
{// bla bla bla
}/**********************************************************/
// BAD BAD BAD BAD
/**********************************************************/
// Why BAD ?
// You can't pause the game automatically.
-(void) onEnter
{[super onEnter];timer1 = [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(tick1) userInfo:nil repeats:YES];timer2 = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(tick2) userInfo:nil repeats:YES];
}
-(void) onExit
{[timer1 invalidate];[timer2 invalidate];[super onExit];
}
-(void) tick
{// bla bla bla
}-(void) tick2
{// bla bla bla
}

绘制vs更新

  • 在绘画方法中,尽量不要更新任何状态变量。
  • 在scheduled方法中,尽量不要绘画任何东西。
  • 在scheduled方法中,更新的状态变量。
  • 在绘画方法中,绘制东西。
  • 如果在绘画方法中更新状态变量,暂停/恢复不会按预期方式工作。
  • 如果在scheduled方法中绘画东西,它将不会变换。
  • scheduled可以指定任何的帧速率,但是最多不能超过应用程序的FPS速率。

/**********************************************************/
// OK OK OK OK OK
/**********************************************************/
-(void) draw
{[item draw];    // OK: DRAW INSIDE DRAW
}
-(void) update:(ccTime) dt
{item.position = dt * finalPosition; // OK, UPDATE STATE IN SCHEDULED SELECTOR
}/**********************************************************/
// BAD BAD BAD BAD 1
/**********************************************************/
-(void) draw
{dt = [self calculateDelta];         // DONT UPDATE STATE IN DRAW.item.position = dt * finalPosition; // Pause won't work[item draw];
}/**********************************************************/
// BAD BAD BAD BAD 2
/**********************************************************/
-(void) update:(ccTime) dt
{item.position = dt * finalPosition;[item draw];            // <--- DON'T DRAW IN SCHEDULED SELECTOR// because transformations won't alter your image
}

Director流程控制(Director flow control)

  • 如果可能的话尽量使用replaceScene而不是使用pushScene
  • pushScene很方便,但是它把旧场景缓存在内存中,在iphone里内存资源是非常稀缺。所以多多思索……

// TRY TO AVOID A BIG STACK OF PUSHED SCENES
-(void) mainMenu()
{// etc[[CCDirector sharedDirector] pushScene: gameScene];
}
// stack:
//   . game  <-- running scene
//   . mainMenu-(void) game
{[[CCDirector sharedDirector] pushScene: gameOverScene];
}
// stack:
//   . gameOver  <-- running scene
//   . game
//   . mainMenu-(void) showGameOver
{[[CCDirector sharedDirector] pushScene: hiScoreScene];
}
// stack:
//   . scores  <-- running scene (4 pushed scenes... expensive)
//   . gameOver
//   . game
//   . mainMenu

创建节点(Creating Nodes ) (CCSprite, CCLabel等等)

在可能的情况下,尽量在init方法中创建CCNode对象(CCSprite,CCLabel,CCLayer等。)或任何其他类型的对象,而不是在绘画方法或者其他的scheduled方法中创建。
创建节点需要非常开销,所以尽量让他们预先创建。
另一方面,需要注意内存的使用。不要让没有意义的对象在内存中。

/**********************************************************/
// OK, MOST OF THE TIME
/**********************************************************/
-(id) init
{// etc...sprite1 = [CCSprite create];     // <-- USUALLY IT IS BETTER TO CREATE OBJECTS IN INIT// etc...
}-(void) tick: (ccTime) dt
{// etc...if( someThing ) {[sprite1 show];         // <--- BUT IF YOU DON'T USE THEM FREQUENTLY, MEMORY IS WASTED}
}/**********************************************************/
// BAD, MOST OF THE TIME
/**********************************************************/
-(void) tick: (ccTime) dt
{// etc...if( someThing ) {sprite = [CCSprite create];      // <--- EXPENSIVE[sprite1 show];//...[sprite1 release];      // <-- AT LEAST MEMORY IS RELEASED}}

图层的层次结构(Hierarchy of Layers)

  • 不要创建一个很大的图层层次结构。尽量可能保持小的层次结构。

动作(ACtions)

  • 创建某些动作代价十分昂贵,因为它可能需要大量的malloc()。
    例如:一个只有CCSpawn和CCRotateBy的CCSequence,而在其内部还创建另外一个CCSequence做衔接等等,这些都是非常高的开销。
  • 因此尽量尝试重用动作。
  • 一旦使用这个动作,并且知道将来还会使用这种类型的动作,请保存它。再次使用的时候,只需初始化就可以使用,而非重新创建一个新的动作。

2010.09.26 困惑,因为大多数的Objective-C类并不指望他们的init()方法在已经初始化的对象中被再次调用。这将使一些CCAction的子类无法工作。CCIntervalAction就是一个例子,如果你二次调用CCSequence的InitOne方法将导致内存泄漏。等等…我认为必须写一个setActionOne:andTwo:方法让CCSequence可以重复使用或者编写一个类释放先前的动作,然后在保留新的。因此我不相信“只需初始化就可以使用” 的意见是好的或者完全够用的,如果有一些其他类型的需重新初始化才工作。

按钮(Buttons)

这不是一个好做法,但是是一个提示:

  • 使用MenuItemImage的菜单或者使用menu.position = ccp(x,y)放置菜单。有关更多详细信息,请参阅MenuTest。

如何暂停/恢复工程?(How does the pause/resume works ?)

这不是一个最佳的实践。

  • 当Director收到暂停消息时,它不会调用任何的预定target/selector.
  • 但是绘画方法会以4FPS的帧频调用(为了减低电池消耗)
  • 当Director收到恢复的消息,预定的target/selector会再次调用。

这篇关于Cocos2d-iphone 新版最佳实践 (cocos2d Best Practices)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

Prometheus与Grafana在DevOps中的应用与最佳实践

Prometheus 与 Grafana 在 DevOps 中的应用与最佳实践 随着 DevOps 文化和实践的普及,监控和可视化工具已成为 DevOps 工具链中不可或缺的部分。Prometheus 和 Grafana 是其中最受欢迎的开源监控解决方案之一,它们的结合能够为系统和应用程序提供全面的监控、告警和可视化展示。本篇文章将详细探讨 Prometheus 和 Grafana 在 DevO

springboot整合swagger2之最佳实践

来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。 一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。 SpringBoot集成 pom <!--swagge

vue2实践:el-table实现由用户自己控制行数的动态表格

需求 项目中需要提供一个动态表单,如图: 当我点击添加时,便添加一行;点击右边的删除时,便删除这一行。 至少要有一行数据,但是没有上限。 思路 这种每一行的数据固定,但是不定行数的,很容易想到使用el-table来实现,它可以循环读取:data所绑定的数组,来生成行数据,不同的是: 1、table里面的每一个cell,需要放置一个input来支持用户编辑。 2、最后一列放置两个b

【HarmonyOS】-TaskPool和Worker的对比实践

ArkTS提供了TaskPool与Worker两种多线程并发方案,下面我们将从其工作原理、使用效果对比两种方案的差异,进而选择适用于ArkTS图片编辑场景的并发方案。 TaskPool与Worker工作原理 TaskPool与Worker两种多线程并发能力均是基于 Actor并发模型实现的。Worker主、子线程通过收发消息进行通信;TaskPool基于Worker做了更多场景化的功能封装,例

vue2实践:第一个非正规的自定义组件-动态表单对话框

前言 vue一个很重要的概念就是组件,作为一个没有经历过前几代前端开发的我来说,不太能理解它所带来的“进步”,但是,将它与后端c++、java类比,我感觉,组件就像是这些语言中的类和对象的概念,通过封装好的组件(类),可以通过挂载的方式,非常方便的调用其提供的功能,而不必重新写一遍实现逻辑。 我们常用的element UI就是由饿了么所提供的组件库,但是在项目开发中,我们可能还需要额外地定义一

《C++中的移动构造函数与移动赋值运算符:解锁高效编程的最佳实践》

在 C++的编程世界中,移动构造函数和移动赋值运算符是提升程序性能和效率的重要工具。理解并正确运用它们,可以让我们的代码更加高效、简洁和优雅。 一、引言 随着现代软件系统的日益复杂和对性能要求的不断提高,C++程序员需要不断探索新的技术和方法来优化代码。移动构造函数和移动赋值运算符的出现,为解决资源管理和性能优化问题提供了有力的手段。它们允许我们在不进行不必要的复制操作的情况下,高效地转移资源

Vue3+elementplus实现图片上传下载(最强实践)

图片上传子组件: 实现照片的上传,预览,以及转成以逗号隔开的图片地址,即时监听,并发送消息到父组件。 <!-- ImageUploader.vue --> <template><div><el-upload class="avatar-uploader" :http-request="customUpload" :before-upload="beforeUpload":show-fil