亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Cocos2d開發(fā)系列(五)

系統(tǒng) 2234 0

Learn IPhone and iPad Cocos2d Game Delevopment》第6章(原文中部分無關(guān)緊要的內(nèi)容沒有進(jìn)行翻譯)。

一、 CCSpriteBatchNode

在屏幕上貼圖時(shí),圖形硬件需要經(jīng)過準(zhǔn)備、渲染、清除等步驟。每次貼圖都會(huì)重復(fù)這個(gè)過程。如果圖形硬件能事先知道有一組擁有相同紋理的 Sprite需要渲染,則這個(gè)過程會(huì)被簡化。比如,一組Sprite的準(zhǔn)備和清除動(dòng)作總共只需要執(zhí)行一次。

下圖的例子使用了 CCSpriteBacthNode。屏幕上同時(shí)有幾百顆子彈飛過。如果一次只渲染一顆,那么幀率馬上降到85%。使用CCSpriteBatchNode,可以避免這種情況:

Cocos2d開發(fā)系列(五)

通常我們這樣創(chuàng)建一個(gè) CCSprite:

CCSprite* sprite=[CCSprite spriteWithFile:@”bullet.png”];

[self addChild:sprite];

而使用 CCSpriteBatchNode 則需要修改為:

CCSpriteBatchNode* batch=[CCSpriteBatchNode batchNodeWithFile:@”bullet.png”];

[self addChild:batch];

for(int i=0;i<100;i++){

CCSprite* sprite=[CCSprite spriteWithFile:@”bullet.png”];

[batch addChild:bullet];

}

注意, CCSpriteBatchNode需要一個(gè)圖片文件名作為參數(shù),哪怕它根本用不著這個(gè)圖片(進(jìn)行顯示)。可以把它看做是一個(gè)Layer,你可以用它來加入一些CCSprite節(jié)點(diǎn)。由于它使用了一個(gè)圖片文件作為構(gòu)造參數(shù),所以在后面加入的CCSprite中必須使用相同的文件作為構(gòu)造參數(shù),否則會(huì)導(dǎo)致如下錯(cuò)誤:

SpriteBatches[13879:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'CCSprite is not using the same texture id'

當(dāng)采用相同紋理的 CCSpite越多,則采用CCSpriteBatchNode的好處越明顯。

但這有一個(gè)限制,所有的 CCSprite節(jié)點(diǎn)都會(huì)位于同一個(gè)Z坐標(biāo)(深度)上。如果子彈是“擊穿”敵人并向后飛,你得使用兩個(gè)Z軸不同的CCSpriteBatchNode。

另外一個(gè)限制是, CCSpriteBatchNode和加入其中的CCSprite必須使用相同的貼圖。這一點(diǎn)在使用Texture Atlas時(shí)尤其顯得重要。一個(gè)Texture Atlas可以畫多個(gè)不同的圖片,并且這些圖片使用同一個(gè)CCSpriteBatchNode,以提高渲染速度。

Z軸的問題可以通過指定CCSpriteBatchNode中單個(gè)CCSprite的Z值來解決。如果你所有的圖片都放到了一個(gè)Texture Atlas(紋理集),則你完全可以只使用一個(gè)CCSpriteBatchNode。

CCSpriteBatchNode看成一個(gè)簡單的CCLayer,它只接受使用相同圖片的CCSprite,這樣,你就知道怎么用它了。

在下面代碼中,隱藏有一個(gè)致命的陷阱:

(id)init{

If ((self = [super initWithFile:@"ship.png"])) {

[self scheduleUpdate];

}

return self;

}

由于 -(id)init方法是默認(rèn)的初始化方法,它會(huì)被其他初始化方法比如initWithFile調(diào)用。 在-(id)init方法中調(diào)用了[super initWithFile…]方法,[super initWithFile…]會(huì)調(diào)用[super init], 該類覆蓋了-(id)init方法,于是又會(huì)調(diào)用-(id)init方法,無限循環(huán)。

解決辦法是修改方法名,比如修改為 -(id)initWithShipImage。

這個(gè)教訓(xùn)告訴我們,在默認(rèn)初始化方法 -(id)init中,除了[super init]之外,永遠(yuǎn)不要調(diào)用其他東西(其他的初始化方法)。如果你必須在初始化方法中調(diào)用[super initWith…]方法,你應(yīng)當(dāng)把方法名命名為initWith…。

二、示例代碼

1、ship類

#import <Foundation/Foundation.h>

#import "cocos2d.h"

@interface Ship : CCSprite

{

}

+( id ) ship;

@end

#import "Ship.h"

#import "Bullet.h"

#import "GameScene.h"

@interface Ship (PrivateMethods)

-( id ) initWithShipImage;

@end

@implementation Ship

+( id ) ship

{

return [[[ self alloc ] initWithShipImage ] autorelease ];

}

-( id ) initWithShipImage

{

if (( self = [ super initWithFile : @"ship.png" ]))

{

[ self scheduleUpdate ];

}

return self ;

}

-( void ) dealloc

{

[ super dealloc ];

}

-( void ) update:( ccTime )delta

{

[[ GameScene sharedGameScene ] shootBulletFromShip : self ];

}

@end

ship類很簡單,除了update方法。該方法調(diào)用了GameScene的shootBulletFromShip方法外([GameScene shareGameScene]實(shí)際上只是獲取GameScene 的單實(shí)例)。

2、GameScene類

#import <Foundation/Foundation.h>

#import "cocos2d.h"

#import "Ship.h"

typedef enum

{

GameSceneNodeTagBullet = 1 ,

GameSceneNodeTagBulletSpriteBatch ,

} GameSceneNodeTags;

@interface GameScene : CCLayer

{

int nextInactiveBullet ;

}

+( id ) scene;

+( GameScene *) sharedGameScene;

-( void ) shootBulletFromShip:( Ship *)ship;

@property ( readonly ) CCSpriteBatchNode* bulletSpriteBatch;

@end

#import "GameScene.h"

#import "Ship.h"

#import "Bullet.h"

@interface GameScene (PrivateMethods)

-( void ) countBullets:( ccTime )delta;

@end

@implementation GameScene

static GameScene* instanceOfGameScene;

+( GameScene *) sharedGameScene

{

NSAssert ( instanceOfGameScene != nil , @"GameScene instance not yet initialized!" );

return instanceOfGameScene ;

}

+( id ) scene

{

CCScene *scene = [ CCScene node ];

GameScene *layer = [ GameScene node ];

[scene addChild : layer];

return scene;

}

-( id ) init

{

if (( self = [ super init ]))

{

instanceOfGameScene = self ;

CGSize screenSize = [[ CCDirector sharedDirector ] winSize ];

CCColorLayer * colorLayer = [ CCColorLayer layerWithColor : ccc4 ( 255 , 255 , 255 , 255 )];

[ self addChild :colorLayer z :- 1 ];

CCSprite * background = [ CCSprite spriteWithFile : @"background.png" ];

background. position = CGPointMake (screenSize. width / 2 , screenSize. height / 2 );

[ self addChild :background];

Ship * ship = [ Ship ship ];

ship. position = CGPointMake (ship. texture . contentSize . width / 2 , screenSize. height / 2 );

[ self addChild :ship];

CCSpriteBatchNode * batch = [ CCSpriteBatchNode batchNodeWithFile : @"bullet.png" ];

[ self addChild :batch z : 1 tag : GameSceneNodeTagBulletSpriteBatch ];

for ( int i = 0 ; i < 400 ; i++)

{

Bullet * bullet = [ Bullet bullet ];

bullet. visible = NO ;

[batch addChild :bullet];

}

[ self schedule : @selector ( countBullets :) interval : 3 ];

}

return self ;

}

-( void ) dealloc

{

instanceOfGameScene = nil ;

// don't forget to call "super dealloc"

[ super dealloc ];

}

-( void ) countBullets:( ccTime )delta

{

CCLOG ( @"Number of active Bullets: %i" , [ self . bulletSpriteBatch . children count ]);

}

-( CCSpriteBatchNode *) bulletSpriteBatch

{

CCNode * node = [ self getChildByTag : GameSceneNodeTagBulletSpriteBatch ];

NSAssert ([node isKindOfClass :[ CCSpriteBatchNode class ]], @"not a CCSpriteBatchNode" );

return ( CCSpriteBatchNode *)node;

}

-( void ) shootBulletFromShip:( Ship *)ship

{

CCArray * bullets = [ self . bulletSpriteBatch children ];

CCNode * node = [bullets objectAtIndex : nextInactiveBullet ];

NSAssert ([node isKindOfClass :[ Bullet class ]], @"not a bullet!" );

Bullet * bullet = ( Bullet *)node;

[bullet shootBulletFromShip :ship];

nextInactiveBullet ++;

if ( nextInactiveBullet >= [bullets count ])

{

nextInactiveBullet = 0 ;

}

}

@end

現(xiàn)在你應(yīng)該看到了,在 init方法中使用CCSpriteBatchNode加入了400顆子彈(被設(shè)置為不可見了)。然后在接下來的shootBulletFromShip方法(在ship的update方法中調(diào)用)中,依次調(diào)用每一顆子彈的shootBulletFromShip方法。

3、Bullet類

#import <Foundation/Foundation.h>

#import "cocos2d.h"

#import "Ship.h"

@interface Bullet : CCSprite

{

CGPoint velocity ;

float outsideScreen ;

}

@property ( readwrite , nonatomic ) CGPoint velocity;

+( id ) bullet;

-( void ) shootBulletFromShip:( Ship *)ship;

@end

#import "Bullet.h"

@interface Bullet (PrivateMethods)

-( id ) initWithBulletImage;

@end

@implementation Bullet

@synthesize velocity;

+( id ) bullet

{

return [[[ self alloc ] initWithBulletImage ] autorelease ];

}

-( id ) initWithBulletImage

{

if (( self = [ super initWithFile : @"bullet.png" ]))

{

}

return self ;

}

-( void ) dealloc

{

[ super dealloc ];

}

// Re-Uses the bullet

-( void ) shootBulletFromShip:( Ship *)ship

{

float spread = ( CCRANDOM_0_1 () - 0.5f ) * 0.5f ;

velocity = CGPointMake ( 1 , spread);

outsideScreen = [[ CCDirector sharedDirector ] winSize ]. width ;

self . position = CGPointMake (ship. position . x + ship. contentSize . width * 0.5f , ship. position . y );

self . visible = YES ;

[ self scheduleUpdate ];

}

-( void ) update:( ccTime )delta

{

self . position = ccpAdd ( self . position , velocity );

if ( self . position . x > outsideScreen )

{

self . visible = NO ;

[ self unscheduleAllSelectors ];

}

}

@end

shootBulletFromShip方法實(shí)現(xiàn)了子彈的射擊。Spread變量計(jì)算了一個(gè)擴(kuò)散值,使從飛船中射出的子彈有1/2的機(jī)率會(huì)向上/下兩邊擴(kuò)散。Velocity是一個(gè)每幀移動(dòng)的位置偏移量。然后設(shè)置子彈的初始位置位于飛船右邊。在把子彈可視狀態(tài)設(shè)置為顯示后,調(diào)度運(yùn)行update方法(每幀調(diào)用一次)。

update方法中,讓子彈移動(dòng)velocity的偏移量。這種方式,比CCMoveXX方法效率更高一些。而且這里用了一個(gè)技巧,當(dāng)子彈飛出屏幕后,我們并沒有立即將Bullet對象清除(為了節(jié)省資源),而是子彈設(shè)置為不可視緩存起來,方便再次使用以提高程序性能。出于這個(gè)原因,我們在GameScene類中設(shè)計(jì)了一個(gè)nextInactiveBullet變量,以此來記錄已經(jīng)使用掉(射出去)的子彈(設(shè)置為可視的子彈)。等所有子彈都射出去以后,nextInactiveBullet重置為0。

三、增加角色動(dòng)畫

以下代碼為 ship對象增加角色動(dòng)畫。Ship對象的角色動(dòng)畫是5張連續(xù)的幀圖像,以表現(xiàn)飛船尾部不斷噴射并變化的火焰。

-( id ) initWithShipImage

{

if (( self = [ super initWithFile : @"ship.png" ]))

{

// 5張圖片裝入動(dòng)畫幀數(shù)組

NSMutableArray * frames = [ NSMutableArray arrayWithCapacity : 5 ];

for ( int i = 0 ; i < 5 ; i++)

{

NSString * file = [ NSString stringWithFormat : @"ship-anim%i.png" , i];

// 使用貼圖緩存構(gòu)造2D貼圖

CCTexture2D * texture = [[ CCTextureCache sharedTextureCache ] addImage :file];

CGSize texSize = texture. contentSize ;

CGRect texRect = CGRectMake ( 0 , 0 , texSize. width , texSize. height );

// 用2D貼圖構(gòu)造動(dòng)畫幀

CCSpriteFrame * frame = [ CCSpriteFrame frameWithTexture :texture rect :texRect offset : CGPointZero ];

// 把動(dòng)畫幀放入數(shù)組

[frames addObject :frame];

}

// 用動(dòng)畫幀數(shù)組構(gòu)造動(dòng)畫對象,幀率: 0.08秒/幀,標(biāo)識名:move

CCAnimation * anim = [ CCAnimation animationWithName : @"move" delay : 0.08f frames :frames];

// 如果你把 anim存儲(chǔ)到CCSprite,則可以通過名稱move來訪問CCAnimation

//[self addAnimation:anim];

// 構(gòu)造 Action:無限重復(fù)

CCAnimate * animate = [ CCAnimate actionWithAnimation :anim];

CCRepeatForever * repeat = [ CCRepeatForever actionWithAction :animate];

[ self runAction :repeat];

[ self scheduleUpdate ];

}

return self ;

}

為求簡便,上面的代碼我們也可以封裝為一個(gè)新的類別 Category。

1、類別Animation Helper

利用 OC中的Category,我們可以擴(kuò)展CCAnimation類。Category提供了一種不需要修改類的源代碼即可為類增加新方法的途徑(有點(diǎn)象AOP?),但它不能增加新的成員變量。下面的代碼為CCAnimation增加了一個(gè)Category,名為Helper(新建Class,名為CCAnimationHelper.h):

#import <Foundation/Foundation.h>

#import "cocos2d.h"

@interface CCAnimation (Helper)

+( CCAnimation *) animationWithFile:( NSString *) name frameCount:( int )frameCount delay:( float ) delay ;

+( CCAnimation *) animationWithFrame:( NSString *)frame frameCount:( int )frameCount delay:( float ) delay ;

@end

#import "CCAnimationHelper.h"

@implementation CCAnimation (Helper)

// 通過圖片文件名創(chuàng)建 CCAnimation對象 .

+( CCAnimation *) animationWithFile:( NSString *) name frameCount:( int )frameCount delay:( float ) delay

{

// 把前面的代碼移到這里來了

NSMutableArray * frames = [ NSMutableArray arrayWithCapacity :frameCount];

for ( int i = 0 ; i < frameCount; i++)

{

NSString * file = [ NSString stringWithFormat : @"%@%i.png" , name , i];

CCTexture2D * texture = [[ CCTextureCache sharedTextureCache ] addImage :file];

CGSize texSize = texture. contentSize ;

CGRect texRect = CGRectMake ( 0 , 0 , texSize. width , texSize. height );

CCSpriteFrame * frame = [ CCSpriteFrame frameWithTexture :texture rect :texRect offset : CGPointZero ];

[ frames addObject :frame];

}

return [ CCAnimation animationWithName : name delay : delay frames : frames ];

}

// 通過 sprite frames 創(chuàng)建 CCAnimation .

+( CCAnimation *) animationWithFrame:( NSString *)frame frameCount:( int )frameCount delay:( float ) delay

{

// 未實(shí)現(xiàn)

return nil ;

}

@end

現(xiàn)住,在 Ship類的初始化方法里,可以通過CCAnimation的類別Helper這樣簡單地創(chuàng)建動(dòng)畫對象了:

-( id ) initWithShipImage

{

if (( self = [ super initWithFile : @"ship.png" ]))

{

// 使用類別 Helper來創(chuàng)建動(dòng)畫對象

CCAnimation * anim = [ CCAnimation animationWithFile : @"ship-anim" frameCount : 5 delay : 0.08f ];

// 創(chuàng)建 Action:無限循環(huán)播放動(dòng)畫

CCAnimate * animate = [ CCAnimate actionWithAnimation :anim];

CCRepeatForever * repeat = [ CCRepeatForever actionWithAction :animate];

[ self runAction :repeat];

[ self scheduleUpdate ];

}

return self ;

}

四、 Texture Atlas 貼圖集(或譯作紋理集)

1、定義

貼圖集 Texture Atlas僅僅是一張大的貼圖。通過使用CCSpriteBatchNode,你可以一次性渲染所有的圖片。使用Texture Atlas不但節(jié)約了內(nèi)存也提升了性能。

貼圖的大小(寬和高)總是 2的n次方——例如1024*128或256*512。由于這個(gè)規(guī)則,貼圖尺寸有時(shí)候是大于圖片的實(shí)際尺寸的。例如,圖片大小140*600,當(dāng)加載到內(nèi)存時(shí),貼圖尺寸是256*1024。這顯然是一種內(nèi)存浪費(fèi),尤其是你有幾個(gè)這樣的單獨(dú)的Texture時(shí)。

因此有了 Texture Atlas的概念。它是一張包含了多個(gè)圖片的圖片,并且它的尺寸已經(jīng)是對齊的。所謂對齊,即是根據(jù)前面提到的那個(gè)規(guī)則,指它的長和寬都已經(jīng)是2的n次方。貼圖集每一個(gè)角色幀(sprite frame)都定義為貼圖集中的一部分(一個(gè)矩形區(qū)域)。這些角色幀的CGrect則定義在單獨(dú)的一個(gè).plist文件里。這樣cocos2d就可以從一張大的貼圖集中單獨(dú)渲染某個(gè)指定的角色幀。

2、Zwoptex

Zwoptex是一個(gè)2D貼圖工具,付費(fèi)版需要$24.95。有一個(gè)7天的試用版,下載地址 http://zwoptexapp.com 。但Zwoptex提供了一個(gè)flash版,沒有時(shí)間限制: http://zwoptexapp.com/flashwersion ,也基本夠用(僅僅有一些限制,比如2048*2048貼圖限制,角色旋轉(zhuǎn)等)。

如果你不想試用 Zwoptex,那么有一個(gè)可以替換的工具是TexturePacker:

http://texturepacker.com/

這里以 Zwoptex 0.3b7版本為例(這個(gè)是免費(fèi)版)。打開Zwoptex,默認(rèn)是一個(gè)叫做Untitled的空白畫布。選擇菜單:Sprite Sheet ——>Import Sprites,會(huì)彈出文件選擇對話框,選擇你需要的角色幀圖片文件,點(diǎn)擊import,于是所有的圖片會(huì)導(dǎo)入到Zwoptex。

選擇菜單: Sprite Sheet——>Settings,會(huì)彈出布局窗口:

Cocos2d開發(fā)系列(五)

你可以更改設(shè)置,包括畫布大小,排序規(guī)則、行間距、列間距等,目的是用最小的貼圖集容納全部所需的圖片。然后點(diǎn)擊 save去應(yīng)用。

注意,除非單獨(dú)為 3GS、iPad和iPhone4開發(fā),否則不要使用2048*2048的畫布尺寸,因?yàn)槔系男吞栕畲笾恢С?024*1024。

