sprite Kit Actions(三)

感覺一輩子都沒打過這麼多字了...


Scale action

縮放動作


You now have an animated zombie and some crazy cat ladies, but the game is missing one very important element – cats! Remember that the purpose of the game is for the player to gather as many cats as he can into the zombie’s conga line.


現在你有了一個可以動的殭屍和一些瘋老太太,但是這個遊戲仍然有一個重要的缺失 — 喵星人!要記得這個遊戲是讓玩家收集儘可能多的貓來跟殭屍一起跳舞.


In Zombie Conga, the cats won’t move from right to left like the cat ladies do – instead, they will appear at a random location on the screen and stay stationary. Rather than have them appear instantly, which would be jarring, you’ll have them start at a scale of 0 and grow to a scale of 1 over time. This will make the cats appear to “pop in” to the game.


在遊戲中,喵星人不會像老太太一樣從右往左移動,而是隨機出現在一個隨機的位置然後待在那裏.爲了防止他們突然出現而讓玩家感到突兀,我們需要讓他們的比例從0到1進行縮放.這會讓它們有一種”彈出”式的效果.


To implement this, add the following new method:


添加下列代碼來實現該功能:


- (void)spawnCat {
    // 1
    SKSpriteNode *cat = [SKSpriteNode spriteNodeWithImageNamed:@"cat"];
    cat.position = CGPointMake(ScalarRandomRange(0, self.size.width), 
            ScalarRandomRange(0, self.size.height));
    cat.xScale = 0;
    cat.yScale = 0; 
    [self addChild:cat];
    // 2
    SKAction *appear = [SKAction scaleTo:1.0 duration:0.5]; 
    SKAction *wait = [SKAction waitForDuration:10.0];
    SKAction *disappear = [SKAction scaleTo:0.0 duration:0.5]; 
    SKAction *removeFromParent = [SKAction removeFromParent]; 
    [cat runAction:[SKAction sequence:@[appear, wait, disappear, removeFromParent]]];
}


1. You create a cat at a random spot on the screen. Note that you set the xScale

and yScale to 0, which makes the cat 0 size – effectively invisible.


我們在屏幕上的隨機位置放了一隻貓.注意我們設置x和y軸的縮放比例都是0,這讓貓的大小變成了0,也就是不可見狀態.


2. You create an action to scale the cat up to normal size by calling the scaleTo:duration: constructor. This action is not reversible, so you also create a similar action to scale the cat back down to 0. The sequence is the cat appears, waits for a bit, disappears, and is then removed from the parent.


這一段我們通過scaleTo:duration:方法來創建了一個把貓縮放到正常大小的動作.這個動作是不可逆的,所以我們還需要創建一個縮放方法來把它縮放回0.這個序列讓貓出現,等待一段時間,然後消失,最後從屏幕移除.


You want the cats to spawn continuously from the start of the game, so add the following inside initWithSize:, just after the line that spawns the enemies:


我們希望在遊戲中持續的放置小貓,那就需要在initWithSize:方法生成老太太的代碼下面添加:


[self runAction:[SKAction repeatActionForever: [SKAction sequence:@[[SKAction
                performSelector:@selector(spawnCat) onTarget:self],
                [SKAction waitForDuration:1.0]]]]];


This is very similar to how you spawned the enemies. You simply run a sequence that calls spawnCat, waits for one second and then repeats.


這跟生成老太太的方法非常相似.簡單的運行一個創建小貓,然後等待一秒的動作序列,然後重複執行.


You should be aware of a few other variants of the scale action:


我們需要知道縮放動作的其他幾個變種:


scaleXTo:duration:, scaleYTo:duration:, and scaleXTo:y:duration:: These allow you to scale just the x-axis or y-axis of a node independently, which you can use to stretch or squash a node.


scaleXTo:duration:,scaleYTo:duration:和scaleXTo:y:duration:,這些方法可以方便的單獨調整x軸,y軸的縮放比例.


