Sprite Kit Actions(一)

来源:互联网 发布:关于网络的作文 高中 编辑:程序博客网 时间:2024/05/16 18:32

So far, you have learned how to move or rotate Sprite Kit nodes – a node being anything that appears onscreen – by manually setting their position and rotation over time.


截至目前,我们学会了如何通过不断的手动调节来移动或者旋转屏幕上的节点节点.


This do-it-yourself approach works and is quite powerful, but Sprite Kit provides an easier way to move sprites incrementally: actions.


这些通过DIY来实现效果的方式非常有效,也非常强大,但是SpriteKit提供了一种更简单的实现方式:actions(动作,感觉还是保留原文更方便).


Actions are great because they allow you to do things like rotate, scale or change a sprite’s position over time with just one line of code! You can also chain actions together to create some neat movement combinations quite easily.


Actions非常强大,紧紧一句话!就可以让你的sprite转身,缩放,或者慢慢移动到某一个位置~还可以非常简单的把一系列action连起来,让你的sprite在屏幕上翩翩起舞~


Move action

移动


Right now your zombie’s life is a bit too carefree, so let’s add some action into this game by introducing some enemies to dodge – crazy cat ladies!


现在我们的僵尸似乎有点太悠然自得了,试试通过action来给他点东西去躲—疯猫奶奶(图片确实是个老奶奶…为什么咱就想不出万磁王,魔形女这种名字呢…理科生的脑子伤不起啊~)


Open MyScene.m and create the start of a new method to spawn an enemy:


打开MyScene.m文件,创建一个生成敌人的方法:


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


Now, you’d like to move the enemy from the right of the screen to the left. If you were doing this manually, you might update the enemy’s position each frame according to a velocity.


现在我们需要把她从屏幕的右边往左边移动.如果要手动实现,我们需要根据速率来更新她每一帧的位置.


No need to trouble yourself with that this time! Simply add these two lines of code to the bottom of spawnEnemy:


但是这次就没有这么麻烦啦!只需要在spawnEnemy:方法最后添加两行代码:


SKAction *actionMove = [SKAction moveTo:CGPointMake(-enemy.size.width/2,enemy.position.y) duration:2.0]; [enemy runAction:actionMove];


To create an action in Sprite Kit, you call one of several static constructors on the SKAction class, such as the one you see here, moveTo:duration:. This particular constructor returns an action that moves a sprite to a specified position, over a specified duration (in seconds).


想要通过SpriteKit创建一个action,需要调用SKAction类的一个静态方法,比如说moveTo:duration:.它返回了一个在一定持续时间(秒)内让sprite移动到指定位置的简单action.


Here you set up the action to move the enemy along the x-axis at whatever speed is necessary to take it from its current position to just off the left side of the screen in two seconds.


这样就设定了一个让老太太在辆秒内移到屏幕外侧的action,至于什么速度?管他呢...


Give it a try! For now, just call this method inside initWithSize:, right after calling [self addChild:_zombie]:


试一下,现在只需要在initWithSize:方法调用加刚才的方法:


[self spawnEnemy];


Build and run, and you should see the crazy cat lady race across the screen:


运行以下,你可以看到老太太在屏幕上慢慢走过了~


Not bad for just two lines of code, eh? You could have even done it with a single line of code if you didn’t need to use the actionMove variable for anything else.


只需要两行代码,是不是感觉不错?如果你不需要actionMove做其他的什么操作的话,只需要一行代码就够了.


Here you saw an example of moveTo:duration:, but there are a few other move action variants:


这里我们演示了moveTo:duration:方法的例子,其实还有很多其他的类似的方法:


moveToX:duration: and moveToY:duration: These allow you to specify a change in only the x or y position – the other is assumed to remain the same. You could have used moveToX:duration: in the example above, to save a bit of typing.


moveToX:duration:和moveToY:duration:这两个方法允许你只指定x或者y轴的坐标,未指定的轴坐标将保持不变,上边的例子就可以使用moveToX:duration.


