运动健康

向结点添加动作(译)

15 6月 , 2019  

这是2个用干毛巾在地上滑行的动作,腹部要时刻保持紧张状态,大大的提高了燃脂效率。当然你还要准备一张瑜伽垫。每个动作每组30秒,两个动作交替循环做3组。

绘制精灵十分有用,但是静态的内容就是一幅画,而不是一个游戏。为了添加游戏元素,你需要让精灵在屏幕上移动并执行其他的一些逻辑。SpriteKit制作动画的主要机制就是动作,如果你是一路学到这里的那么你已经了解了动作子系统的一部分内容。现在,是时间深入了解一下动作是怎样构造并执行的了。
动作就是你想要对场景做的改变。大部分情况下,一个动作会将它的改变应用到执行它的结点上。比如说,如果我们想要移动一个精灵穿过屏幕,你要创建一个move动作并让精灵结点执行这个动作。SpriteKit会自动改变精灵的位置直到动画结束。

动作是自包含对象

每个动作都是描述如何改变场景的不透明的对象。所有的动作均继承自SKAction,它没有明确的实例,实际上,不同类型的动作都是使用类方法实例化的(工厂模式?)。例如,下面是一些动作可以完成的一些事情

  • 改变结点的位置或者方向
  • 改变结点的大小或者缩放属性
  • 改变结点的可见性或者使它变得透明
  • 改变节点的内容使得它可以执行贴图动画(一系列的贴图逐帧显示形成动画)
  • 给结点着色
  • 播放声音
  • 将一个结点从结点树中移除
  • 调用一个代码块(block)
  • 调用一个对象的方法

当你创建一个结点之后,它的类型就无法改变了,而且他的属性也很少能够改变。SpriteKit利用不可变对象的优势以提高执行效率。

提示:因为动作时高效的不可变对象,收益以你可以安全的将相同的动作同时应用在多个不同的结点上。基于这个缘故,如果在你的游戏中需要反复执行一个动作,你可以只只创建一个动作对象,然后在你需要的时候将它应用到结点上执行就可以了。

动作可以时即时的也可以不是即时的

  • 即时的动作在一个动画帧里开始和结束。例如,将一个结点从结点树中移除就是一个即时动作,因为结点不能部分的移除。当动作执行,结点就会立即移除。
  • 非即时动作进行动画效果时需要跨度一个时间段。动作执行时,会在每个动画帧处理动作知道动作结束。

用来创建动作的完整的类方法雷彪参见SKAction class
Reference
,但是只有当你需要知道怎样配置某个动作的详细方法时才需要查阅。

结点执行方法

只有你让一个结点执行动作时动作才会执行。执行一个动作最简单的方法时让一个结点调用runAction:方法。代码
3-1 创建了一个move动作并让一个结点执行它。
代码 3-1 执行一个动作

SKAction *moveNodeUp = [SKAction moveByX:0.0 y:100.0 duration:1.0];
[rocketNode runAction: moveNodeUp];

move动作需要一段时间,所以这个动作会跨越很多动画帧直到时间到达动作的duration用完为止。当动作执行完后,动作会从结点移除
你可以在任何时候执行动作。当你添加一个动作到结点而这是场景正在处理动作时,动作也许不会立即执行知道下一帧开始。场景用来处理动作的步骤在
高级场景处理中描述
结点可以同时执行多个动作,即使这些动作是在不同时刻开始执行的。场景会保存每个动作是何时开始执行的并计算此刻该动作对结点造成的影响。例如,如果你执行两个动作移动同一个结点,两个动作会对每一帧造成改变。如果两个move动作相同但是方向相反,那么结点会呆在原点不动。
因为动作的处理是和场景绑定在一起的,所以只有在结点是当前显示的结点树的一部分时,动作才会被处理。你可以充分利用这个特性,创建一个结点并将动作赋给它,但是只有当该结点被添加到当前场景的结点上去时,动作才会执行。当结点添加到场景,它的动作会立即执行。当结点被拷贝时,动作正在执行的动作也一同被拷贝和打包,所以这个特性非常有用。
如果结点正在执行动作,那么hasActions属性会返回YES

取消正在执行的动作

要取消一个动作正在执行的动作,调用它的
removeAllActions方法,所有的动作都会立即从结点移除。如果被移除的结点有duration,动作对结点做的任何改变都会原封不动的保存,但会后续帧的改变不会执行。

动作完成时执行回调

runAction:completion:
方法和runAction:方法是一样的,但是当动作结束时,completion代码块会被执行。这个回调只有在动作结束时才会调用。如果动作完成前被移除了,那么这个回调不会执行。

使用命名的动作以便对动作精确控制

通常情况下,你不知道那些动作正在执行,如果你想移除动作,你必须移除所有的动作。如果你需要知道某一个动作是否正在执行或者想要移除某一个动作,你必须使用命名的动作。命名的动作使用一个唯一的key来标识该动作,你可以在结点上开始,移除,查找以及替换命名的动作
代码 3-2和 3-1 相似,但是动作使用一个key进行标识
代码 3-2 运行命名的动作

[SKAction *moveNodeRight = [SKAction moveByX:100.0 y:0.0 duration:1.0];
[spaceship runAction: moveNodeRight withKey:@"ignition"];

可以使用如下基于key的方法:

  • runAction:withKey:
    方法执行一个动作,如果具有相同key的动作正在执行,在新的动作被添加之前,旧的同key动作会被移除
  • actionForKey: 方法确定动作是否已经执行
  • removeActionForKey:方法移除动作

代码 3-3
演示如何使用命名动作控制精灵的移动。如果用户在场景中点击,方法被调用。这段代码确定点击发生的位置然后让精灵向那个位置移动。动作执行的时间会根据距离进行计算,因此精灵总是保持一个固定的速度。因为代码使用了runAction:withKey:
方法,所以如果精灵已经在运动,前一个运动会停止,新的运动会从当前点开始到达一个新的位置。
代码 3-3 移动精灵到当前点击位置

- (void)mouseDown:(NSEvent *)theEvent
{
    CGPoint clickPoint = [theEvent locationInNode:self.playerNode.parent];
    CGPoint charPos = self.playerNode.position;
    CGFloat distance = sqrtf((clickPoint.x-charPos.x)*(clickPoint.x-charPos.x)+
                             (clickPoint.y-charPos.y)*(clickPoint.y-charPos.y));

    SKAction *moveToClick = [SKAction moveTo:clickPoint duration:distance/characterSpeed];
    [self.playerNode runAction:moveToClick withKey:@"moveToClick"];
}

创建执行其他动作的动作

SpriteKit提供了改变场景中结点属性的许多标准动作,但是只有将它们结合起来,动作才能发出巨大的威力。通过组合动作,执行单独一个动作就可以创建复杂的令人印象深刻的动画来。组合动作比起其他基本动作类型更简单。在脑中存有这些印象,我们开始学习序列动作,组动作以及重复动作。

  • 序列动作(动作序列)包含几个子动作,几个动作按照先后顺序依次执行
  • 组动作也是由几个动作组成,所有的动作保存在一个族中并且同时执行
  • 重复动作只有一个子动作,当子动作结束时,它会重新执行


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图