欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

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

系統(tǒng) 2163 0

Learn IPhone and iPad Cocos2d Game Delevopment》的第5章。

一、使用多場景

很少有游戲只有一個場景。這個例子是這個樣子的: Cocos2d開發(fā)系列(四)

這個 Scene中用到了兩個Layer,一個Layer位于屏幕上方,標(biāo)有”Here be your Game Scores etc“字樣的標(biāo)簽,用于模擬游戲菜單。一個Layer位于屏幕下方,一塊綠色的草地上有一些隨機游動的蜘蛛和怪物,模擬了游戲的場景。

1、加入新場景

一個場景是一個 Scene類。加入新場景就是加入更多的Scene類。

有趣的是場景之間的切換。使用 [CCDirector replaceScene]方法轉(zhuǎn)場時,CCNode有3個方法會被調(diào)用:OnEnter、OnExit、 onEnterTransitionDidFinish。

覆蓋這 3個方法時要牢記,始終要調(diào)用super的方法,避免程序的異常(比如內(nèi)存泄露或場景不響應(yīng)用戶動作)。

-(void) onEnter {

// node的 init 方法后調(diào)用.

// 如果使用 CCTransitionScene方法,在轉(zhuǎn)場開始后調(diào)用.

[super onEnter];

}

-(void ) onEnterTransitionDidFinish {

// onEnter方法后調(diào)用.

// 如果使用 CCTransitionScene方法,在轉(zhuǎn)場結(jié)束后調(diào)用.

[super onEnterTransitionDidFinish];

}

-(void) onExit

{

// node的 dealloc 方法前調(diào)用.

// 如果使用CCTransitionScene方法, 在轉(zhuǎn)場結(jié)束時調(diào)用.

[super onExit];

}

當(dāng)場景變化時,有時候需要讓某個 node干點什么,這時這3個方法就派上用場了。

與在 node的init方法和dealloc方法中做同樣的事情不同,在onEnter方法執(zhí)行時,場景已經(jīng)初始化了;而在onExit方法中,場景的node仍然是存在的。

這樣,在進(jìn)行轉(zhuǎn)場時,你就可以暫停動畫或隱藏用戶界面元素,一直到轉(zhuǎn)場完成。這些方法調(diào)用的先后順序如下(使用 replaceScene 方法):

1. 第2個場景的 scene 方法

2. 第2個場景的 init 方法

3. 第2個場景的 onEnter 方法

4. 轉(zhuǎn)場

5. 第1個場景的 onExit 方法

6. 第2個場景的 onEnterTransitionDidFinish 方法

7. 第1個場景的 dealloc 方法

二、請稍候??

切換場景時,如果場景的加載是一個比較耗時的工作,有必要用一個類似“ Loading,please waiting…”的場景來過渡一下。用于在轉(zhuǎn)場時過渡的場景是一個“輕量級”的Scene類,可以顯示一些簡單的提示內(nèi)容:

typedef enum

{

TargetSceneINVALID = 0 ,

TargetSceneFirstScene,

TargetSceneOtherScene,

TargetSceneMAX,

} TargetScenes;

@interface LoadingScene : CCScene

{

TargetScenes targetScene_;

}

+( id ) sceneWithTargetScene:(TargetScenes)targetScene;

-( id ) initWithTargetScene:(TargetScenes)targetScene;

@end

#import "LoadingScene.h"

#import "FirstScene.h"

#import "OtherScene.h"

@interface LoadingScene (PrivateMethods)

-( void ) update:(ccTime)delta;

@end

@implementation LoadingScene

+( id ) sceneWithTargetScene:(TargetScenes)targetScene;

{

return [[[ self alloc] initWithTargetScene:targetScene] autorelease];

}

-( id ) initWithTargetScene:(TargetScenes)targetScene

{

if (( self = [ super init]))

{

targetScene_ = targetScene;

CCLabel* label = [CCLabel labelWithString: @"Loading ..." fontName: @"Marker Felt" fontSize: 64 ];

CGSize size = [[CCDirector sharedDirector] winSize];

label.position = CGPointMake(size.width / 2 , size.height / 2 );

[ self addChild:label];

[ self scheduleUpdate];

}

return self ;

}

-( void ) update:(ccTime)delta

