Sprite Kit 高级场景处理

使用Sprite Kit涉及到操纵场景树的内容来让内容在屏幕上的动起来。通常情况下,动作是该系统的核心。然而,通过直接地挂接到(hooking into)场景处理,你可以创建动作不能单独完成的其他行为。要做到这一点,你需要学习:
· 场景如何处理动画
· 如何在场景处理过程中添加自己的行为

场景如何处理动画帧

在传统视图系统中,视图内容渲染一次后,然后只有当模型(model)的内容发生变化时才会再次渲染。这种模式对于视图非常适用,因为在实践中,大多数视图内容是静态的。另一方面,Sprite Kit是明确为动态内容设计的。Sprite Kit不断更新的场景内容并渲染它,以确保动画是平滑和精确的。
动画和渲染场景的过程绑定到场景对象(SKScene)上。场景和动作处理只在场景被呈现时运行。呈现的场景运行一个渲染循环,该循环在处理场景的节点树和渲染它之间交替进行。这种模式类似于在大多数游戏中使用的渲染和处理循环。
图7-1展示了场景执行渲染循环的步骤。
图7-1 场景中的帧处理
每次通过的最终目标是要渲染并更新场景的节点树的内容。你不直接挂接到渲染步骤,而是更新节点树的内容,如在 “建筑场景 ”中描述的那样。然而,Sprite Kit为你提供了工具来挂接到其他步骤。下面是那些步骤:
1. 随着时间在模拟中流逝,渲染循环从调用场景的update:方法开始。这是实现你自己游戏内模拟(in-game simulation)的主要场所,包括输入处理、人工智能、游戏脚本和其他类似的游戏逻辑。通常情况下,你使用这个方法对节点进行更改或运行节点上的动作。
2. 场景处理树中的所有节点上的动作。它找到任何正在运行的操作,并将那些更改应用到树上。在实践中,因为自定义操作,你还可以挂接到动作进程(mechanism)调用你自己的代码。
你不能直接控制动作的处理的顺序,也不能让场景跳过某个节点上的动作,除非你从这些节点中移除动作或从节点树中移除节点。
3. 在帧的所有动作都已处理后,场景的didEvaluateActions方法被调用。
4. 然后场景对场景中的物理体模拟物理。添加物理到场景中在 “模拟物理”中描述, 但模拟物理的最终结果是,物理模拟可能会调节树中节点的位置和旋转角度。你的游戏也可以在物理体之间互相接触时接收到回调。
5. 场景的didSimulatePhysics方法是场景渲染前的最后一个步骤。这是你对场景进行更改的最后机会。
6. 渲染场景。

场景中的后处理

场景可以以任意顺序处理场景树中的动作。由于这个原因,如果你有一些需要在每一帧运行的任务,且你需要在它们运行时精确地控制它们,你应该使用didEvaluateActions和didSimulatePhysics方法来执行这些任务。通常情况下,你在这里进行的更改,需要树中的某些节点的最终计算出来的位置。你的后处理(post-processing)可以利用这些位置,并在树上执行其他有用的工作。
下面是一些你可能执行的后处理任务的例子:
· 居中场景的内容在某个节点上
· 在场景内容上添加调试信息的覆盖层(overlay)
· 复制节点树的某一部分的节点到另一部分。例如,你可能有一个效果节点,它的子节点需要跟树中其他的节点一样。 

例子:居中场景在节点上
在需要内容滚动的游戏中,居中场景的内容在某个节点上,对相机(cameras)和类似的概念是有用的。在这种情况下,内容比场景的frame要大。在玩家左右移动时,角色在某个地方保持固定,而世界(world)在他们周围移动。场景保持对角色锁定,无论玩家把角色移动到哪里。
Sprite工具并不提供相机的内置支持,但实现却是非常简单。世界和相机分别由场景中的一个节点表示。世界是场景的一个直接子节点,而相机是一个世界节点的后代。节点的这种安排是非常有用的,因为它给游戏世界一个不绑定于场景坐标系的坐标系。你可以使用这个坐标系布置世界内容。
图7-2   为一个滚动的世界组织场景
相机被放置在世界中。世界可以在场景中四处滑动。因为相机是一个节点,你可以用动作甚至是物理来移动相机。然后,在后处理步骤,你重新在场景中定位世界节点,使相机节点在场景正中。图7-3展示了这个。世界放置在场景中,以便让角色居中。然后,该角色在世界里面四处移动。最后,后处理步骤重定位世界以便角色再次居中。
图7-3   世界在场景内移动
下面是实现的片段:
1. 把场景的锚点放置在场景中心。
复制代码
  1. self.anchorPoint = CGPointMake(0.5,0.5);

