Sprite Kit Actions(二)

Repeat action

重複動作


So far, so good, but what if you want the cat lady to repeat this sequence multiple times? Of course, there’s an action for that!


現在看來還不錯,但是如果你希望老太太多遛幾個彎,當然,我們也有對應的action!


You can repeat an action a certain number of times using repeatAction:count:, or an endless number of times using repeatActionForever:.


你可以通過repeatAction:count:方法重複一個顯存的動作,或者通過repeatActionForever:無限重複下去.


Let’s go with the endless variant. Replace the line that runs your action in spawnEnemy with the following two lines:


來試試無限循環的版本.把spawnEnemy方法中調用action的代碼替換一下:


SKAction *repeat = [SKAction repeatActionForever:sequence]; 
[enemy runAction:repeat];


Congratulations, now you understand many useful types of actions:


恭喜,現在我們已經明白了很多有用的action:


• Move actions 移動
• Sequence actions 序列
• Wait for duration actions 等待
• Run block and selector actions 調用

Reversing actions 反向

• Repeat actions 重複


Next, you’re going to put these all together in a new and interesting way: you’re going to make cat ladies spawn periodically over time, instead of spawning just one cat lady at launch.


接下來嘗試一點新東西:讓老太太隨機出現而不是開始的時候有一個.


Periodic spawning

週期生成


To prepare for periodic spawning, you’ll revert the spawnEnemy code to the original version that simply moves the cat lady from right to left. You’ll also introduce some random variance so the cat lady doesn’t always spawn at the same y-position.


想要週期生成一個sprite,我們需要把spwanEnemy方法恢復到最初那個單純把老老太太龍右往左移的版本.我們還需要用到一些隨機的變量來使老太太站在y軸的不同位置上.


First things first: you need a helper method to generate a random number within a range of values. Add this new method to the top of your file, along with the other math utilities you added in the first challenge in the previous chapter:


首先,我們需要創建一個用來在一定範圍內生成隨機數的輔助方法.把下列方法添加到文件的頂部,把這個方法跟上一章的挑戰中創建的方法放到一起:


#define ARC4RANDOM_MAX 0x100000000
static inline CGFloat ScalarRandomRange(CGFloat min,CGFloat max)
{
    return floorf(((double)arc4random() / ARC4RANDOM_MAX) *(max - min) + min);
}


Next, replace the current version of spawnEnemy with the following


下一步把spawnEnemy方法替換一下:


- (void)spawnEnemy {
     
     SKSpriteNode *enemy = [SKSpriteNode spriteNodeWithImageNamed:@"enemy"];
     enemy.position = CGPointMake( self.size.width + enemy.size.width/2, ScalarRandomRange(enemy.size.height/2,self.size.height - enemy.size.height/2));
     [self addChild:enemy];

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

     [enemy runAction:actionMove];
}


All you did here was modify the fixed y-position to be a random value between the bottom and top of the screen, and revert the movement back to the original implementation. Well, the moveToX:duration: variant of the original implementation, anyway.


這裏我們所做的只不過是把代碼恢復到之前的版本,然後將固定的y左邊改成了一個限定在屏幕內的隨機值.恩...還有這個moveToX:duration:方法...


Now it’s time for some action. Inside initWithSize:, replace the call to spawnEnemy: with the following:


到了搞點動作的時候了.把initWithSize:中調用spawnEnemy:方法的代碼替換成:


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


This is an example of how you can chain actions together inline if you’d like, instead of creating separate variables for each action.


這是一個使用單行代碼的例子,如果你喜歡,可以不需要單獨聲明變量而使用這種形式.


Remove from parent action

用於移出父節點的動作


If you keep the game running for a while, you’ll notice that the node count in the bottom right keeps increasing.


如果你讓遊戲持續運行一段時間,你會注意到右下角的節點數在不斷增加.


A never-ending list of nodes in a game is not a good thing. This node army will eventually consume all of the memory on the device, and the OS will automatically terminate your app, which from a user’s perspective will look like your app crashed.


一個持續增加的節點列表對於遊戲來說不是什麼好事.這些節點大軍最終將導致設備的內存耗盡,然後OS就會自動的終止掉你的程序,從用戶的角度來看,你的程序就這樣崩了...


And as you may have guessed, there’s an action for that, too! When you no longer need a node and can remove it from the scene, you can either call removeFromParent directly, or use the remove from parent action.


可能大家已經猜到了,我們也有用來完成這個動作的action!當你不再需要一個今兒點的時候,你可以把它從場景中移除,也可以直接調用removeFromParent,又或者使用移除動作.


Let’s give this a try. Modify your list of actions in spawnEnemy: like so


一起來試一下.修改一下spawnEnemy:


SKAction *actionMove = [SKAction moveToX:-enemy.size.width/2 duration:2.0];
SKAction *actionRemove = [SKAction removeFromParent];
[enemy runAction:[SKAction sequence:@[actionMove, actionRemove]]];


And now the node count should always stay about constant, regardless of how long you run the game. Ah – much better!