scaleBy:duration:: The “by” variant of scaling, which multiples the passed-in scale by the current node’s scale. For example, if the current scale of a node is 1.0, and you scale it by 2.0, it is now at 2x. If you scale it by 2.0 again, it is now at 4x. Note that you could not use scaleBy:duration: in the previous example, because anything multiplied by 0 is still 0!


scaleBy:duration:這個”按倍縮放”的變種可以基於當前的縮放比例來進行縮放.舉個例子,如果當前比例是1.0,然後我們把它縮放2.0倍,那麼就會被縮放到2x.如果再次縮放2.0倍,就會被縮放爲4x.需要注意的是在這個例子裏我們不能用這個方法,因爲0縮放幾倍都是0.


• scaleXBy:y:duration:: Another “by” variant, but this one allows you to scale x and y independently.


scaleXBy:y:duration:另一個按倍縮放的變種,區別在於他可以獨立的縮放x和y軸比例.


Rotate action

旋轉動作


The cats in this game should be appealing to the player to try to pick up, but right now they’re just sitting motionless.


這些貓應該是要吸引玩家來收集他們的,但是他們現在只是傻傻的待在那裏.


Let’s give them some charm by making them wiggle back and forth while they sit.


讓我們來添加一些有意思的效果,讓他們在屏幕上的時候來回的搖擺~(哈林:選我選我選我~~)


To do that, you’ll need the rotate action. To use it, you call the rotateByAngle:duration: constructor, passing in the angle (in radians) by which to rotate. Replace the list of actions in spawnCat with the following:


我們需要用到旋轉動作來實現這一效果.調用rotateByAngle:duration:並指定要旋轉的角度.用下列代碼來替換spawnCat方法中的代碼:


cat.zRotation = -M_PI / 16;
SKAction *appear = [SKAction scaleTo:1.0 duration:0.5];
SKAction *leftWiggle = [SKAction rotateByAngle:M_PI / 8 duration:0.5]; 
SKAction *rightWiggle = [leftWiggle reversedAction];
SKAction *fullWiggle =[SKAction sequence: @[leftWiggle, rightWiggle]];
SKAction *wiggleWait = [SKAction repeatAction:fullWiggle count:10];
//SKAction *wait = [SKAction waitForDuration:10.0];
SKAction *disappear = [SKAction scaleTo:0.0 duration:0.5]; 
SKAction *removeFromParent = [SKAction removeFromParent]; 
[cat runAction:[SKAction sequence:@[appear, , disappear, removeFromParent]]];


Now the cat has wiggled left and right and is back to its start position. This “full wiggle” takes one second total, so in wiggleWait you repeat this 10 times to have a 10-second wiggle duration.


現在小貓會左右搖擺了,依次完整的擺動需要耗時1秒鐘,所以重複10詞,正好停留10秒鐘.


Group action

動作組


So far you know how to run actions one after another in sequence, but what if you want to run two actions at the exact same time? For example, in Zombie Conga you want to make the cat wiggle and scale up and down slightly as he’s wiggling.


現在我們知道了如何利用序列來執行一個一個的動作,但是怎麼讓兩個動作同時執行?舉個例子,遊戲中你希望貓在搖擺的同時進行些微縮放.


For this sort of multitasking, you can use something called the group action. It works in a similar way to the sequence action, where you pass in a list of actions. However, instead of running them one at a time, a group action runs them all at once.


爲了解決之歌多任務問題,我們可以使用動作組.有點類似動作序列.區別在於序列是一個一個運行,而組是同時運行.


Let’s try this out. Replace the list of actions in spawnCat with the following:


試一下,把spawnCat中的內容替換成下面的代碼:


SKAction *appear = [SKAction scaleTo:1.0 duration:0.5];
SKAction *leftWiggle = [SKAction rotateByAngle:M_PI / 8 duration:0.5]; SKAction *rightWiggle = [leftWiggle reversedAction];
SKAction *fullWiggle =[SKAction sequence: @[leftWiggle, rightWiggle]];
//SKAction *wait = [SKAction waitForDuration:10.0];

