1

この質問を単純化するように求められたので、それが私がやっていることです。

SpriteKit の物理ジョイント (およびおそらく物理ボディ プロパティ) で苦労しています。すべてのサブクラスと多くの構成を試しましたが、何も機能しないか、何か間違ったことをしているように見えます。

私はスネークゲームを開発しています。ユーザーは蛇の頭を一定の速度で前方に動かし、ユーザーはそれを時計回りまたは反時計回りに回すことができます。残りのすべてのヘビの破片は、頭をたどる必要があります。それらは、少し前に頭があったのとまったく同じパスを移動する必要があります。

このゲームではピン ジョイントが答えになると思います。アンカー ポイントは要素間の正確な中心にあります。

残念ながら、結果は完璧ではありません。構造は完全な円になるはずですが、そうではありません。コードと、現在の効果を示す gif を添付します。望ましい効果を得るために、ここで物理的な身体や関節のどの特性を適用する必要があるかを提案するのに十分な経験がある人はいますか?

ここに画像の説明を入力

私のコード:

class GameScene: SKScene {
    private var elements = [SKNode]()

    override func didMove(to view: SKView) {
        physicsWorld.gravity = CGVector(dx: 0, dy: 0)

        let dummyTurnNode = SKNode()
        dummyTurnNode.position = CGPoint(x: size.width / 2 - 50, y: size.height / 2)
        let dummyTurnBody = SKPhysicsBody(circleOfRadius: 1)
        dummyTurnBody.isDynamic = false
        dummyTurnNode.physicsBody = dummyTurnBody
        addChild(dummyTurnNode)

        for index in 0..<5 {
            let element = SKShapeNode(circleOfRadius: 10)
            let body = SKPhysicsBody(circleOfRadius: 10)
            body.linearDamping = 0
            // body.mass = 0
            element.physicsBody = body
            element.position = CGPoint(x: size.width / 2, y: size.height / 2 - 30 * CGFloat(index))
            elements.append(element)
            addChild(element)

            let label = SKLabelNode(text: "A")
            label.fontSize = 10
            label.fontName = "Helvetica-Bold"
            element.addChild(label)

            if index == 0 {
                element.fillColor = UIColor.blue()

                body.velocity = CGVector(dx: 0, dy: 30)

                let dummyTurnJoint = SKPhysicsJointPin.joint(withBodyA: dummyTurnBody, bodyB: body, anchor: dummyTurnNode.position)
                physicsWorld.add(dummyTurnJoint)
            } else {
                body.linearDamping = 1

                element.fillColor = UIColor.red()
                let previousElement = elements[index - 1]
                let connectingJoint = SKPhysicsJointPin.joint(withBodyA: previousElement.physicsBody!, bodyB: body, anchor: CGPoint(x: size.width / 2, y: size.height / 2 - 30 * CGFloat(index) + CGFloat(15)))
                physicsWorld.add(connectingJoint)
            }
        }
    }

    override func update(_ currentTime: TimeInterval) {
        let head = elements.first!.physicsBody!
        var velocity = head.velocity
        velocity.normalize()
        velocity.multiply(30)
        head.velocity = velocity
    }
}

extension CGVector {
    var rwLength: CGFloat {
        let xSq = pow(dx, 2)
        let ySq = pow(dy, 2)
        return sqrt(xSq + ySq)
    }

    mutating func normalize() {
        dx /= rwLength
        dy /= rwLength
    }

    mutating func multiply(_ factor: CGFloat) {
        dx *= factor
        dy *= factor
    }
}
4

1 に答える 1

2

「残りのすべてのヘビの破片は頭をたどる必要があります。それらは、頭が少し前にあったのとまったく同じ経路をたどる必要があります。」

物理ジョイントを使用すると、何をしても分散が発生する可能性が高いことに注意してください。完璧に近い場合でも、フードの下に丸め誤差があり、パスが正確ではなくなります。

すべての尾の部分が等しい場合は、別のアプローチを使用することもできます。これは、彗星の尾に対して行ったことです。基本的には、尾オブジェクトの配列があり、フレームごとに移動すると、最後の尾オブジェクトが常に頭オブジェクトと同じ位置に移動します。head-object の z 位置が高い場合、尾はその下に描画されます。

尾を順番に保持する必要がある場合は、頭の位置 (フレームごとのパス) の配列を格納することでアプローチを変更し、フレームごとの更新呼び出しでそのパスに沿って尾のオブジェクトを配置できます。

たとえば、以下の私のコードを参照してください。

これらは head-object 変数です:

var tails = [SKEmitterNode]()
var tailIndex = 0

head init 関数で、tail オブジェクトをインスタンス化します。

for _ in 0...MAX_TAIL_INDEX
        {
            if let remnant = SKEmitterNode(fileNamed: "FireTail.sks")
            {
                p.tails.append(remnant)
            }
        }

以下をフレームごとに呼び出します。

func drawTail()
{
    if tails.count > tailIndex
    {
        tails[tailIndex].resetSimulation()
        tails[tailIndex].particleSpeed = velocity() / 4
        tails[tailIndex].emissionAngle = zRotation - CGFloat(M_PI_2) // opposite direction
        tails[tailIndex].position = position
        tailIndex = tailIndex < MAX_TAIL_INDEX ? tailIndex + 1 : 0
    }
}

シーンの update() 関数から呼び出すと、結果として得られる効果は実際には非常にスムーズです。

于 2016-07-15T08:08:35.190 に答える