以有限的旋转速度通过触摸旋转精灵 [英] Rotate sprite by touch with a limited rotation speed

查看:25
本文介绍了以有限的旋转速度通过触摸旋转精灵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让我的 spriteNode 在手指触摸时旋转.

I'm trying to make my spriteNode rotate over finger touch.

到目前为止我可以做到,但我想要的是我的节点有一个旋转速度".所以我计算了角度的长度,然后设置了一个不同的时间来旋转(如果弧很长,那就需要时间......).

So far I can do it, but what I want is that my node have a "rotation speed". So I calculate the length of the angle then set a different timing to rotate with it (if the arc is long, it will take time...).

这是我的代码:

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会阻塞移动.

The main problem is that adding several SKAction to the node block the movement.

我想知道解决办法是什么?如果可能的话,使用 SKAction,因为我想避免在每一帧上进行更新来计算运动(但如果它是唯一的解决方案......)

I would like to know what could be the solution ? If possible by using SKAction, since I would like to avoid doing an update on each frame to calculate the movement (but if it's the only solution...)

回答后的注意事项

收到答案后,我再次阅读 SpriteKit 文档,发现 这个清楚的说明 :

As I received answers, I read again the SpriteKit documentation and found this clear note :

何时不应使用操作

虽然动作是有效的,但创建和执行它们是有成本的.如果您在动画的每一帧中都对节点的属性进行更改,并且这些更改需要在每一帧中重新计算,那么您最好直接对节点进行更改,而不是使用操作来这样做.有关您可以在游戏中的何处执行此操作的更多信息,请参阅高级场景处理.

Although actions are efficient, there is a cost to creating and executing them. If you are making changes to a node’s properties in every frame of animation and those changes need to be recomputed in each frame, you are better off making the changes to the node directly and not using actions to do so. For more information on where you might do this in your game, see Advanced Scene Processing.

推荐答案

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

I have a turret which ... should target the finger position, but not immediately, by taking time to turn.

这样的事情你将无法摆脱 SKActions.您可以尝试,但这会非常混乱且效率低下.您需要实时运动控制来实现此类操作,因为您的炮塔角速度需要根据触摸位置不断变化.

You won't be able to get away with SKActions for something like this. You can try but it will be really messy and inefficient. You need real-time motion control for something like this because the angular velocity of your turret needs to change constantly depending on the touch position.

所以我给你写了一个快速示例项目,展示如何计算角速度.该项目还处理所有特殊情况,例如防止角度跳过目标旋转.

So I wrote you a quick example project showing how to calculate the angular velocity. The project handles all special cases as well, such as preventing the angle from jumping over your target rotation.

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.zRotation = targetZRotation
        }

    }


}

<小时>

这篇关于以有限的旋转速度通过触摸旋转精灵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