代码 - > http://pastebin.com/W3DMYjXa
我正在修补SpriteKit,我似乎无法按照我想要的方式让我的太空船旋转发射器节点。
我观看了Apple Tech Talks Session,他们描述了制造宇宙飞船并使用发射器进行推力排气,但他们将船只锁定在一个方向。
在我的实验中,我试图允许玩家精灵(宇宙飞船)向任何方向行进,我有旋转和滚动为玩家工作,但粒子发射器似乎不随玩家旋转。
我的层次结构看起来像这样
场景
- >世界节点
- >播放器节点
---->玩家精灵
---->发射器节点
我的理论是,如果我旋转(播放器节点),它应该旋转它的两个子节点,它会旋转它们,但发射器继续以相同的方向发射。
我可以手动改变发射角度,但似乎不必要地复杂化。
这是我用来旋转的东西
-(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];
}
我在这里错过了什么吗?
以下是此操作的视频
答案 0 :(得分:3)
我相当确定spritekit中有一个与targetNode和rotation相关的错误。另一个答案似乎表明这是预期的行为,但忽略了文档明确地将这种情况作为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;
}
请注意,如果有多个可以旋转的祖先节点,则需要循环遍历它们并将所有zRotations一起添加。
答案 1 :(得分: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帧执行此检查。
我希望这有助于某人!
答案 2 :(得分:0)
您正在将发射器的targetNode
属性设置为背景。请注意,这会强制发射器的粒子由背景节点渲染,并且它们将被视为背景是其父级。因此,粒子不会改变角度,因为背景的旋转不会改变。
移除[emitter setTargetNode:backgroundNode]
,发射器的发射角度应与播放器一起正确旋转。
如果你正在寻找一个“中间地带”,角度与玩家一起旋转,而已经渲染的粒子没有“卡住”发射器,请尝试:
其次,正如您要运行旋转操作一样,暂时将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;
}];