現在無論運行多長時間,節點數量將會始終保持一個常量,世界美好了~


Animation action

動畫動作


This one is super-useful, because adding animations is a super easy way to add a lot of polish and fun to your game.

這東西非常有用,因爲添加動畫是讓遊戲變得光鮮有趣的超級簡單的辦法.


To run an animation action, you first need to gather a list of images called textures that make up the frames of the animation. A sprite has a texture assigned to it, but you can always swap out the texture with a different one at runtime by setting the texture property on the sprite.


想要使用動畫首先需要有一幀一幀的連續圖片,我們稱之爲材質.一個sprite開始就會被指派一個材質,但是你可以通過修改texture屬性來動態的修改sprite的材質.


In fact, this is what animations do for you – automatically swap out your sprite’s textures over time, with a slight delay between each.


事實上,這正是動畫所做的事 — 沒隔一段時間切換一張材質圖片.


Zombie Conga already includes some animation frames for the zombie. you have four textures to use as frames to show the zombie walking.


項目中已經包含了一些殭屍的動畫材質,你有4張材質圖片來顯示殭屍的移動.(Zombie1~4)


You can then repeat this endlessly for a continuous walk animation.


接下來可以無線循環這些圖片來實現一個連續的行走動畫.


Give it a shot. First create a private instance variable for the zombie action:


試一下,第一步爲殭屍的動作創建一個私有成員:


SKAction *_zombieAnimation;


Then add the following code to initWithSize:, right after adding the zombie as a child to the scene:


然後在initWithSize:中添加殭屍節點的代碼下方添加下列代碼:


// 1
NSMutableArray *textures = [NSMutableArray arrayWithCapacity:10];
// 2
for (int i = 1; i < 4; i++) { 
    NSString *textureName = [NSString stringWithFormat:@"zombie%d", i]; 
    SKTexture *texture = [SKTexture textureWithImageNamed:textureName]; 
    [textures addObject:texture];
}
// 3
for (int i = 4; i > 1; i--) {
    NSString *textureName = [NSString stringWithFormat:@"zombie%d", i]; 
    SKTexture *texture = [SKTexture textureWithImageNamed:textureName]; 
    [textures addObject:texture];
}
// 4
_zombieAnimation = [SKAction animateWithTextures:textures timePerFrame:0.1];
// 5
[_zombie runAction: [SKAction repeatActionForever:_zombieAnimation]];


2.The animation frames are named zombie1.png, zombie2.png, zombie3.png, and zombie4.png. This makes it nice and easy to create a loop that creates a string for each image name, and then makes a texture object from each name using SKTexture’s textureWithImageNamed: constructor.


動畫材質的名字是zombie1~4.png.這種命名方式使得創建材質循環變得更加容易,然後通過SKTexture的textureWithImageNamed:方法來創建材質對象.


3. The first for loop adds frames 1 to 3, which is most of the “forward walk.” This for loop reverses the order and adds frames 4 to 2 to create the “backward walk” animation.


第一個循環添加了第1~3幀來創建”前進”的部分.這個循環則逆序添加了4~2來創建”後退”的動畫.


Stopping action

停止動作


Your zombie’s off to a good start, but one annoying thing is that when the zombie stops moving, his animation keeps running. Ideally, you’d like to stop the animation when the zombie stops moving.


你的殭屍有了個不錯的開始,但是有個討厭的事 — 當殭屍的位置不在改變時依舊還在走太空步,真當自己是傑克遜了...我們需要的是當殭屍停止移動的時候動畫也應該對應的停止.


In Sprite Kit, whenever you run an action, you can give the action a key simply by using a variant of the runAction: method called runAction:withKey:. This is handy because then you can stop the action later by calling removeActionForKey:.


在Sprite Kit中,無論你何時想用一個動作,你都可以用runAction:方法的變種runAction:withKey:來給動畫一個key.這樣就可以通過removeActionForKey:方法來停止這個動作.


Give it a shot by adding these two new methods:


試着添加這樣兩個方法:


- (void)startZombieAnimation { 
    if (![_zombie actionForKey:@"animation"]) 
        { 
            [_zombie runAction: [SKAction repeatActionForever:_zombieAnimation] withKey:@"animation"]; 
        } 
} 

- (void)stopZombieAnimation { 
[_zombie removeActionForKey:@"animation"]; 
} 


Now, go to initWithSize: and comment out the line that ran the action there:


現在,註釋掉initWithSize:方法中運行action的方法:


//[_zombie runAction:
// [SKAction repeatActionForever:_zombieAnimation]];


Call startZombieAnimation at the beginning of moveZombieToward::


調用startZombieAnimation來讓殭屍開始動畫:


[self startZombieAnimation];


And call stopZombieAnimation inside update:, right after the line of code that sets _velocity = CGPointZero:


然後在update:方法中_velocity=CGPointZero;這行代碼的下面調用stopZombieAnimation方法.


and now your zombie will only move when he should!


現在,你的殭屍只會在需要的時候移動了.



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