{

[ self unscheduleAllSelectors];

switch (targetScene_)

{

case TargetSceneFirstScene:

[[CCDirector sharedDirector] replaceScene:[FirstScene scene]];

break ;

case TargetSceneOtherScene:

[[CCDirector sharedDirector] replaceScene:[OtherScene scene]];

break ;

default :

// NSStringFromSelector(_cmd) 打印方法名

NSAssert2( nil , @"%@: unsupported TargetScene %i" , NSStringFromSelector( _cmd ), targetScene_);

break ;

}

}

-( void ) dealloc

{

CCLOG( @"%@: %@" , NSStringFromSelector( _cmd ), self );

[ super dealloc];

}

@end

首先,定義了一個枚舉。這個技巧使 LoadingScene 能用于多個場景的轉(zhuǎn)場,而不是固定地只能在某個場景的切換時使用。繼續(xù)擴展這個枚舉的成員,使 LoadingScene 能適用與更多目標(biāo) Scene 的轉(zhuǎn)場。

sceneWithTargetScene 方法中返回了一個 autorelease 的對象。在 coco2d 自己的類中也是一樣的,你要記住在每個靜態(tài)的初始化方法中使用 autorelease

方法中,構(gòu)造了一個 CCLabel ,然后調(diào)用 scheduleUpdate 方法。 scheduleUpdate 方法會在下一個時間(約一幀)后調(diào)用 update 方法。在 update 方法中,我們根據(jù) sceneWithTargetScene 方法中指定的枚舉參數(shù),切換到另一個 scene 。在這個 scene 的加載完成之前, LoadingScene 會一直顯示并且凍結(jié)用戶的事件響應(yīng)。

我們不能直接在初始化方法 initWithTargetScene 中直接切換 scene ,這會導(dǎo)致程序崩潰。記住,在一個 Node 還在初始化的時候,千萬不要在這個 scene 上調(diào)用 CCDirector replaceScene 方法。

LoadingScene 的使用很簡單,跟一般的 scene 一樣:

CCScene * newScene = [ LoadingScene sceneWithTargetScene : TargetSceneFirstScene ];

[[ CCDirector sharedDirector ] replaceScene :newScene];

三、使用 Layer

Layer類似Photoshop中層的概念,在一個scene中可以有多個Layer:

typedef enum

{

LayerTagGameLayer ,

LayerTagUILayer ,

} MultiLayerSceneTags;

typedef enum

{

ActionTagGameLayerMovesBack ,

ActionTagGameLayerRotates ,

} MultiLayerSceneActionTags;

@class GameLayer ;

@class UserInterfaceLayer ;

@interface MultiLayerScene : CCLayer

{

bool isTouchForUserInterface ;

}

+( MultiLayerScene *) sharedLayer;

@property ( readonly ) GameLayer* gameLayer;

@property ( readonly ) UserInterfaceLayer* uiLayer;

+( CGPoint ) locationFromTouch:( UITouch *)touch;

+( CGPoint ) locationFromTouches:( NSSet *)touches;

+( id ) scene;

@end

@implementation MultiLayerScene

static MultiLayerScene* multiLayerSceneInstance;

+( MultiLayerScene *) sharedLayer

{

NSAssert ( multiLayerSceneInstance != nil , @"MultiLayerScene not available!" );

return multiLayerSceneInstance ;

}

-( GameLayer *) gameLayer

{

CCNode * layer = [ self getChildByTag : LayerTagGameLayer ];

NSAssert ([layer isKindOfClass :[ GameLayer class ]], @"%@: not a GameLayer!" , NSStringFromSelector ( _cmd ));

return ( GameLayer *)layer;

}

-( UserInterfaceLayer *) uiLayer

{

CCNode * layer = [[ MultiLayerScene sharedLayer ] getChildByTag : LayerTagUILayer ];

NSAssert ([layer isKindOfClass :[ UserInterfaceLayer class ]], @"%@: not a UserInterfaceLayer!" , NSStringFromSelector ( _cmd ));

return ( UserInterfaceLayer *)layer;

}

+( CGPoint ) locationFromTouch:( UITouch *)touch

{

CGPoint touchLocation = [touch locationInView : [touch view ]];

return [[ CCDirector sharedDirector ] convertToGL :touchLocation];

}

+( CGPoint ) locationFromTouches:( NSSet *)touches

{

return [ self locationFromTouch :[touches anyObject ]];

}

+( id ) scene

{

CCScene * scene = [ CCScene node ];

MultiLayerScene * layer = [ MultiLayerScene node ];

[scene addChild :layer];

return scene;

}

