亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

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

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關鍵字??偟膩碚f,聲明一個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?;蛘邠Q句話說,可以滾動的區域是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 

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美日韩精品久久奇米色影视| 欧美人在线观看| 亚洲综合在线做性| 国产亚洲精品久久久久动| 欧美一区二区三区免费视| 国产欧美日韩精品在线观看| 成人两性免费视频| 亚洲午夜精品久久久久久性色| 国产日韩欧美中文| 久久香蕉国产线看观看av| 一个人看的www久久| 欧美色视频日本高清在线观看| 97超级碰碰人国产在线观看| 自拍偷拍亚洲区| 8090成年在线看片午夜| 国产日韩欧美91| 91久久久久久| 欧美午夜无遮挡| 日韩欧美在线免费观看| 动漫精品一区二区| 亚洲经典中文字幕| 亚洲影视中文字幕| 欧美又大又硬又粗bbbbb| 久热精品在线视频| 亚洲视频在线视频| 国产一区二区三区日韩欧美| 成人乱人伦精品视频在线观看| 日韩av免费在线播放| 日本免费久久高清视频| 久久久精品在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 欧美午夜美女看片| 超碰精品一区二区三区乱码| 亚洲欧美精品在线| 中文字幕国产亚洲| 深夜福利亚洲导航| 欧美在线一级va免费观看| 国产99视频精品免视看7| 亚洲一区二区久久久久久| 色妞色视频一区二区三区四区| 尤物九九久久国产精品的分类| 国产精品美女视频网站| 国产精品毛片a∨一区二区三区|国| 国产69精品久久久久9| 日韩av免费在线播放| 国产精品看片资源| 精品国产乱码久久久久久婷婷| 成人精品一区二区三区电影黑人| 欧美国产欧美亚洲国产日韩mv天天看完整| 久久久久免费精品国产| 国产成人一区二| 91地址最新发布| 国产精品96久久久久久又黄又硬| 亚洲第一偷拍网| 亚洲午夜精品视频| 欧美国产第二页| 亚洲激情在线观看| 91在线无精精品一区二区| 亚洲电影免费观看| 在线观看久久av| 疯狂做受xxxx欧美肥白少妇| 亚洲男子天堂网| 亚洲欧美国产制服动漫| 亚洲人成网站色ww在线| 中文字幕一区电影| 亚洲一区二区三| 欧美日韩日本国产| 欧美性生交xxxxx久久久| 国产精品自拍偷拍| 欧美成人免费播放| 亚洲成人精品久久久| 欧洲亚洲在线视频| www.日韩免费| 精品久久久一区| 色综合亚洲精品激情狠狠| 国产美女搞久久| 亚洲欧美一区二区三区情侣bbw| 中文字幕综合在线| xxx欧美精品| 亚洲天堂第二页| 91av在线播放视频| 亚洲精品美女在线观看| 91国产视频在线| 国产一区二区激情| 97视频在线观看亚洲| 91亚洲va在线va天堂va国| 国产精品盗摄久久久| 欧美精品成人在线| 国产日韩在线亚洲字幕中文| 亚洲国产精彩中文乱码av在线播放| 欧美大片欧美激情性色a∨久久| 日韩精品福利网站| 亚洲成人亚洲激情| 欧美日韩加勒比精品一区| 综合国产在线观看| 日韩av网址在线观看| 亚洲女性裸体视频| 国产欧美最新羞羞视频在线观看| 日韩欧美一区二区三区久久| 26uuu另类亚洲欧美日本一| 国产成人在线播放| 日韩精品在线观看网站| 久久精品成人欧美大片古装| 亚洲最大成人网色| 久久精品国产清自在天天线| 在线免费看av不卡| 欧美性极品少妇精品网站| 欧美电影院免费观看| 成人福利在线观看| 久久亚洲精品毛片| 精品久久久久久久久久| 欧美日韩中文在线| 久久在精品线影院精品国产| 免费99精品国产自在在线| 亚洲а∨天堂久久精品9966| 黄色一区二区在线| 色99之美女主播在线视频| 精品久久在线播放| 久久露脸国产精品| 庆余年2免费日韩剧观看大牛| 日本午夜精品理论片a级appf发布| 国产精品一区二区av影院萌芽| 国产精品海角社区在线观看| 国产在线视频欧美| 亚洲欧美国内爽妇网| 色老头一区二区三区在线观看| 午夜精品99久久免费| 欧美一级片久久久久久久| 亚洲热线99精品视频| 亚洲综合在线做性| 欧美噜噜久久久xxx| 午夜精品一区二区三区在线| 成人国产亚洲精品a区天堂华泰| 国产精品视频精品视频| 精品呦交小u女在线| 欧美乱妇高清无乱码| 日韩精品免费综合视频在线播放| 日本免费在线精品| 日韩欧美在线视频免费观看| 久久精品视频导航| 91av国产在线| 97av视频在线| 91大神在线播放精品| www.亚洲男人天堂| 色中色综合影院手机版在线观看| 国产日韩欧美日韩| 91久久精品日日躁夜夜躁国产| www.欧美精品一二三区| 欧美尺度大的性做爰视频| 欧美日韩综合视频| 这里只有精品视频| 亚洲一区中文字幕在线观看| 欧美日韩性生活视频| 一本色道久久88综合日韩精品| 欧美性高潮床叫视频| 欧美激情视频免费观看| 成人欧美一区二区三区黑人孕妇| 欧美精品电影免费在线观看| 国产精品亚洲欧美导航| 日韩av手机在线看| 亚洲欧洲日本专区| 97在线视频精品| 欧美亚洲另类在线| 欧美日韩免费在线观看|