改變畫布大小時(shí)要當(dāng)心,因?yàn)橛袝r(shí)候圖片會(huì)疊在一起——由于空間不足。

建議不要手動(dòng)更改圖片(如移動(dòng)、旋轉(zhuǎn)),因?yàn)檫@個(gè)版本并不支持,它是自動(dòng)布局的。

Zwoptex會(huì)自動(dòng)截掉圖片中透明邊沿,所以本來一樣大小的圖片在Zwoptex中會(huì)顯得大小不一。

Cocos2d開發(fā)系列(五)

不用擔(dān)心, cocos2d會(huì)自動(dòng)計(jì)算這些誤差并正確顯示(不用擔(dān)心,這些數(shù)據(jù)都記載在.plist里)。

點(diǎn)擊 File——>save菜單,編輯結(jié)果保存為.zss文件格式(Zwoptex格式)。

點(diǎn)擊 Sprite Sheet——>Export——>Texture,編輯結(jié)果保存為.png格式。

點(diǎn)擊 Sprite Sheet——>Export——>Cordinates,編輯結(jié)果保存為.plist格式。

后兩者,正是 cocos2d所需要的。

3、Cocos2d中使用貼圖集

首先,將 Zwoptex生成的.png和.plist文件加入到項(xiàng)目的Resource組中。然后在代碼中使用貼圖集:

-( id ) initWithShipImage

{

// CCSpriteFrameCache加載貼圖集,用.plist文件而不是.png文件做參數(shù)

CCSpriteFrameCache * frameCache = [ CCSpriteFrameCache sharedSpriteFrameCache ];

[frameCache addSpriteFramesWithFile : @"ship-and-bullet.plist" ];

// 從貼圖集中加載名為 ship.png的sprite,注意ship.png是.plist中定義的key,而不是真正意義的文件名

if (( self = [ super initWithSpriteFrameName : @"ship.png" ]))

{

// 從貼圖集中加載 sprite幀,注意用.plist中的key值做參數(shù)而非文件名

NSMutableArray* frames = [NSMutableArray arrayWithCapacity : 5 ];

for ( int i = 0 ; i < 5 ; i ++)

{

NSString* file = [NSString stringWithFormat: @"ship-anim%i.png" , i ];

CCSpriteFrame * frame = [frameCache spriteFrameByName :file];

[frames addObject :frame];

}

CCAnimation * anim = [ CCAnimation animationWithName : @"move" delay : 0.08f frames :frames];

CCAnimate * animate = [ CCAnimate actionWithAnimation :anim];

CCRepeatForever * repeat = [ CCRepeatForever actionWithAction :animate];

[ self runAction :repeat];

[ self scheduleUpdate ];

}

return self ;

}

