Ziehen Drehen Sie einen Knoten um einen festen Punkt
Ich versuche, einen drehbaren Knoten zu erstellen, der dem "Preisrad" in dieser Frage ähnelt . Bisher habe ich die Fähigkeit, mit einem UIPanGestureRecognizer, der wirklich gut funktioniert, Winkelimpulse auf einen Physikkörper zu übertragen. Ich kann das Drehen auch mit einer Berührung stoppen.
Jetzt versuche ich, eine Feineinstellung des Rads durch Ziehen oder Wischen zu ermöglichen. Wenn der Spieler mit dem Ergebnis nicht zufrieden ist, kann er es manuell drehen / ziehen / drehen, um die gewünschte Drehung zu erzielen.
Derzeit speichere ich den Ort der Berührung im touchBegan und versuche, die zRotation meines Knotens in der Aktualisierungsschleife zu erhöhen.
Die Rotation folgt nicht meinem Finger und ist ruckartig. Ich bin mir nicht sicher, ob ich die Fingerbewegung genau genug ablesen kann oder ob die Änderungsposition des Fingers nicht genau in Bogenmaß übersetzt wird. Ich vermute, dass es keine gute Lösung ist, die Berührung zu erkennen und sie dann im Update zu behandeln.
Hier ist mein Code.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
if let touch = touches.first as? UITouch {
var location = touch.locationInView(self.view)
location = self.convertPointFromView(location)
mostRecentTouchLocation = location
let node = nodeAtPoint(location)
if node.name == Optional("left") && node.physicsBody?.angularVelocity != 0
{
node.physicsBody = SKPhysicsBody(circleOfRadius:150)
node.physicsBody?.applyAngularImpulse(0)
node.physicsBody?.pinned = true
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if mostRecentTouchLocation != CGPointZero{
let node = nodeAtPoint(mostRecentTouchLocation)
if node.name == Optional("left")
{
var positionInScene:CGPoint = mostRecentTouchLocation
let deltaX:Float = Float(positionInScene.x) - Float(node.position.x)
let deltaY:Float = Float(positionInScene.y) - Float(node.position.y)
let angle:CGFloat = CGFloat(atan2f(deltaY, deltaX))
let maths:CGFloat = angle - (CGFloat(90) * (CGFloat(M_PI) / 180.0))
node.zRotation += maths
mostRecentTouchLocation = CGPointZero
}
}
}
Ich habe einige der Berechnungen im Update auf mehrere Zeilen verteilt, um das Debuggen etwas zu vereinfachen.
Ich kann den PanGestureRecognizer-Code bei Bedarf hinzufügen, aber ich werde versuchen, ihn vorerst kurz zu halten.
BEARBEITEN Hier ist mein neuester Code, der auf der Empfehlung von GilderMan basiert. Ich denke, es funktioniert besser, aber die Rotation ist alles andere als glatt. Es springt in großen Schritten und folgt dem Finger nicht gut. Bedeutet das, dass mit meiner Winkelberechnung etwas nicht stimmt?
override func didSimulatePhysics() {
if mostRecentTouchLocation != CGPointZero {
let node = nodeAtPoint(mostRecentTouchLocation)
if node.name == Optional("left")
{
var positionInScene:CGPoint = mostRecentTouchLocation
let deltaX:Float = Float(positionInScene.x) - Float(node.position.x)
let deltaY:Float = Float(positionInScene.y) - Float(node.position.y)
let angle:CGFloat = CGFloat(atan2f(deltaY, deltaX))
node.zRotation += angle
println(angle)
mostRecentTouchLocation = CGPointZero
}
}
}
Der folgende Code simuliert ein Preisrad, das sich je nach Berührung dreht. Wenn sich der Finger des Benutzers bewegt, dreht sich das Rad proportional zur Geschwindigkeit des Fingers. Wenn der Benutzer über das Rad wischt, dreht sich das Rad proportional zur Geschwindigkeit des Wischens. Sie können die angularDamping
Eigenschaft des Physikkörpers ändern, um die Geschwindigkeit, mit der das Rad zum Stillstand kommt, zu verlangsamen oder zu erhöhen.
class GameScene: SKScene {
var startingAngle:CGFloat?
var startingTime:TimeInterval?
override func didMove(to view: SKView) {
let wheel = SKSpriteNode(imageNamed: "Spaceship")
wheel.name = "wheel"
wheel.setScale(0.5)
wheel.physicsBody = SKPhysicsBody(circleOfRadius: wheel.size.width/2)
// Change this property as needed (increase it to slow faster)
wheel.physicsBody!.angularDamping = 0.25
wheel.physicsBody?.pinned = true
wheel.physicsBody?.affectedByGravity = false
addChild(wheel)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in:self)
let node = atPoint(location)
if node.name == "wheel" {
let dx = location.x - node.position.x
let dy = location.y - node.position.y
// Store angle and current time
startingAngle = atan2(dy, dx)
startingTime = touch.timestamp
node.physicsBody?.angularVelocity = 0
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in:self)
let node = atPoint(location)
if node.name == "wheel" {
let dx = location.x - node.position.x
let dy = location.y - node.position.y
let angle = atan2(dy, dx)
// Calculate angular velocity; handle wrap at pi/-pi
var deltaAngle = angle - startingAngle!
if abs(deltaAngle) > CGFloat.pi {
if (deltaAngle > 0) {
deltaAngle = deltaAngle - CGFloat.pi * 2
}
else {
deltaAngle = deltaAngle + CGFloat.pi * 2
}
}
let dt = CGFloat(touch.timestamp - startingTime!)
let velocity = deltaAngle / dt
node.physicsBody?.angularVelocity = velocity
// Update angle and time
startingAngle = angle
startingTime = touch.timestamp
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
startingAngle = nil
startingTime = nil
}
}