SpriteNode を 1 本の指で「タッチ アンド ドラッグ」して回転させるには、次のようにします。
- ぐるぐるしない
- 円を描くように移動します (この部分は、コードのみのソリューションと SKS ファイルの両方を使用して数回成功しました)
- 意味のある値を生成します (物理的なコントロール ノブのように)
- 指を置いている間は動きますが、指を離すと動きません
私が試したこと:
CGAffineTransform の CGAffineTransformMakeRotationを使用して、SpriteKit のノブを回転させます。しかし、SpriteNode で CGAffineTransformMakeRotation を使用する方法がわかりません。シーン内またはその上に別の種類のオブジェクトを配置することもできますが、それは正しくありません。
たとえば、Matthijs Hollemans の MHRotaryKnob https://github.com/hollance/MHRotaryKnob
です。Hollemans ノブを Objective C から Swift 4 に変換しましたが、SpriteKit でそれを使用してスプライトを回転させようとすると問題が発生しました。knobImageView.transform = CGAffineTransformMakeRotation (newAngle * M_PI/180.0);
SpriteKit で Swiftを使用する方法がわからなかったので、わかりませんでした。Hollemans Objective C クラスを使用して UIImage をシーンの上にプッシュできることはわかっていますが、それは最善の解決策でも最も洗練された解決策でもないようです。
また、コードの CGAffineTransform 部分の処理に関するAllan Weirの提案 を使用して、Objective C から Wexのソリューションを Swift Rotate image on centerに翻訳しまし た。動作しません。
.physicalBody を使用せずに、スプライトに直接zRotationを設定しようとしましたが、役に立ちませんでした。同じぎくしゃくした動きで、止めたいところで止まらない。ラジアン角の前に「-」を付けても、指でドラッグした方向とは反対の方向に移動します。
また、スタック オーバーフローで 0x141Eのソリューションを試しました:固定点を中心にノードをドラッグして回転 させます。 )。この解決策はぎくしゃくし、指にスムーズに追従せず、ノブを特定のポイントに一貫して動かすことができません。摩擦、質量、angularDamping と linearDamping、または SKSpriteNode の速度を下げるためにphysicsBody 属性を設定するかどうかは問題ではありません。
また、SpriteKit を使用して Swift 4 で適切なソリューションを探してインターネットを精査しましたが、これまでのところ役に立ちませんでした。
import Foundation
import SpriteKit
class Knob: SKSpriteNode
{
var startingAngle: CGFloat?
var currentAngle: CGFloat?
var startingTime: TimeInterval?
var startingTouchPoint: CGPoint?
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
self.setupKnob()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupKnob()
}
func setupKnob() {
self.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(self.size.height))
self.physicsBody?.pinned = true
self.physicsBody?.isDynamic = true
self.physicsBody?.affectedByGravity = false
self.physicsBody?.allowsRotation = true
self.physicsBody?.mass = 30.0
//self.physicsBody?.friction = 0.8
//self.physicsBody?.angularDamping = 0.8
//self.physicsBody?.linearDamping = 0.9
//self.speed = 0.1
self.isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in:self)
let node = atPoint(location)
startingTouchPoint = CGPoint(x: location.x, y: location.y)
if node.name == "knobHandle" {
let dx = location.x - node.position.x
let dy = location.y - node.position.y
startingAngle = atan2(dy, dx)
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in:self)
let node = atPoint(location)
guard startingAngle != nil else {return}
if node.name == "knobHandle" {
let dx:CGFloat = location.x - node.position.x
let dy:CGFloat = location.y - node.position.y
var angle: CGFloat = atan2(dy, dx)
angle = ((angle) * (180.0 / CGFloat.pi))
let rotate = SKAction.rotate(toAngle: angle, duration: 2.0, shortestUnitArc: false)
self.run(rotate)
startingAngle = angle
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
var touch: UITouch = touches.first!
var location: CGPoint = touch.location(in: self)
self.removeAllActions()
startingAngle = nil
startingTime = nil
}
}
編集: 度への変換を削除し、 SKAction の期間を 1.0 に変更すると、SKAction.rotate(toAngle:duration: 1.0, shortestUnitArc:)
ほとんど機能します。レバーは方向をうまく変えません。つまり、移動していた方向と反対に動かそうとすると、ドラッグしている新しい方向ではなく、アンカーポイントの周りの古い方向に進み続けることがあります。
編集 2: GreatBigBoreと私は、SKAction ローテーションと self.zRotation の両方について説明しました。上記のコードと以下のコードです。
編集 3: sicvayneは SKScene のコードをいくつか提案し、私は SKSpriteNode (以下) に適応しました。一貫して移動したり、特定の場所で停止したりできません。
import Foundation
import SpriteKit
class Knob: SKSpriteNode {
var fingerLocation = CGPoint()
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
self.setupKnob()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupKnob()
}
func setupKnob() {
self.isUserInteractionEnabled = true
}
func rotateKnob(){
let radians = atan2(fingerLocation.x - self.position.x, fingerLocation.y - self.position.y)
self.zRotation = -radians
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
fingerLocation = touch.location(in: self)
}
self.rotateKnob()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
/*override func update(_ currentTime: TimeInterval) { //this is a SKScene function
rotateKnob()
}*/
}