2.使用世界节点来表示滚动的世界。世界的内容将作为世界的子节点,将是精灵节点和内容节点。(图中未示出)。
复制代码
  1. SKNode *myWorld = [SKNode node];
  2. [self addChild:myWorld];

3.使用世界内的一个节点表示相机。
复制代码
  1. SKNode *camera = [SKNode node];
  2. camera.name = @“camera”;
  3. [myWorld addChild:camera];

4.使用didSimulatePhysics方法居中场景在相机上。centerOnNode方法把相机当前的位置转换成场景坐标,然后从世界的位置减去那些坐标来滑动角色到(0,0)位置。
复制代码
  1. - (void)didSimulatePhysics {   
  2.     [self centerOnNode:
  3.     [self childNodeWithName:@“//camera”]];
  4. }
  5.  - (void)centerOnNode:(SKNode *)node{   
  6.     CGPoint cameraPositionInScene = [node.scene convertPoint:node.position fromNode:node.parent]; 
  7.    node.parent.position = CGPointMake(node.parent.position.x  -  cameraPositionInScene.x,     node.parent.position.y  -  cameraPositionInScene.y);
  8. }


例子:添加调试覆盖层
当你正在使用Sprite Kit开发一个游戏时,显示实时的可视化调试信息是有帮助的,这些信息关于场景中正在发生的事情。例如,以下信息可能在调试你的游戏时是有用的:
   场景中角色的人工智能决策
   在世界中触发脚本动作的位置
   物理信息,如重力以及其他力,甚至物理体的尺寸
形状和标签节点对注释你的游戏的行为特别有用。
要添加一个调试覆盖层,最好的办法是使用一个单一的节点代表覆盖层,并把它添加到场景。所有调试信息由这个节点的后代节点表示。这个节点被放置在场景中附带一个z坐标,z坐标把它放置在所有其他场景内容的上面。调试节点可以是但不必是场景的直接子节点。例如,在一个滚动的世界,你放置在覆盖层的信息可能绑定于世界坐标,而不是场景坐标。在场景开始处理一帧之前,你从场景中移除这个节点,然后移除它的子节点。其假设是,调试信息需要每帧更新。经过场景模拟物理后,节点被添加回到场景且它的内容会重新生成。
创建场景类中的调试节点的属性,并在场景第一次呈现时初始化它。
复制代码
  1. @property(SKNode *)debugOverlay;
  2.  self.debugOverlay = [SKNode node];
  3. [self addChild:self.debugOverlay];

2.在动作处理前移除节点。
复制代码
  1.  - (void)update:(NSTimeInterval)currentTime{   
  2.      [self.debugOverlay removeFromParent];   
  3.      [self.debugOverlay removeAllChildren];
  4. }

3.在场景处理完后添加节点。
复制代码
  1.  - (void)didSimulatePhysics{    
  2.     [self addChild:self.debugOverlay];   
  3.     / /添加代码来创建调试节点并添加调试图像到调试节点。   
  4.     / /这个例子显示了重力矢量。    
  5.     SKShapeNode *gravityLine = [[SKShapeNode alloc] init];   
  6.     gravityLine.position = CGPointMAke(200,200);     
  7.     CGMutablePathRef path= CGPathCreateMutable();   
  8.     CGPathMoveToPoint(path, NULL, 0.0, 0.0);    
  9.     CGPathAddLineToPoint(path, self.physicsWorld.gravity.x * 10,    self.physicsWorld.gravity.y * 10);    
  10.     CGPathCloseSubpath(path);    
  11.     gravityLine.path = path;    
  12.     CGPathRelease(path);
  13.     [self.debugOverlay addChild:gravityLine];
  14. }            


例子:在场景中复制信息
实现此行为的技术类似与添加调试覆盖层。当你预处理(pre-process)场景时,从树中移除节点过时的副本。然后,在后处理过程中,你从树的一部分复制节点到另一部分。你使用节点的副本,因为每个节点只能有一个父节点。
在某些情况下,你只需要在每一帧更新少量的信息。在这种情况下,不断地添加、移除和复制节点的成本可能是昂贵的。相反,只复制一次,然后用你的后处理步骤来更新重要的属性。
复制代码
  1.  copyNode.position = originalNode.position;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值