//SKAction *wiggleWait =
// [SKAction repeatAction:fullWiggle count:10];

SKAction *scaleUp = [SKAction scaleBy:1.2 duration:0.25];
SKAction *scaleDown = [scaleUp reversedAction];
SKAction *fullScale = [SKAction sequence:@[scaleUp, scaleDown, scaleUp, scaleDown]];

SKAction *group = [SKAction group:@[fullScale, fullWiggle]];
SKAction *groupWait = [SKAction repeatAction:group count:10];
SKAction *disappear = [SKAction scaleTo:0.0 duration:0.5]; 
SKAction *removeFromParent = [SKAction removeFromParent]; 
[cat runAction:[SKAction sequence:@[appear, , disappear, removeFromParent]]];


The duration of a group action is equal to the longest duration of any of the actions it contains. So if you add one action that takes one second, and another that takes 10 seconds, both actions will begin to run at the same time, and after one second the first action will be complete. The group action will continue to execute for nine more seconds until the other action is complete.


動作組的持續時間與組中最長的動作的持續時間相同.所以如果你添加了一個1秒的動作和一個10秒的動作,兩個動作會同時執行,1秒之後第一個動作就結束了,但是動作組會繼續執行9秒,直到另一個動作完成.


Collision detection

碰撞檢測


You’ve got a zombie, you’ve got cats, you’ve even got crazy cat ladies – but what you don’t have is a way to detect when they collide.


我們有了殭屍,有了貓,也有了老太太,但是我們沒有檢測他們碰撞的機制


There are multiple ways to detect collisions in Sprite Kit, including using the built-in physics engine, as you’ll learn in Chapter 9, “Intermediate Physics”. In this chapter, you’ll take the simplest and easiest approach: bounding box collision detection.


在Sprite Kit中有很多種辦法來做碰撞檢測,包括第9章將要講到的內置的物理引擎.在這一章我們將會使用最簡單的實現方法,邊界檢測.


There are three basic ideas you’ll use to implement this:


這裏有三個基本思路:


You need a way of getting all of the cats and crazy cat ladies in a scene into lists so that you can check for collisions one-by-one. An easy way to do this is to give nodes a name when you create them. Then you can use the enumerateChildNodesWithName:usingBlock: method on the scene to find all of the nodes with a certain name.


我們需要建立一個在場景中所有需要進行碰撞檢測的貓和老太太的索引列表.最簡單的辦法是在創建的時候給每個節點一個名字.然後就可以通過enumerateChildNodesWithName:usingBlock:方法來找到一個擁有既定名字的節點.


2. Once you have the lists of cats and cat ladies, you can loop through them to check for collisions. Each node has a frame property that gives you a rectangle representing where the node is onscreen.

一旦我們建立了這個索引列表就可以循環遍歷他們來進行碰撞檢測了.每一個節點都包含一個frame屬性用來標記他們在屏幕上的位置.


3. If you have the frame for either a cat lady or a cat, and the frame for the zombie, you can use the built-in method CGRectIntersectsRect to see if they collide.


如果我們得到了貓,老太太和殭屍的frame,我們就可以使用內建的CGRectIntersectsRect方法來進行碰撞檢測.


Let’s give this a shot. First you need to set the name for each node. Inside spawnEnemy, right after creating the enemy sprite, add this line:


一起來試一下.第一步給每一個節點一個名稱.在spawnEnemy方法中創建老太太的代碼後邊添加下面這行代碼:


enemy.name = @"enemy";


Similarly, inside spawnCat, right after creating the cat sprite, add this line:


同樣的 ,在spawnCat方法中創建小貓的代碼後邊添加下邊的代碼:


cat.name = @"cat";


Then add this new method to the file:


添加下面這個新的方法:


- (void)checkCollisions {
    [self enumerateChildNodesWithName:@“cat" usingBlock:^(SKNode *node, BOOL *stop){
        SKSpriteNode *cat = (SKSpriteNode *)node;
        if (CGRectIntersectsRect(cat.frame, _zombie.frame)) 
        {
            [cat removeFromParent]; 
        }
    }];

    [self enumerateChildNodesWithName:@“enemy" usingBlock:^(SKNode *node, BOOL *stop){
        SKSpriteNode *enemy = (SKSpriteNode *)node;
        CGRect smallerFrame = CGRectInset(enemy.frame, 20, 20); 
        if (CGRectIntersectsRect(smallerFrame, _zombie.frame)) 
        {
            [enemy removeFromParent]; 
        }
    }]; 
}


Here you enumerate through any child of the scene that has the name “cat” or “enemy” and cast it to an SKSpriteNode, since you know it is a sprite node if it has that name.


這裏我們遍歷了所有叫做”cat”或者”enemy”的子節點,同時由於我們知道他們的類型,我們把這些節點轉換成了SKSpriteNode.


You then check if the frame of the cat or enemy intersects with the frame of the zombie. If there is an intersection, you simply remove the cat or enemy from the scene.


然後我們檢查了貓或者殭屍是否與殭屍相撞.如果他們相交了,就把他們從場景裏面移除.


Also, notice that you do a little trick for the cat lady. Remember that the frame of a sprite is the entire image of the sprite, including transparent space:


另外,我們需要解決這個老太太的一點問題.要知道sprite的frame是整個圖片,包括了透明的部分.


So that means that transparent space at the top of the cat lady image would “count” as a hit if the zombie went into that area. Totally unfair!


所以這意味着當殭屍碰到了老太太上部的透明區域時也會視爲發生碰撞.這太不公平了!


To resolve this, you shrink the bounding box a little bit by using the CGRectInset method. It’s still not perfect, but it’s a start. You’ll learn a better way to do this in Chapter 10, “Advanced Physics”.


爲了解決這個,我們需要通過CGRectInset方法來收縮邊界,但是這仍然不是那麼完善,姑且這麼處理吧.我們在第10章的時候將會學習到更好的辦法.


Add the following call to this method at the end of update::


添加下面的代碼到update:方法的底部:


[self checkCollisions];


Build and run, and now when you collide with the cats or enemies they disappear from the scene. It’s your first small step toward the zombie apocalypse!


編譯運行以下,現在當貓和老太太與殭屍發生接觸的時候就會被吃掉了~恩...殭屍末日就要到了~


The Sprite Kit game loop, round 2

SpriteKit遊戲循環2


There’s a slight problem with the way you’re doing the collision detection here that I should point out, which is related to how Sprite Kit’s game loop and actions interrelate.


這裏我需要指出一個處理碰撞檢測時與Sprite Kit遊戲循環和動作打斷相關的的小問題.


The last time you saw the Sprite Kit game loop, you saw that the update: method gets called, then some “other stuff” occurs, and finally Sprite Kit renders the screen:


上一次我們在介紹Sprite Kit的遊戲循環時提到,首先調用update:方法,然後一些其他的東西被調用,最後Sprite Kit纔會繪製屏幕.


Well, it turns out that one of the things in the “other stuff” section is evaluating the actions that you’ve been learning about in this chapter:


於是乎,引出了在”其他東西”這部分中的一些內容 — 動作評估:


(Sprite Kit遊戲循環:update: —> SKScene evaluates actions —> -didEvaluateActions —> other stuff —> SpriteKit renders screen)


This leads to the problem with the way you’re currently doing collision detection. You check for collisions at the end of the update: loop, but Sprite Kit doesn’t evaluate the actions until after this update: loop. Therefore, your collision detection code is always one frame behind!


這就引出了目前碰撞檢測機制中的問題.我們在update:結束的時候進行碰撞檢測.但是Sprite Kit在update:結束之前是不會對動作進行評估的.因此,我們的碰撞檢測代碼永遠會落後一幀.


As you can see in the updated event loop diagram, a much better place to perform the collision detection would be after Sprite Kit evaluates the actions and all the sprites are in their new spots. So comment out the call at the end of update::


就像你在上面的圖例(序列),更好的處理碰撞檢測的位置應該在Sprite Kit對動作評估結束之後,同時所有的sprite都在他們的新位置之後.所以註釋掉update:方法最後的方法調用.