[CCSpriteFrameCache sharedSpriteFrameCache]是一個(gè)單例對象,其 addSpriteFramesWithFile 方法用于加載貼圖集(需要以.plist文件名作為參數(shù))。對于大文件貼圖集(超過512*512),加載過程可能會(huì)花費(fèi)數(shù)秒,應(yīng)當(dāng)在游戲開始前就加載。

CCSprite的initWithSpriteFrameName方法可以從貼圖集中獲取貼圖,并設(shè)置Sprite的顯示圖片,但它需要以貼圖集(.plist)中的幀名(framename,實(shí)際上是<frames>中的一個(gè)<key>)為參數(shù)。

當(dāng)然,如果要從貼圖集中得到一個(gè)幀,可以用 CCSpriteFrameCache的spriteFrameByName方法。這同樣需要用貼圖集中的幀名為參數(shù)。

如果你加載了多個(gè)貼圖集,但只要名為 ship.png的幀只有1個(gè),那么cocos2d就可以找到正確貼圖的。

其他代碼沒有任何改變。但出現(xiàn)了一個(gè)奇怪的現(xiàn)象:飛船的位置莫名其妙地向屏幕中心靠近了一點(diǎn),盡管不是很明顯。這個(gè)問題很容易解決,之前 Ship的初始化代碼是這樣的:

Ship * ship = [ Ship ship ];

ship. position = CGPointMake (ship. texture . contentSize . width / 2 , screenSize. height / 2 );

[ self addChild :ship];

這個(gè)地方需要改變:

ship. position = CGPointMake (ship. contentSize . width / 2 , screenSize. height / 2 );

問題解決了。導(dǎo)致這個(gè)現(xiàn)象的原因是, ship對象的texture的contentSize要比ship對象的contentSize大(Ship的Texture現(xiàn)在用的是貼圖集——具體說就是 ship-and-bullet.png 這張圖,尺寸為256*256,而原來的ship.png才128*64)。

4、修改CCAnimation類別Helper

現(xiàn)在是實(shí)現(xiàn)類別 Helper中的animationWithFrame方法的時(shí)候了:

+( CCAnimation *) animationWithFrame:(NSString*)frame frameCount:( int )frameCount delay:( float ) delay

{

// 構(gòu)造一個(gè) frame數(shù)組

NSMutableArray* frames = [NSMutableArray arrayWithCapacity :frameCount];

// 通過 CCSpriteFrameCache從貼圖集中加載frame,并將frame加到數(shù)組中

for ( int i = 0 ; i < frameCount; i ++)

{

NSString* file = [NSString stringWithFormat: @"%@%i.png" , frame, i ];

CCSpriteFrameCache * frameCache = [ CCSpriteFrameCache sharedSpriteFrameCache ];

CCSpriteFrame * frame = [frameCache spriteFrameByName :file];

[ frames addObject :frame];

}

// frame數(shù)組構(gòu)建animation對象并返回

return [ CCAnimation animationWithName :frame delay : delay frames : frames ];

}

