4

代码 --> http://pastebin.com/W3DMYjXa

我正在修补 SpriteKit,但我似乎无法让发射器节点按照我想要的方式与我的飞船一起旋转。

我观看了 Apple 技术讲座,他们描述了制造宇宙飞船并使用发射器进行推力排气,但他们将飞船锁定为仅面向一个方向。

在我的实验中,我试图让玩家精灵(宇宙飞船)向任何方向行进,我有旋转和滚动为玩家工作,但粒子发射器似乎没有随着玩家旋转。

我的层次结构看起来像这样

场景

-->世界节点

-->播放器节点

---->玩家精灵

---->发射器节点

我的理论是,如果我旋转(播放器节点),它应该旋转它的两个子节点,并且它确实旋转了它们,但发射器继续朝同一方向发射。

我可以手动更改发射角度,但这似乎不必要地复杂。

这是我用来旋转的

-(void)rotatePlayerToDirection:(TTDirection)direction {

    CGFloat radDir;
    CGFloat emiDir;
    scrollDirection = direction;

    switch (direction) {
        case TTUp:
            radDir = 0;
            emiDir = 3.142;
            break;
        case TTRight:
            radDir = 4.712;
            emiDir = 1.571;
            break;
        case TTDown:
            radDir = 3.142;
            emiDir = 0;
            break;
        case TTLeft:
            radDir = 1.571;
            emiDir = 4.712;
            break;

        default:
            break;
    }



    SKAction *rotatePlayer = [SKAction rotateToAngle:radDir duration:0.1 shortestUnitArc:YES];

    [playerNode runAction:rotatePlayer];

}

我在这里错过了什么吗?

这是一个实际操作的视频

http://youtu.be/NGZdlB9-X_o

4

3 回答 3

3

我相当肯定 spritekit 中存在与 targetNode 和旋转有关的错误。另一个答案似乎表明这是预期的行为,但这忽略了文档明确地将这种情况作为存在 targetNode 的动机。

使用其他节点类型

您真正想要的是生成粒子,但此后独立于发射器节点。当发射器节点旋转时,新粒子获得新方向,而旧粒子保持其旧方向。

然后给出了一个使用 targetEmitter 的例子来说明如何实现这一点。但是,示例代码不起作用。

似乎设置 targetNode 会破坏粒子旋转。

更新:我找到了解决方法。

当设置 SKEmitterNode.targetNode 时,Spritekit 无法调整 SKEmitterNode.emissionAngle 属性。您可以通过在处理完操作后手动设置来解决此问题。

假设您的 SKEmitterNode 只有一个父节点,您可以在场景中执行类似的操作。

- (void)didEvaluateActions
{
    // A spaceship with a thrust emitter as child node.
    SKEmitterNode *thrust = (SKEmitterNode *)[self.spaceship childNodeWithName:@"thrust"];
    thrust.emissionAngle = self.spaceship.zRotation + STARTING_ANGLE;
}

请注意,如果有多个祖先节点可以旋转,您将需要遍历它们并将它们的所有 zRotation 添加在一起。

于 2014-04-22T06:52:34.627 回答
1

我知道这是一个老问题,OP 可能已经找到了解决方案或解决方法,但我想我会增加两便士的价值,以防它帮助其他人。

我刚刚开始使用 SpriteKit 和 Swift,并且正在开发一个游戏,其中节点飞来飞去并相互碰撞,经常改变行进方向。

我向每个节点添加了一个发射器,最初发现当节点旋转并改变方向时,发射“轨迹”保持不变。然后我读到发射器应该将其目标节点设置为不是它的子节点,而是它们都存在的场景。

这至少使粒子轨迹真实地扭曲和转动,而不仅仅是朝一个方向喷出。

但是节点可以旋转并改变方向,我希望粒子以与其行进相反的方向远离节点 - 就像飞机或火箭的烟雾轨迹一样。

由于节点可能会旋转,因此将发射器的发射角度设置为节点的 z 旋转不起作用。所以...

我在字典中跟踪所有屏幕上的节点,当它们离开屏幕时将它们从场景中移除。

所以在didSimulatePhysics我使用相同的字典来获取节点并根据速度矢量计算行进角度,然后相应地设置发射器发射角度:

import Darwin

// in your scene class...

override func didSimulatePhysics() {
    removeOffScreenParticles()
    for (key,particle) in particles {
        let v = particle.physicsBody!.velocity
        particle.trail!.emissionAngle = atan2(v.dy, v.dx) - CGFloat(M_PI)
    }
}

我知道这个计算和调整正在为每个屏幕节点、每一帧执行,所以如果性能成为问题,可能会使用我的帧计数器只在每第 n 帧进行一次检查。

我希望这可以帮助别人!

于 2015-02-04T15:08:50.640 回答
0

您正在将发射器的targetNode属性设置为背景。请注意,这会强制发射器的粒子由背景节点渲染,并且它们将被视为背景是它们的父级。所以,粒子没有改变角度,因为背景的旋转没有改变。

移除[emitter setTargetNode:backgroundNode]并且发射器的发射角度应该随着播放器正确旋转。

如果您正在寻找“中间地带”,其中角度与玩家一起旋转,而已经渲染的粒子不会“卡”在发射器上,试试这个:

  • 首先,不要在发射器上设置 targetNode(默认为 nil)。
  • 其次,就在你即将运行旋转动作时,暂时将targetNode设置为另一个节点,完成后将其重置为nil(以便粒子可以沿着旋转):

    emitter.targetNode = backgroundNode;
    [playerNode runAction:rotatePlayer completion:^{
       emitter.targetNode = nil;
    }];
    

请注意,结果也是“中间地带”——随着目标节点的变化,发射器“喷出”(之前的粒子被移除,新的粒子由新的目标节点渲染)。希望有帮助。

除此之外,没有真正直接的方法可以实现这一点——毕竟手动设置发射角度可能是最简单的方法。这是一种方法,在运行旋转之前(发射器目标节点仍然为零,而且,不需要硬编码发射角度):

    float originalAngle = emitter.emissionAngle;
    emitter.emissionAngle = emitter.emissionAngle - radDir;
    [playerNode runAction:rotatePlayer completion:^{
        emitter.emissionAngle = originalAngle;
   }];
于 2014-02-26T14:46:26.137 回答