-( id ) init

{

if (( self = [ super init ]))

{

NSAssert ( multiLayerSceneInstance == nil , @"another MultiLayerScene is already in use!" );

multiLayerSceneInstance = self ;

GameLayer * gameLayer = [ GameLayer node ];

[ self addChild : gameLayer z : 1 tag : LayerTagGameLayer ];

UserInterfaceLayer * uiLayer = [ UserInterfaceLayer node ];

[ self addChild : uiLayer z : 2 tag : LayerTagUILayer ];

}

return self ;

}

-( void ) dealloc

{

CCLOG ( @"%@: %@" , NSStringFromSelector ( _cmd ), self );

[ super dealloc ];

}

@end

MultiLayerScene 中使用了多個 Layer: 一個 GameLayer h 和一個 UserInterfaceLayer

MultiLayerScene 使用了靜態(tài)成員 multiLayerSceneInstance 來實現(xiàn)單例。 MultiLayerScene也是一個Layer,其node方法實際上調(diào)用的是實例化方法init——在其中,我們加入了兩個Layer,分別用兩個枚舉 LayerTagGameLayer LayerTagUILayer 來檢索 , 如屬性方法 gameLayer和uiLayer所示。

uiLayer是一個UserInterfaceLayer,用來和用戶交互,在這里實際上是在屏幕上方放置一個菜單,可以把游戲的一些統(tǒng)計數(shù)字比如:積分、生命值放在這里:

typedef enum

{

UILayerTagFrameSprite ,

} UserInterfaceLayerTags;

@interface UserInterfaceLayer : CCLayer

{

}

-( bool ) isTouchForMe:( CGPoint )touchLocation;

@end

@implementation UserInterfaceLayer

-( id ) init

{

if (( self = [ super init ]))

{

CGSize screenSize = [[ CCDirector sharedDirector ] winSize ];

CCSprite * uiframe = [ CCSprite spriteWithFile : @"ui-frame.png" ];

uiframe. position = CGPointMake ( 0 , screenSize. height );

uiframe. anchorPoint = CGPointMake ( 0 , 1 );

[ self addChild :uiframe z : 0 tag : UILayerTagFrameSprite ];

// Label模擬UI控件( 這個Label沒有什么作用,僅僅是演示) .

CCLabel * label = [ CCLabel labelWithString : @"Here be your Game Scores etc" fontName : @"Courier" fontSize : 22 ];

label. color = ccBLACK ;

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

label. anchorPoint = CGPointMake ( 0.5f , 1 );

[ self addChild :label];

self . isTouchEnabled = YES ;

}

return self ;

}

-( void ) dealloc

{

CCLOG ( @"%@: %@" , NSStringFromSelector ( _cmd ), self );

[ super dealloc ];

}

-( void ) registerWithTouchDispatcher

{

[[ CCTouchDispatcher sharedDispatcher ] addTargetedDelegate : self priority :- 1 swallowsTouches : YES ];

}

// 判斷觸摸是否位于有效范圍內(nèi) .

-( bool ) isTouchForMe:( CGPoint )touchLocation

{

CCNode * node = [ self getChildByTag : UILayerTagFrameSprite ];

return CGRectContainsPoint ([node boundingBox ], touchLocation);

}

-( BOOL ) ccTouchBegan:( UITouch *)touch withEvent:( UIEvent *)event

{

CGPoint location = [ MultiLayerScene locationFromTouch :touch];

bool isTouchHandled = [ self isTouchForMe :location];

if (isTouchHandled)

{

// 顏色改變?yōu)榧t色,表示接收到觸摸事件 .

CCNode * node = [ self getChildByTag : UILayerTagFrameSprite ];

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

(( CCSprite *)node). color = ccRED ;

// Action: 旋轉(zhuǎn) +縮放 .

CCRotateBy * rotate = [ CCRotateBy actionWithDuration : 4 angle : 360 ];

CCScaleTo * scaleDown = [ CCScaleTo actionWithDuration : 2 scale : 0 ];

CCScaleTo * scaleUp = [ CCScaleTo actionWithDuration : 2 scale : 1 ];

CCSequence * sequence = [ CCSequence actions :scaleDown, scaleUp, nil ];

sequence. tag = ActionTagGameLayerRotates ;

GameLayer * gameLayer = [ MultiLayerScene sharedLayer ]. gameLayer ;

// 重置 GameLayer 屬性 , 以便每次動畫都是以相同的狀態(tài)開始

[gameLayer stopActionByTag : ActionTagGameLayerRotates ];

[gameLayer setRotation : 0 ];

[gameLayer setScale : 1 ];

// 運行動畫

[gameLayer runAction :rotate];

[gameLayer runAction :sequence];

}

return isTouchHandled;

}

