麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

SpriteBuilder學習筆記二

2019-11-14 19:35:54
字體:
來源:轉載
供稿:網友

Chapter 3  Controlling and Scrolling

@implementation GameScene {    __weak CCNode *_levelNode;    __weak CCPhysicsNode *_physicalNode;    __weak CCNode *_playerNode;    __weak CCNode *_backgroundNode;}

注意__weak關鍵字。總的來說,聲明一個obejct pointer 變量而不是由類created 或者說owned的時候,最好都使用__weak,尤其是在cocos2d中,應該總是聲明一個引用,當這個引用不是parent或者node的“兄弟”(sibling)時。如果沒有__weak關鍵字,默認生成一個strong引用。

通過名字找到Player Node

在GameScene中添加代碼:

- (void)didLoadFromCCB {    NSLog(@"GameScene created!");    // 使得可以接受輸入的事件 (enable receiving input events)    // 這句話允許GameScene類去接受觸摸事件    self.userInteractionEnabled = YES;    // load the current level 載入當前level    [self loadLevelNamed:nil];}
- (void)loadLevelNamed:(NSString*)levelCCB {    // 在scene中獲取當前level的player,遞歸尋找    _playerNode = [self getChildByName:@"player" recursively:YES];    // 如果沒有找到,NSAssert會拋出一個異常    NSAssert1(_playerNode, @"player node not found in level:%@", levelCCB);}

下面的代碼用于實現通過觸摸移動物體到觸摸的位置

- (void)touchBegan:(CCTouch*)touch withEvent:(UIEvent*)event {    _playerNode.position = [touch locationInNode:self];}

NOTE:書中第一個參數類型為UITouch* 報錯,改為CCTouch后即可實現功能。

查閱API,摘抄如下:

touchBegan:withEvent:

Called when a touch began. Behavior notes:

- (void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event

Parameters

touch

Contains the touch.

event

Current event information.

Discussion

  • If a touch is dragged inside a node which does not claim user interaction, a touchBegan event will be generated.
  • If node has exclusive touch, all other ongoing touches will be cancelled.
  • If a node wants to handle any touch event, the touchBegan method must be overridden in the node subclass. Overriding just touchMoved or touchEnded does not suffice.
  • To pass the touch further down the Cocos2D responder chain, call the super implementation, ie [super touchBegan:withEvent:].

Declared In

CCResponder.h

 

分配Level-Node變量

在SPRiteBuilder中分配變量和通過名字獲取一個node是一樣的,僅僅是個人習慣問題。但是不推薦頻繁使用getChildByName:方法在schedule methond中(不太懂這是什么方法)和updata:方法中,特別是遞歸查找和a deep-node hierarch。

Caution:在SpriteBuilder中分配一個變量僅僅適用于CCB文件的直接descendants(后代--不知如何翻譯),不可以對通過Sub File(CCBFile)導入的另一個CCB指定node為變量或者properties。這也是為何player node通過名字獲取。

打開GameScene.ccb,

 

note:A doc root var assigns a node to a correspondingly named ivar or property declared in the CCB root node's custom class

Doc root var:分配一個node,為在CCB根node的自定義類中聲明的相對應名字的變量或者屬性。

做完這步后,_levelNode變量會在它發送didLoadFromCCB消息之前被CCBReader分配,這是創建一個在CCB中包含的node的最簡單,最有效的方法。

 

用CCActionMoveTo移動Player

為了平滑的移動player到指定位置,可以修改如下代碼:

- (void)touchBegan:(CCTouch*)touch withEvent:(UIEvent*)event {   // _playerNode.position = [touch locationInNode:self];    CGPoint pos = [touch locationInNode:_levelNode];    CCAction *move = [CCActionMoveTo actionWithDuration:0.2 position:pos];    [_playerNode runAction:move];}

觸摸點根據_levelNode轉化。這一點很重要,保證了player可以在整個_levelNode上移動,而不是被禁錮在屏幕空間中。但是這一點目前還看不出來,因為還沒有添加滾動(scrolling)。

但是此時,如果增加duration(持續時間),會發現移動的動作并沒有疊加,player也不會停在你最后一次點擊的地方。所以必須添加一個tag,有了這個tag,可以在執行新的動作之前,停止當前動作,代碼更改如下:

- (void)touchBegan:(CCTouch*)touch withEvent:(UIEvent*)event {   // _playerNode.position = [touch locationInNode:self];    [_playerNode stopActionByTag:1];    CGPoint pos = [touch locationInNode:_levelNode];    CCAction *move = [CCActionMoveTo actionWithDuration:20.2 position:pos];    move.tag = 1;    [_playerNode runAction:move];}

 

滾動Level(Scrolling the Level)

在2D游戲中,更普遍的做法是相反方向移動content layer,已達到滾動效果。

在Cocos2D和OpenGl中,沒有camera的概念,只有device screen(設備屏幕).

 

 Scheduling Updates(調度更新)

如果player移動到右邊和上邊,那我們要做的事情實際上是移動_levelNode向左邊和下邊方向移動。player的位置限定在level node中,左下角左邊為(0,0),在這個程序中,范圍是4000*500 points。

在GameScene中添加如下代碼:

// the updata:method is automatically called once per frame// update方法在每一幀都被自動調用- (void)update:(CCTime)delta {    // update scroll node position to player node, with offset to center player in the view    [self scrollToTarget:_playerNode];}

update:方法自動被Cocos2d調用,在底層,每一幀,node出現在屏幕之前,都回被調用。

不像之前的Cocos2d版本,你不再需要去明確調度更新(you no longer have to explicitly schedule the update:method.)

你可以使用node schedule和unschedule方法調度其他的方法或blocks.(you can still schedule other methods or blocks using the node schedule and unschedule methods)

例如:延遲運行一個selector,可以寫為:

[self scheduleOnce:@selector(theDelayedMethod:)delay:2.5]:

然后再相同的類中實現對應的selector。這個selector必須使用一個CCTime參數:

-(void)theDelayedMethod:(CCTime)delta {

//your code

}

Caution:永遠不要使用NSTimer等。這些時間方法在node或者Cocos2d暫停時候不會自動暫停。

delta參數是delta time,或者difference in time。

在60幀每秒時,delta時間經常取大約0.0167,單位是秒。

delta time通常用作以相同的速度移動nodes,而忽略幀速率。我們在這本書中不使用delta time,因為我們使用Cocos2d的物理引擎。

 

Moving the level Node in the Opposite Derection

向相反方向移動Level Node

在GameScene.m中添加scrollToTarget方法以完成滾動:

- (void)scrollToTarget:(CCNode*)target {    CGSize viewSize = [CCDirector sharedDirector].viewSize;    CGPoint viewCenter = CGPointMake(viewSize.width / 2.0,viewSize.height / 2.0);    CGPoint viewPos = ccpSub(target.positionInPoints, viewCenter);    CGSize levelSize = _levelNode.contentSizeInPoints;    viewPos.x = MAX(0.0, MIN(viewPos.x, levelSize.width - viewSize.width));    viewPos.y = MAX(0.0,MIN(viewPos.y, levelSize.height - viewSize.height));    _levelNode.positionInPoints = ccpNeg(viewPos);}

前兩行的作用是指定view的尺寸到viewSize,值為屏幕以points為單位的值。

然后計算view的中心點。

viewPos變量被初始化為目標的positionInPoints減去中心點viewCenter。

這個使用ccpSub做的減法是為了保持目標node保持中心位置,如果不做這一步,目標node會消失在屏幕的左下角。

levelSize變量被定義為_lovelNode.contentSizeInPoints,在下面兩行中,它用于夾住viewPos。

因為屏幕永遠不應該比viewCenter滾動的更接近于level的邊界,所以使用減法。每個邊界的距離相加等于viewSize。或者換句話說,可以滾動的區域是viewCenter的兩倍或者一個viewSize   ???

level區域和可滾動區域的關系圖:箭頭表示可滾動區域。注意player在接近level邊界的時候已經不在中心位置了。

 

Parallax Scrolling 視差滾動

有很多種實現視差滾動的方法,最簡單的方法是給每個layer不同的速度,并移動layers。但是這種方法有一個缺點,就是你永遠也不可能知道每個layer到底需要多大,而且很難判斷當player到達一個level中的點時,背景的哪一個部分會是可見的。

Working with Images

 

如果你只有2x規模的圖片版本,可以適配retina iphone和non-retina ipad,你可以改變“Scale from”設置,從Default改變為2x。這不能起到節省內存的作用,SpriteBuilder會創建一個低規模的1x和一個高規模的4x版本。這意味著4x版本的圖片和原始的2x版本的圖片有一樣程度的細節。你也可以為各種規模的圖片采用不同的圖片。強烈建議創建所有images。

SpriteBuilder給你兩個選擇:要么創建所有圖片,4x和568x384,以便在ipads上運行,要么創建2x,568x320,然后只為了在iphone設備上運行。

舉例來說,填滿ipads Retina屏幕需要最少2048x1536個像素(defult 4x),如果是2272x1536更好,可以更好的覆蓋4-inch的iphon屏幕。如果你的app只為了在iphone上運行,(對所有圖片使用2x規模),那么覆蓋整個retina屏幕的圖片需要1136x640像素點(568X320 points)。但是如果你希望稍后添加ipad版本,那么就需要你為ipad retina屏幕設計你所有的圖片了。

Project Setting

如果你開發一個僅在Iphone上運行的app,SpriteBuilder給了你改變默認4x規模的選擇。File-Project-Setting dialog

 

如果你想你的iPad版本顯示對應的更大的游戲世界,你可以改變“Default scaling from”,設定為2x(phonehd),注意設置不會應用在已經存在的圖片上,只有伺候新的添加進SpriteBuilder的images會改變。

注意:Apple要求app開發者支持Retina。強烈建議使用設置:Scale from setting 1x for any images,因為在iPad Retina屏幕上的顯示質量會很低。

設置:phone:僅在iPhone3GS上適用

     phonehd:在iPhone4和更新的設備上適用

   tablet:對非Retina ipads:Ipad1 和2,iPad mini1上適用

    tablethd:對iPad3和iPadmini2和更新的設備上適用

其他的選項:

    Audio quality:影響發布的音頻文件的大小和質量。level 1創建最小但是質量最差的文件。

    Screen mode:主要的應用情況是當你的游戲僅僅是iPhone上運行時,并且你希望把3.5和4英寸iphone作為同一個設備,這種情況下可以考慮使用fixed mode,但是通常不建議使用因為這會使得屏幕的布局很困難。

   Orientation:橫屏或者豎屏設置。

 

Adding Addition Background Layers

很明顯,需要更多的layers去達到景深效果。距離觀察者更近的layer,它的size就需要更大。

 

Prepare to Parallax in 3 2 1...

使得背景layers視差滾動需要一些初始化步驟。

首先,引進physics node,并使得player node變成physics node的子node。現在,physics node是level的內容容器,而不是level.ccb本身。

讓player作為另一個node的子node的主要原因是為了能夠在視差背景中獨立移動level內容。如果繼續使用Level.ccb做為player的父node,the changes made to the player's parent position would offset all of the level1.ccb child nodes,including the background .這會使得背景滾動的代碼復雜得多,并且很難添加一個靜止不動的node,比如暫停按鈕。

NOTE:不能把player node拖拽到background node下。因為background node 是Sub File node,不可以接受子nodes。還有其他幾類無法擁有子nodes的:Particle System,Label TTF, Label BM-Font,Button,Text Field,Slider,Scroll View。

現在需要分配CCPhysicsNode引用_physicsNode變量。因為getChildByName:返回一個CCNode類的引用,所以必須強轉返回的node。

_physicsNode = (CCPhysicsNode*)[_levelNode getChildByName:@"physics" recursively:NO];

 

- (void)loadLevelNamed:(CCNode*) levelCCB {    _physicsNode = (CCPhysicsNode*)[_levelNode getChildByName:@"physics" recursively:NO];    _background = [_levelNode getChildByName:@"background" recursively:NO];    _playerNode = [_physicsNode getChildByName:@"player" recursively:NO];    NSAssert1(_playerNode, @"not found %@", levelCCB);    NSAssert1(_physicsNode, @"not found %@", levelCCB);    NSAssert1(_background, @"not found %@", levelCCB);}

現在,需要對scrollToTarget方法進行修改:

_levelNode.positionInPoints = ccpNeg(viewPos);

改為

_physicsNode.positionInPoints = ccpNeg(viewPos);

這樣,_backgroundNode的位置就會被解放,可以根據_physicsNode的位置獨立的更新。

現在,scrollToTarget方法的代碼為:

- (void)scrollToTarget:(CCNode*)target {    // 屏幕大小 480 * 320    CGSize viewSize = [CCDirector sharedDirector].viewSize;    // player的中心位置 (240,160)    CGPoint viewCenter = CGPointMake(viewSize.width / 2.0, viewSize.height / 2.0);    // levelNode的size 4000 * 500;    CGSize levelSize = _levelNode.contentSizeInPoints;    //    CGPoint viewPos = ccpSub(target.positionInPoints, viewCenter);    viewPos.x = MAX(0.0, MIN(viewPos.x, levelSize.width - viewSize.width));    viewPos.y = MAX(0.0, MIN(viewPos.y, levelSize.height - viewSize.height));    _physicsNode.positionInPoints = ccpNeg(viewPos);}

現在,必須獲取每個背景layers在_physisNode的位置更新時視差滾動的位置。

因為你想要每個layers的位置對應_physicsNode的位置,(在這個方法中是viewPos),那么考慮到viewPos(view的中心)應該與level的邊界保持一定的距離就很重要了。這個最小的距離必須至少在水平方向是viewCenter.width,在垂直方向是viewCenter.height.這樣才可以阻止可視區域出現在level邊界的外面.

這幅圖可以幫助理解,想象viewPos是每個Viewable Area的中心,那么實際的Scrollable Area矩形(比如,viewPos合法位置)必須比Level Area的左下角大,必須比右上角小。

這樣,每個背景layer相對應的位置不能和整個尺寸的level相比,也就是4000x500個points。

例子:在Iphone5上,viewCenter是284x160.這樣的話,scrollable area就是:

284x160 到( 4000 - 284) x (500 - 160) = 3716 x 340 points.

換句話說,這個Scrollable Area是level的尺寸減去view的尺寸。這樣,通過scrollable area(levelSize - viewSize)分割viewPos給了你_physicsNode當前位置在scrollable area上的百分比:

CGPoint viewPosPercent = CGPointMake(viewPos.x / (levelSize.width - viewSize.width),viewPos.y / (levelSize.height - viewSize.height));

現在,得到了_physicsNode的位置的范圍(0.0到1.0之間),0.0指的是scrollalbe area的左下角的位置,284x160,1.0指的是右上角的位置 3716x340.下一步必須運用這個百分比在每一個layer上,把每個layer自己的尺寸算進去。

試著計算: 使用568x384作為layerSize的寬和高,并且用568x320作為viewSize的寬和高,計算當viewPosPercent是0.5,0.5的時候,layerPos是多少。

- (void)scrollToTarget:(CCNode*)target {    // 屏幕大小 480 * 320    CGSize viewSize = [CCDirector sharedDirector].viewSize;    // player的中心位置 (240,160)    CGPoint viewCenter = CGPointMake(viewSize.width / 2.0, viewSize.height / 2.0);    // levelNode的size 4000 * 500;    CGSize levelSize = _levelNode.contentSizeInPoints;    //    CGPoint viewPos = ccpSub(target.positionInPoints, viewCenter);    viewPos.x = MAX(0.0, MIN(viewPos.x, levelSize.width - viewSize.width));    viewPos.y = MAX(0.0, MIN(viewPos.y, levelSize.height - viewSize.height));    _physicsNode.positionInPoints = ccpNeg(viewPos);    CGPoint viewPosPercent = CGPointMake(viewPos.x / (levelSize.width - viewSize.width),viewPos.y / (levelSize.height - viewSize.height));    for (CCNode *layer in _backgroundNode.children) {        CGSize layerSize = layer.contentSizeInPoints;        CGPoint layerPos = CGPointMake(viewPosPercent.x * (layerSize.width - viewSize.width), viewPosPercent.y * (layerSize.height - viewSize.height));        layer.positionInPoints = ccpNeg(layerPos);    }}
- (void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event {    //_playerNode.position = [touch locationInNode:self];    [_playerNode stopActionByTag:1];    CGPoint pos = [touch locationInNode:_physicsNode];    CCAction *move = [CCActionMoveTo actionWithDuration:0.2 position:pos];    move.tag = 1;    [_playerNode runAction:move];}

 

試著計算

 

未完待續d 

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 男女无遮挡羞羞视频 | 亚洲成人国产 | 亚欧美一区二区 | 中国美女一级黄色大片 | 日韩视频―中文字幕 | www.精品视频 | 国产免费一级淫片a级中文 99国产精品自拍 | 欧美精品色精品一区二区三区 | 国产成人综合在线观看 | 久久久久久久久成人 | 日韩精品久久久久久久九岛 | 亚洲小视频在线 | 91在线免费观看 | 亚洲成人精品区 | 欧美成人三级大全 | 久久久国产精品免费观看 | 国产亚洲精品久久777777 | 亚洲片在线观看 | 国产一区二区精品91 | 看个毛片| 做羞羞视频 | 中文在线观看免费视频 | 中文字幕激情视频 | 亚洲成人精品一区二区 | 国产精品麻豆91 | 成人午夜在线免费 | 播色网| 国产精品视频一区二区噜噜 | 亚洲精品xxx| 草草视频免费观看 | 中文字幕在线免费播放 | 国产精品一区在线免费观看 | 欧美人禽| av在线免费网 | 欧美福利视频一区二区 | 亚洲国产高清自拍 | 看国产一级毛片 | 中文字幕视频在线播放 | 91精品国产综合久久婷婷香 | www.99热视频 | 九九视频在线观看黄 |