現(xiàn)在,可以修改 ship類中initWithShipImage方法,把CCAnimation的初始化修改為:

CCAnimation * anim = [ CCAnimation animationWithFrame : @"ship-anim" frameCount : 5 delay : 0.08f ];

5、弱水三千,只取一瓢飲

只要你愿意,你可以把所有游戲圖片都加到一個(gè)貼圖集里。用 3個(gè)1024*1024的貼圖集跟用20個(gè)更小的貼圖集效率更高。

對于程序員而言,應(yīng)當(dāng)把代碼“分離”成不同的邏輯組件。于此不同,對于貼圖集來說,我們的目標(biāo)就是盡可能多地把圖片放到一個(gè)貼圖集里,盡可能降低內(nèi)存空間的浪費(fèi)。

用一個(gè)貼圖集放入玩家圖片,用另外的貼圖集放怪物 A、B、C的圖片——這好像更符合邏輯些,但這僅僅有助于你有大量的圖片,而且每次你只是有選擇地加載一部分圖片的時(shí)候。

當(dāng)你的圖片只需要 3-4個(gè)1024*1024貼圖集的時(shí)候,你應(yīng)當(dāng)把所有圖片只放在這些貼圖集里進(jìn)行預(yù)加載。這需要12-16MB的內(nèi)存。程序代碼和其他資源如音頻則不會(huì)占用這么多內(nèi)存,你可以把這些貼圖集都保留在內(nèi)存,這樣哪怕只有128MB RAM的老IOS設(shè)備也可以承受。

如果超過這個(gè)內(nèi)存,就應(yīng)該采取特別的策略了。比如,可以把游戲圖片進(jìn)行分類,并且只在當(dāng)前地圖中加載必要的貼圖集。這可以減少地圖加載時(shí)的延時(shí)。