-( void ) ccTouchEnded:( UITouch *)touch withEvent:( UIEvent *)event

{

CCNode * node = [ self getChildByTag : UILayerTagFrameSprite ];

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

// 色彩復(fù)原

(( CCSprite *)node). color = ccWHITE ;

}

@end

為了保證 uiLayer總是第一個收到touch事件,我們在 registerWithTouchDispatcher 方法中使用-1的priority。并且用 isTouchForMe 方法檢測touch是否處于Layer的范圍內(nèi)。如果在,touchBegan方法返回YES,表示“吃掉” touch事件(即不會傳遞到下一個Layer處理);否則,返回NO,傳遞給下一個Layer(GameLayer)處理。

而在 GameLayer中, registerWithTouchDispatcher 的priority是0

以下是 GameLayer代碼:

@interface GameLayer : CCLayer

{

CGPoint gameLayerPosition ;

CGPoint lastTouchLocation ;

}

@end

@interface GameLayer (PrivateMethods)

-( void ) addRandomThings;

@end

@implementation GameLayer

-( id ) init

{

if (( self = [ super init ]))

{

self . isTouchEnabled = YES ;

gameLayerPosition = self . position ;

CGSize screenSize = [[ CCDirector sharedDirector ] winSize ];

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

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

[ self addChild :background];

CCLabel * label = [ CCLabel labelWithString : @"GameLayer" fontName : @"Marker Felt" fontSize : 44 ];

label. color = ccBLACK ;

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

label. anchorPoint = CGPointMake ( 0.5f , 1 );

[ self addChild :label];

[ self addRandomThings ];

self . isTouchEnabled = YES ;

}

return self ;

}

// node加上一個MoveBy的動作(其實就是在圍繞一個方框在繞圈)

-( void ) runRandomMoveSequence:( CCNode *)node

{

float duration = CCRANDOM_0_1 () * 5 + 1 ;

CCMoveBy * move1 = [ CCMoveBy actionWithDuration :duration position : CGPointMake (- 180 , 0 )];

CCMoveBy * move2 = [ CCMoveBy actionWithDuration :duration position : CGPointMake ( 0 , - 180 )];

CCMoveBy * move3 = [ CCMoveBy actionWithDuration :duration position : CGPointMake ( 180 , 0 )];

CCMoveBy * move4 = [ CCMoveBy actionWithDuration :duration position : CGPointMake ( 0 , 180 )];

CCSequence * sequence = [ CCSequence actions :move1, move2, move3, move4, nil ];

CCRepeatForever * repeat = [ CCRepeatForever actionWithAction :sequence];

[node runAction :repeat];

}

// 模擬一些游戲?qū)ο? ,為每個對象加上一些動作(繞圈) .

-( void ) addRandomThings

{

CGSize screenSize = [[ CCDirector sharedDirector ] winSize ];

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

{

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

firething. position = CGPointMake ( CCRANDOM_0_1 () * screenSize. width , CCRANDOM_0_1 () * screenSize. height );

[ self addChild :firething];

[ self runRandomMoveSequence :firething];

}

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

{

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

spider. position = CGPointMake ( CCRANDOM_0_1 () * screenSize. width , CCRANDOM_0_1 () * screenSize. height );

[ self addChild :spider];

[ self runRandomMoveSequence :spider];

}

}

-( void ) dealloc

{

CCLOG ( @"%@: %@" , NSStringFromSelector ( _cmd ), self );

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

[ super dealloc ];

}

-( void ) registerWithTouchDispatcher

{

[[ CCTouchDispatcher sharedDispatcher ] addTargetedDelegate : self priority : 0 swallowsTouches : YES ];

}

-( BOOL ) ccTouchBegan:( UITouch *)touch withEvent:( UIEvent *)event

{

// 記錄開始touch時的位置 .

lastTouchLocation = [ MultiLayerScene locationFromTouch :touch];

// 先停止上一次動作,以免對本次拖動產(chǎn)生干擾 .

[ self stopActionByTag : ActionTagGameLayerMovesBack ];

// 吃掉所有 touche

return YES ;

}