moveByX:y:duration: The “move to” actions move the sprite to a particular point, but sometimes it’s convenient to move a sprite as an offset from its current position, wherever that may be. You could have used moveByX:y:duration for this example, passing -(self.size.width + enemy.size.width) for x and 0 for y.


moveByX:y:duration:刚才”移动到”的动作让sprite移动到一个确定的点,但是有些时候让sprite根据当前的位置进行偏移会更加方便.向x传递-(self.size.width+enemy.size.width),给y一个0,就可以用这个方法替代上边的方法了.


You’ll see this pattern of “[action] to” and “[action] by” variants for other action types as well. In general, you can use whichever of these is more convenient for you – but keep in mind that if either works, the “[action] by” actions are preferable because they are reversible. 


你会看到在其他的action中看到很多同样的”to”和”by”模式,通常来讲,哪个对你更方便就可以用哪个,但是需要注意的是如果两个方法都可以用,推荐使用”by”,因为他是可逆的.(恩...跟结扎手术差不多的道理…).


Sequence action

动作队列


The real power of actions lies in how easily you can chain them together. For example, say you want the cat lady to move in a V – down toward the bottom of the screen, then up to the goal position.


actions真正的强大之处在于关联他们的方式简单到令人发指!举个例子,你希望老太太走一个V字形,移动到屏幕的底端,然后再往指定的位置走.


To do this, replace the lines that create and run the move action in spawnEnemy with the following:


只需要把spawnEnemy方法中创建移动action的代码替换一下就搞定了:


// 1SKAction *actionMidMove =[SKAction moveTo:CGPointMake(self.size.width/2,enemy.size.height/2)duration:1.0];// 2SKAction *actionMove =[SKAction moveTo:CGPointMake(-enemy.size.width/2,enemy.position.y) duration:1.0];// 3SKAction *sequence =[SKActionsequence:@[actionMidMove, actionMove]];// 4[enemy runAction:sequence];


The sequence action is one of the most useful and commonly used actions – chaining actions together is just so powerful! You will be using the sequence action many times in this chapter and throughout the rest of this book.


动作序列是actions最有用,最常用的功能 — 把一些列动作串起来是如此的强大!本章和本书的剩余部分都会大量的使用动作序列.


Wait for duration action

动作等待


The wait for duration action does exactly what you’d expect: makes the sprite wait for a period of time, during which the sprite does nothing.


就像你想的那样,动作等待让sprite就跟那呆一段时间.(矮人直升机的导弹…dota还是很有用的...)

“What’s the point of that?”, you may be wondering. Well, wait for duration actions only truly become interesting when combined with a sequence action.


你可能会想”这东西有什么用?”.恩...只有当把它放到动作序列里的时候才会变的有趣.


For example, let’s make the cat lady briefly pause when she reaches the bottom of the V-shape. To do this, simply modify your list of actions in spawnEnemy:, like so (changes highlighted):


举个例子,你希望让老太太移动到屏幕底端的时候思考一下人生~只需要把spawnEnemy:方法中控制动作序列的方法稍作更改(这里只贴出更改部分的代码):

SKAction *wait = [SKAction waitForDuration:0.25];SKAction *sequence = [SKAction sequence:@[actionMidMove, wait, actionMove]];


Run block and selector actions

block和选择器调用动作


At times when you’re running a sequence of actions, you’ll want to run your own block of code at some point. For example, say you want to log out a message when the cat lady reaches the bottom of the V.


有些时候当你运行动作序列时需要在某一个时间点调用一些block.举个例子,让老太太移动到屏幕底端的时候阐述一下对人生的思考...


To do this, just modify your list of actions in spawnEnemy: like so (changes highlighted):


再次修改以下spawnEnemy:方法中的代码(同上):


