以有限的旋转速度触摸旋转精灵

我试图让我的精灵节点旋转手指触摸。

到目前为止,我可以做到这一点,但我想要的是,我的节点有一个“旋转速度”。 所以我计算angular度的长度,然后设置一个不同的时间来旋转它(如果弧长,这将需要时间…)。

这是我的代码:

override func touchesMoved(touches: NSSet, withEvent event: UIEvent) { _isTouched = true for touch in touches { let location:CGVector = touch.locationInNode(self) - miner.position miner.weaponRotation = location.angle() - CGFloat(M_PI_2) } } var wantedRotation: CGFloat { get { return _wantedRotation } set(rotation) { if rotation > CGFloat(M_PI) || rotation < -CGFloat(M_PI) { _wantedRotation = CGFloat(M_PI) + rotation % CGFloat(M_PI) } else { _wantedRotation = rotation } removeActionForKey("rotation") let arc: CGFloat = CGFloat(abs(_wantedRotation - zRotation)) let shortestArc: CGFloat = min(arc, CGFloat(M_PI * 2.0) - arc) runAction(SKAction.rotateToAngle(_wantedRotation, duration: NSTimeInterval(shortestArc / CGFloat(M_PI) * rotationSpeed), shortestUnitArc: true), withKey: "rotation") } } 

主要的问题是添加几个SKAction到节点阻止移动。

我想知道什么是解决scheme? 如果可能的话,通过使用SKAction,因为我想避免在每一帧进行更新来计算运动(但如果这是唯一的解决scheme…)

注意后的答案

当我收到答案时,我再次阅读了SpriteKit文档,并发现这个明确的说明 :

何时不应该使用操作

尽pipe行动是有效的,但是创build和执行它们是有成本的。 如果要在每个animation帧中更改节点的属性,并且需要在每个帧中重新计算这些更改,则最好直接对节点进行更改,而不要使用动作来执行此操作。 有关在游戏中可以执行此操作的更多信息,请参阅高级场景处理。

我有一个炮塔,它应该瞄准手指的位置,但不是立即,花时间转动。

你将无法摆脱SKActions这样的事情。 你可以尝试,但它会非常混乱和低效率。 您需要实时运动控制 ,因为您的炮塔的angular速度需要根据触摸位置不断变化。

所以我写了一个快速示例项目来演示如何计算angular速度。 该项目也处理所有的特殊情况,如防止angular度跳过你的目标旋转。

 import SpriteKit class GameScene: SKScene { let turret = SKSpriteNode(imageNamed: "Spaceship") let rotationSpeed: CGFloat = CGFloat(M_PI) //Speed turret rotates. let rotationOffset: CGFloat = -CGFloat(M_PI/2.0) //Controls which side of the sprite faces the touch point. I offset the angle by -90 degrees so that the top of my image faces the touch point. private var touchPosition: CGFloat = 0 private var targetZRotation: CGFloat = 0 override func didMoveToView(view: SKView) { turret.physicsBody = SKPhysicsBody(rectangleOfSize: turret.size) turret.physicsBody!.affectedByGravity = false turret.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0) self.addChild(turret) } override func touchesMoved(touches: NSSet, withEvent event: UIEvent) { calculateAngleToTouch(touches.anyObject() as UITouch) } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { calculateAngleToTouch(touches.anyObject() as UITouch) } func calculateAngleToTouch(touch: UITouch) { let position = touch.locationInNode(self) let angle = atan2(position.y-turret.position.y, position.x-turret.position.x) targetZRotation = angle + rotationOffset } override func update(currentTime: NSTimeInterval) { var angularDisplacement = targetZRotation - turret.zRotation if angularDisplacement > CGFloat(M_PI) { angularDisplacement = (angularDisplacement - CGFloat(M_PI)*2) } else if angularDisplacement < -CGFloat(M_PI) { angularDisplacement = (angularDisplacement + CGFloat(M_PI)*2) } if abs(angularDisplacement) > rotationSpeed*(1.0/60.0) { let angularVelocity = angularDisplacement < 0 ? -rotationSpeed : rotationSpeed turret.physicsBody!.angularVelocity = angularVelocity } else { turret.physicsBody!.angularVelocity = 0 turret.zPosition = targetZRotation } } } 

在这里输入图像说明

你不需要这样做:removeActionForKey(“rotation”) – 这是你有移动阻塞的原因。 只要看看这些方法

  • speedBy:时间:
  • speedTo:时间:

以及来自文档的animation属性:

速度 – 速度因素调整动作的animation运行速度。 例如,2.0的速度因子意味着animation运行速度快两倍。

在你的情况下很难说,而且解决办法是创build序列动作,所以它们将一个接一个地执行。 希望这可以帮助

我会试一试。 但我现在不能testing。 这是一个Objective-C(伪)代码。

 - (void)rotateSprite:(SKSpriteNode *)sprite toAngle:(float)angle inDuration:(NSTimeInterval)duration { SKAction *rotation = [SKAction rotateToAngle:angle duration:duration]; [sprite runAction:rotation completion:^{ [sprite removeAllActions]; }]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { . . . // your sprite [node removeAllActions]; float angle = [self calcAngle]; // your angle NSTimeInterval duration = [self calcDuration]; // your duration [self rotateSprite:(SKSpriteNode *)node toAngle:angle inDuration:duration]; } 

我已经创build了代码,无论angular度如何都以恒定速度将node0精灵转向触摸点。 你已经在你的问题中指出,你更喜欢使用SKAction,而不是在更新方法中使用代码。

以下是GameScene.m文件的示例项目代码:

 #import "GameScene.h" @implementation GameScene { SKAction *objectAnimation; SKSpriteNode *node0; } -(void)didMoveToView:(SKView *)view { self.backgroundColor = [SKColor blackColor]; node0 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 10)]; node0.position = CGPointMake(300, 300); node0.zRotation = 0.0; [self addChild:node0]; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { CGPoint touchLocation = [touch locationInNode:self]; // calculate angle between object and touch float deltaY = touchLocation.y - node0.position.y; float deltaX = touchLocation.x - node0.position.x; float moveBydegrees = atan2(deltaY, deltaX) * 180 / 3.14159265359; // convert degrees to radians float moveByRadians = moveBydegrees * M_PI / 180; float myFloat0 = 0; if(moveByRadians < 0) { myFloat0 = fabs(moveByRadians); } else { myFloat0 = moveByRadians; } NSLog(@"myFloat0 = %f",myFloat0); float myFloat1 = 0; if(node0.zRotation < 0) { myFloat1 = fabs(node0.zRotation); } else { myFloat1 = node0.zRotation; } NSLog(@"myFloat1 = %f",myFloat1); float durationTime = fabs(myFloat0 - myFloat1); NSLog(@"durationTime = %f",durationTime); objectAnimation = [SKAction rotateToAngle:moveByRadians duration:durationTime shortestUnitArc:YES]; [self startObjectAnimation]; } } -(void)startObjectAnimation { [node0 removeActionForKey:@"animation"]; if (![node0 actionForKey:@"animation"]) { if(objectAnimation != nil) { [node0 runAction:objectAnimation withKey:@"animation"]; NSLog(@"runnign animation"); } else { NSLog(@"enemy node animation is nil"); } } } 

我个人认为使用更新方法来完成这个任务会更好。 这将使您在对象的zRotation的逐步移动中,而不是使用SKAction,更好地控制。