-( void ) ccTouchMoved:( UITouch *)touch withEvent:( UIEvent *)event

{

// 記錄手指移動的位置

CGPoint currentTouchLocation = [ MultiLayerScene locationFromTouch :touch];

// 計算移動的距離

CGPoint moveTo = ccpSub ( lastTouchLocation , currentTouchLocation);

// 上面的計算結(jié)果要取反 .因為接下來是移動前景,而不是移動背景

moveTo = ccpMult (moveTo, - 1 );

lastTouchLocation = currentTouchLocation;

// 移動前景——修改 Layer的位置,將同時改變Layer所包含的node self . position = ccpAdd ( self . position , moveTo);

}

-( void ) ccTouchEnded:( UITouch *)touch withEvent:( UIEvent *)event

{

// 最后把 Layer的位置復(fù)原 .Action: 移動 +漸慢

CCMoveTo * move = [ CCMoveTo actionWithDuration : 1 position : gameLayerPosition ];

CCEaseIn * ease = [ CCEaseIn actionWithAction :move rate : 0.5f ];

ease. tag = ActionTagGameLayerMovesBack ;

[ self runAction :ease];

}

@end

為了讓程序運行起來更有趣, GameLayer中加入了一張青草的背景圖,以及一些游戲?qū)ο螅⒆屵@些對象在隨機地移動。這部分內(nèi)容不是我們關(guān)注的,我們需要關(guān)注的是幾個touch方法的處理。

1、 ccTouchBegan

由于 GameLayer是最后收到touch事件的Layer,我們不需要檢測touch是否在Layer范圍(因為傳給它的都是別的Layer“吃剩下”的touch)。所以GameLayer的touchBegan方法只是簡單的返回YES(“吃掉”所有touch)。

2 ccTouchMoved:

在這里我們計算手指移動的距離,然后讓 Layer作反向運動。為什么要作“反向”運動? 因為我們想制造一種屏幕隨著手指劃動的感覺,例如: 當(dāng)手向右劃動時,屏幕也要向右運動。當(dāng)然,iPhone不可能真的向右運動。要想模擬屏幕向右運動,只需讓游戲畫面向左運動即可。因為當(dāng)運動物體在向前移動時,如果假設(shè)運動物體固定不動,則可以認(rèn)為是參照物(或背景)在向后運動。

3、 ccTouchEnded:

在這里,我們把 Layer的位置恢復(fù)到原位。

四、其他

這一章還討論了很多有用的東西,比如“關(guān)卡”。是使用 Scene還是Layer作為游戲關(guān)卡?

作者還建議在設(shè)計 Sprite時使用聚合而不要使用繼承。即Sprite設(shè)計為不從CCNode繼承,而設(shè)計為普通的NSObject子類(在其中聚合了CCNode)。

此外還討論了 CCTargetToucheDelegate、CCProgressTimer、CCParallaxNode、vCCRibbon和CCMotionStreak。

這些東西可以豐富我們的理論知識,但沒有必要細(xì)讀。

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 狠狠干成人| 深夜你懂的在线网址入口 | 好骚综合在线 | 国产成人精品福利色多多 | 亚洲精品自产拍在线观看app | 妖精视频国产 | www一区二区三区 | 成人免费视频网站在线观看 | 精品的一区二区三区 | 九一国产精品 | 中文字幕亚洲欧美日韩在线不卡 | 91精品国产综合久久久久久 | 欧美成年视频 | 亚洲视频一区在线 | 中文字幕精品一区久久久久 | 老司机福利在线视频 | 亚洲AV久久久久久久无码 | 久久国产精品视频一区 | 欧美日韩一区二区三区免费视频 | 亚洲91精品 | 99热这里有精品 | 色天天天天综合男人的天堂 | 亚洲最大在线视频 | 在线观看中文字幕 | 国产乱码精品1区2区3区 | 天天摸天天操免费播放小视频 | 九一免费国产 | 97av在线 | 国产成人一区二区三区电影 | 99热在线观看免费 | 一本大道香蕉中文日本不卡高清二区 | 亚洲视频区 | 麻豆短视频app网站 天天澡天天碰天天狠伊人五月 | 国产视频福利 | 91高清视频在线免费观看 | 九九视频九九热 | 久热久热| 午夜视频久久 | 久久亚洲一级α片 | 欧美一区二区三区久久久 | 亚洲zscs综合网站 |