SKAction *logMessage = [SKAction runBlock:^{    NSLog(@"Reached bottom!”);}];SKAction *sequence = [SKAction sequence: @[actionMidMove, logMessage, wait, actionMove]];


Build and run, and when the cat lady reaches the bottom of the V, you should see the following in the console:


编译运行,这次当老太太思考的时候就会看到这么一句话:


ZombieConga[9644:70b] Reached bottom!


Of course, you can do far more than just log a message here – since it’s an arbitrary code block, you can do anything you want!


当然,除了打印记录信息,你能做的事多了去了~发挥一下野马一样的思维...


You should be aware of a few other actions related to running blocks of code:


可能你已经意识到了肯定还有其他根block调用相关的动作:


runBlock:queue: Allows you to run the block of code on an arbitrary dispatch queue instead of in the main Sprite Kit event loop. You can learn more about this in Chapter 25, “Performance.”


runBlock:queue:方法允许你通过多线程来调用block(该部分内容涉及到GCD的相关知识,此处不展开讨论,有兴趣的读者可以到以下连接获取相关资料…http:www.google.com.hk...  =.=||).

performSelector:onTarget: Allows you to run any method on a target object, rather than having a block of code inline. Whether you use this or the runBlock: action to execute code is a matter of personal preference – mostly. You’ll see an example where your choice actually matters in Chapter 16, “Saving and Loading Games.”


performSelecton:onTarget:允许你调用一个对象的方法来替代block.绝大多数情况下这两种方法的选择都是个人喜好.16章的时候我们会讨论究竟什么情况下才有明显的区别.


Reversed actions

反转动作


Let’s say you want to make the cat lady go back the way she came – after she moves in a V to the left, she should move in a V back to the right.


现在我们想让这个老太太从哪来回哪去,当她移动到屏幕的左边时原路返回(走的可能也是猫步…)


You can reverse certain actions in Sprite Kit simply by calling reversedAction on them. This results in a new action that is the opposite of the original action.


在SpriteKit中,你可以非常简单的通过reversedAction方法来反向一个现有的动作序列.


Not all actions are reversible – for example, moveTo:duration: is not.


并非所有的动作都是可逆的,举例来说,moveTo:duration:就不行.


Let’s try this out. Modify your list of actions in spawnEnemy:


试一下,把spawnEnemy方法修改成这个样子:


SKAction *actionMidMove = [SKAction moveByX:-self.size.width/2-enemy.size.width/2 y:-self.size.height/2+enemy.size.height/2 duration:1.0];SKAction *actionMove = [SKAction moveByX:-self.size.width/2-enemy.size.width/2 y:self.size.height/2+enemy.size.height/2 duration:1.0];SKAction *wait = [SKAction waitForDuration:1.0]; SKAction *logMessage = [SKAction runBlock:^{    NSLog(@"Reached bottom!"); }];SKAction *reverseMid = [actionMidMove reversedAction];SKAction *reverseMove = [actionMove reversedAction];SKAction *sequence = [SKAction sequence:@[actionMidMove, logMessage, wait, actionMove, reverseMove, logMessage, wait, reverseMid]]; [enemy runAction:sequence];


One last thing about reversible actions: if an action is not reversible, then it will return the same action. And because sequence actions are also reversible, you can simplify the above code as follows. Remove the lines where you create the reversed actions and replace the sequence creation with the following lines:


关于反向动作还有最后一件事:如果一个action是不可逆的,那么他会返回相同的action.另外,动作序列是可逆的,你可以把上面创建反向动作的代码改写成这样:


SKAction *sequence = [SKAction sequence:@[actionMidMove, logMessage, wait, actionMove]];sequence = [SKAction sequence:@[sequence,[sequence reversedAction]]];


Astute observers may have noticed that the first half of this action logs a message as soon as it reaches the bottom of the screen, but on the way back the message is not logged until after the sprite has waited at the bottom for one second.


细心的读者可能发现了,这次动作序列的前半部分会在老太太刚刚到达屏幕底部的时候打印信息,但是回来的时候却要等一秒才会打印.


This is because the reversed sequence is the exact opposite of the original, unlike how you wrote the first version. Later in this chapter you’ll read about the group action, which you could use to fix this.


这是由于反向序列是对原序列的纯粹反转,并不向我们之前写的那个版本一样.本章稍后的内容会使用动作组来解决这一问题.


时间问题,今天先写到这了,明天继续~



原创粉丝点击