//[self checkCollisions];


And implement didEvaluateActions as follows:


然後在didEvaluateActions方法中重新調用:


-(void)didEvaluateActions 
{
    [self checkCollisions];
}


You probably won’t notice much difference in this case because the frame rate is so fast that it is hard to tell it was behind – but in some games this may be more noticable so it’s good to do things properly.


你可能並不能察覺到這兩種方式的區別,畢竟繪製幀的速度實在太快了所以你沒辦法說看出究竟實在之前還是之後 — 但是在有些遊戲中可能就會比較容易察覺到,所以先這樣適當的修改還是適當的.


注:書中沒有細講關於evaluates actions這個階段究竟做了什麼,譯者在這裏也無法做過多解釋,如果之後看到相關的內容會進行相關補充.


Sound action

音效動作


The last type of action you’ll learn about in this chapter also happens to be one of the most fun – the one that plays sound effects!


本章要學習的最後一個動作也是最有意思的一個就是聲音效果!


Using the playSoundFileNamed:waitForCompletion: action, playing a sound effect with Sprite Kit takes just one line of code. Note that the node on which you run this action doesn’t matter, so typically you’ll just run it as an action on the scene itself.


使用playSoundFileNamed:waitForCompletion:action方法,使用Sprite Kit播放聲音特效只需要1行代碼.值得注意的是究竟是用哪個節點來播放聲音並不重要,所以通常來說都是由場景本身來調用的.


You’ve already added the sounds to your project earlier, so you just need to write the code. Inside checkCollisions, add the following line just after [cat removeFromParent];:


之前我們已經把聲音資源添加到了項目中,所以只需要寫幾行代碼.在checkCollisions方法中,添加一行代碼到[cat removeFromParent]之後:


[self runAction:[SKAction playSoundFileNamed:@"hitCat.wav" waitForCompletion:NO]];


Then add this line just after [enemy removeFromParent];:


然後添加一行代碼到[enemy removeFromParent];之後:


[self runAction:[SKAction playSoundFileNamed:@"hitCatLady.wav" waitForCompletion:NO]];


Here you play the appropriate sound action for each type of collision. Build and run, move the zombie around and enjoy the sounds of the smash-up!


這樣我們就會在不同碰撞的時候播放對應的音樂.編譯運行,讓殭屍跑起來然後享受天災的怒吼把…(不禁想起了復仇者聯盟中美國隊長跟綠巨人說的那句話…Smash~)


Sharing actions

公用動作


In the previous section, you may have noticed a slight pause the first time the sound plays. This can occur when the sound system is initialized the first time it is used. The solution to this problem also demonstrates one of the most powerful features of Sprite Kits actions: sharing.


在上一節中,你可能注意到了在第一次播放聲音的時候會有一點點停頓.這是因爲在第一次播放聲音時需要對聲音系統初始化造成的.這裏我們要介紹一個Sprite Kit中最強大的功能來解決這個問題 — 公用.


The SKAction object does not actually maintain any state itself, and that allows you to do something cool – reuse actions on any number of nodes simultaneously! For example, the action you create to move the cat ladies across the screen looks something like this:


SKAction對象並不會自己保持某一種狀態,這就讓我們可以做一些這樣或者那樣的事了...比方說讓任意數量的節點同時重用一些動作!舉個例子,我們創建的用來移動老太太的動作是這樣的:


SKAction *actionMove = [SKAction moveToX:-enemy.size.width/2 duration:2.0];


But you create this action for every cat lady. Instead, you could create a private or static SKAction variable, store this action in it, and then use that variable wherever you are currently using actionMove.


但是你爲每一個老太太都創建了這樣一個動作.但是我們實際上可以創建一個私有的靜態變量用來儲存這個SKAction,然後在任意需要使用這個動作的時候使用它.


In fact, you could modify Zombie Conga so it reuses most of the actions you’ve created so far. Doing so would reduce the amount of memory your system uses, but that’s a performance improvement you probably don’t need to make in such a simple game. You’ll learn more about things like this in Chapter 25, “Performance.”