因?yàn)? cocos2d會(huì)自動(dòng)緩存所有圖片,需要一種卸載貼圖的機(jī)制。絕大部分情況下你可以使用cocos2d提供的:

[[CCSpriteFrameCache sharedSpriteFrameCache]removeUnusedSpriteFrames];

[[CCTextureCache sharedTextureCache] removeUnusedTextures];

顯然應(yīng)當(dāng)在某些貼圖不再使用的時(shí)候調(diào)用這些方法。比如轉(zhuǎn)場景完成后。游戲正在進(jìn)行時(shí)就不行了。注意,僅僅在新場景初始化結(jié)束后,前面的場景才會(huì)被 deallocated 。意即在一個(gè) Scenen 的初始化方法中你不能調(diào)用 removeUnusedxxx 方法——除非你在兩個(gè) scene 轉(zhuǎn)換中使用了第 5 章的 LoadingScene 類,這樣你要擴(kuò)展 LoadingScene 使它在加載新場景替時(shí) remove 所有未使用的貼圖。

如果要絕對清除所有內(nèi)存中的貼圖以加載新的貼圖,應(yīng)當(dāng)使用:

[CCSpriteFrameCache purgeSharedSpriteFrameCache];

[CCTextureCache purgeSharedTextureCache];

6 、美工和藝術(shù)

圖片的編輯你可以使用免費(fèi)軟件 Searshore http://seashore.sourceforge.net

對于動(dòng)畫和位圖,你可以使用 Pixen http://opensword.org/Pixen ,這是一個(gè)簡單易用和強(qiáng)大的動(dòng)畫編輯工具。

如果你想自己制作音樂音效,可以使用 Mac 自帶的 GarageBand 。插上一只麥克風(fēng)開始記錄一些聲音,花幾分鐘編輯并在任何適當(dāng)?shù)牡胤绞褂眠@些聲音。如果不想自己制作聲效,也可以從網(wǎng)上搜索一些免費(fèi)或便宜的音頻,例如 www.soundsnap.com 或者類似網(wǎng)站。

警告:對于使用源自互聯(lián)網(wǎng)的音頻和圖片要尤其小心。你可以下載到一些“免費(fèi)”的資源用于早期的游戲制作。但簡單的“免費(fèi)”并不意味著你可以再分發(fā)這些文件,或者用于商業(yè)用途,例如在蘋果商店中銷售。除非獲得作者特別的授權(quán)或者這些資源附有一個(gè)正式的協(xié)議。

Cocos2d開發(fā)系列(五)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 老司机久久精品视频 | 久久精品影院永久网址 | 欧美色久| 97免费在线观看 | 五月天婷婷一区二区三区久久 | 黄色毛片免费看 | 精品一区二区在线观看 | 亚洲日本久久久午夜精品 | 欧美成人免费大片888 | 国产成人精品日本亚洲麻豆 | 亚洲精品一区久久狠狠欧美 | 久久福利免费视频 | 在线中文字幕日韩 | 欧美色亚洲 | 日日拍夜夜嗷嗷叫国产 | 欧美日本综合一区二区三区 | 99热这里只有成人精品国产 | 天天色综合图片 | 亚洲成年人在线观看 | 亚洲在线免费视频 | 99re免费视频精品全部 | 四虎爱爱 | 污影院 | 国产91在线播放边 | 精品国产免费一区二区三区 | 亚洲深夜在线 | 欧美一级高清片在线 | 波多野结衣手机视频一区 | a免费国产一级特黄aa大 | 东北一级毛片 | 男人的天堂在线视频 | 日韩xoxo视频在线观看 | 色综合色综合色综合 | 亚洲欧美日韩久久精品第一区 | 日本一区二区日本免费 | 国产精品久久久久影院嫩草 | 国产成人福利夜色影视 | 国产成年 | 天天色天天干天天射 | 日韩国产午夜一区二区三区 | 久久久久久久久66精品片 |