實際上,我們可以重構遊戲中之前創建的大部分動作.這樣可以節省大量的內存消耗,但是這可能這種級別的遊戲中我們並不需要用到這樣的性能優化.我們在25章中將進一步探討關於性能的問題.


But how does this relate to the sound delay?


但是爲什麼這會造成音效延遲?


The application is loading the sound the first time you create an action that uses it. So to prevent the sound delay, you can create the actions in advance and then use them when necessary.


程序會在你第一次使用一個動作的時候載入音效.所以爲了防止音效延遲,你可以預先創建一個動作然後當合適的時候使用.


Create the following private variables:


創建以下兩個私有變量:


SKAction *_catCollisionSound; 
SKAction *_enemyCollisionSound;


These variables will hold shared instances of the sound actions you want to run.


這些變量將會持有共享的音效實例的引用.


Now create the sound actions by adding the following lines at the end of initWithSize:, just after the line that runs the action that calls spawnCat:


現在在initWithSize:方法的最後添加創建聲音特效的代碼:


_catCollisionSound = [SKAction playSoundFileNamed:@"hitCat.wav" waitForCompletion:NO];
_enemyCollisionSound =[SKAction playSoundFileNamed:@“hitCatLady.wav" waitForCompletion:NO];


These are the same actions you create in checkCollisions, but now you create them just once for the scene. That means your app will load these sounds as soon as the scene is initialized.


這些是與我們在checkCollisions方法中創建的動作完全一樣,但是現在我們只需要爲這個場景創建他們一次.這就可以讓你的軟件在初始化場景的時候加載這些音效.


Finally, find this line in checkCollisions:


最後找到checkCollisions中的這行代碼:


[self runAction:[SKAction playSoundFileNamed:@"hitCat.wav" waitForCompletion:NO]];


Replace the above line with this one:


把上邊的代碼替換成爲:


[self runAction:_catCollisionSound];


Also find this line:


然後找到這行代碼:


[self runAction:[SKAction playSoundFileNamed:@"hitCatLady.wav" waitForCompletion:NO]];


And replace it with this one:


替換成爲:


[self runAction:_enemyCollisionSound];


Build and run again. You should no longer experience any pauses before the sound effects play.


重新編譯運行,程序再也不會因爲播放音效而變卡了.


Challenges

挑戰


Be sure to do these challenges. As a Sprite Kit developer you will be using actions all the time, so it’s important to get some practice with them before moving further.


確保完成這些挑戰!作爲一個SpriteKit開發這你將會一直在使用actions,所以再深入學習之前進行足夠的練習是必要的.


Challenge 1: The ActionsCatalog demo

挑戰1:動作目錄示例


This chapter covers the most important actions in Sprite Kit, but it doesn’t cover all of them. To help you get a good understanding of all the actions that are available to you, I’ve created a little demo called ActionsCatalog, which you can find in the resources for this chapter.


這一章包含了Sprite Kit中最重要的動作,但是並沒有包含全部.爲了幫助你更好的瞭解所有可用的actions,我做了一個demo,可以在資源文件中知道他們.


Your challenge is to flip through each of these demos, then take a look at the code to answer the following questions:


你的挑戰是瀏覽demo中的每一個動作,然後回答下列問題:


What action constructor would you use to make a sprite follow a certain pre-defined path?


使用哪一個構造方法來讓sprite按照一個既定路線移動


2. What action constructor would you use to make a sprite 50% transparent, regardless of what its current transparency settings are?


使用哪個構造方法可以忽略當前的透明度,而把sprite的透明度設置爲50%,


3. What are “custom actions” and how do they work at a high level?


自定義動作是什麼?有什麼高級應用?


Challenge 2: An invincible zombie

挑戰2:無敵殭屍


Your challenge is to modify the game to do just this. When the zombie collides with a cat lady, he should become temporarily invincible instead of destroying the cat lady.


你的挑戰是修改程序,當殭屍與老太太發生碰撞的時候會變成一個臨時的無敵狀態,而不是吃掉這個老太太.


While the zombie is invincible, he should blink. To do this, you can use the custom blink action that is included in ActionsCatalog. Here’s the code for your convenience:


在殭屍的無敵持續時間內他應該保持閃爍.你可以用demo中的自定義閃爍動作來實現.這裏有些方便使用的代碼:


float blinkTimes = 10; 
float blinkDuration = 3.0; 
SKAction *blinkAction = [SKAction customActionWithDuration:blinkDuration actionBlock:
    ^(SKNode *node, CGFloat elapsedTime) {
    float slice = blinkDuration / blinkTimes; 
    float remainder = fmodf(elapsedTime, slice); 
    node.hidden = remainder > slice / 2;
}];


Challenge 3: The conga train

挑戰3:拍火車


This game is called Zombie Conga, but there’s no conga line to be seen just yet!


這個遊戲叫做殭屍康茄舞,但是現在並沒有一個康茄舞的隊伍!


Your challenge is to fix that. You’ll modify the game so that when the zombie collides with a cat, instead of disappearing, the cat joins your conga line!


你的挑戰就是修正這一問題.修改遊戲,當殭屍與一隻貓發生了碰撞,不是讓貓消失,而是讓貓加入這個隊伍!


Here are the steps to implement this challenge:


這裏有幾個實現步驟:


1.Create a constant float variable to keep track of the cat’s move points per second at the top of the file. Set it to 120.0.


在文件頂部創建一個float類型的常量來追蹤小貓們每秒要移動的點,設置爲120.0


2. Set the zombie’s zPosition to 100. This makes the zombie appear on top of the other sprites. Larger z values are “out of the screen” and smaller values are “into the screen”, and the default value is 0.


設置殭屍的zPosition屬性爲100.這會讓殭屍顯示在所有其他sprite的上面.越大的z數字代表的理屏幕越遠,數字越小則越近,默認爲0.


3. When the zombie collides with a cat, don’t remove the cat from the scene. Instead, do the following:


當殭屍與貓發生碰撞時,不要把貓從屏幕上移除,而是做這麼幾件事:


Set the cat’s name to “train” (instead of “cat”).


把貓的名字由”cat”改爲”train”


b. Stop all actions currently running on the cat by calling removeAllActions. 


調用removeAllActions把所有作用於這隻貓的動作停止.


c. Set the scale to 1 and rotation of the cat to 0.


設置縮放比例爲1,旋轉角度爲0.


d. Run an action to make the cat turn green over 0.2 seconds. If you’re not sure what action to use for this, check out ActionsCatalog.


運行一個動作,讓cat在0.2秒的時間內變爲綠色.如果不知道用身什麼,可以參見之前的demo.


4. Make a new method called moveTrain. The basic idea for this method is that every so often, you make each cat move toward where the previous cat currently is. This creates a conga line effect!


創建一個新的方法叫做moveTrain.通常這個方法的基本想法是讓每一隻貓移動到上一隻貓的位置,這就創建了一個康茄舞隊伍的效果(殭屍貪吃蛇…)


Use the following template:


使用下面的模板:


-(void)moveTrain 
{
    __block CGPoint targetPosition = _zombie.position; 
    [self enumerateChildNodesWithName:@“train" usingBlock:^(SKNode *node, BOOL *stop)
        {
            if (!node.hasActions) 
            {
                float actionDuration = 0.3; 
                CGPoint offset = // a
                CGPoint direction = // b
                CGPoint amountToMovePerSec = // c 
                CGPoint amountToMove = // d 
                SKAction *moveAction = // e
                [node runAction:moveAction]; 
            }
            targetPosition = node.position; 
        }];
}


You need to fill in a through d by using the math utility functions you created last chapter, and e by creating the appropriate actions.


你需要通過上一張創建的數學方法計算給a到d的值,然後創建一個適當的動作給e


5. Call moveTrain at the end of update:.


在update:方法的最後調用moveTrain方法


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章