如何限制两条锚定线的运动,使它们像钟摆一样连续摆动

iGe*_*tIt 17 sprite-kit swift swift3

我创建了两条固定在精灵上的线,相距30˚.我希望两条线像摆锤一样左右摆动,总是从一端到另一端摆动(这样它们在它们的初始位置的左右摆动45°).请看下面我想要实现的目标:

在此输入图像描述

以下是我能够实现的代码:

extension Int {
  var degreesToRadians: Double { return Double(self) * .pi / 180 }
}
extension FloatingPoint {
  var degreesToRadians: Self { return self * .pi / 180 }
  var radiansToDegrees: Self { return self * 180 / .pi }
}

class GameScene: SKScene, SKPhysicsContactDelegate {

var anchorSprite = SKSpriteNode(imageNamed: "swingPin")
var armLeft = SKSpriteNode(imageNamed: "swingArm")
var armRight = SKSpriteNode(imageNamed: "swingArm")

override func didMove(to view: SKView) {


    self.physicsWorld.gravity = CGVector(dx: 0, dy: -1.8)
    self.physicsWorld.contactDelegate = self

    var tealBg = SKSpriteNode(imageNamed: "tealBg")
    tealBg.position = CGPoint(x: frame.midX, y: frame.midY)
    tealBg.zPosition = 10
    addChild(tealBg)

    anchorSprite.position = CGPoint(x: frame.midX, y: frame.midY + frame.midY/2)
    anchorSprite.zPosition = 20

    anchorSprite.physicsBody = SKPhysicsBody(rectangleOf: anchorSprite.frame.size)
    anchorSprite.physicsBody?.categoryBitMask = pinCategory
    anchorSprite.physicsBody?.isDynamic = false
    addChild(anchorSprite)

    armRight.anchorPoint = CGPoint(x: 0.5, y: 1)
    armRight.position = anchorSprite.position
    armRight.zPosition = 20
    armRight.physicsBody = SKPhysicsBody(rectangleOf: armRight.frame.size)
    armRight.zRotation = CGFloat(Double(15).degreesToRadians)//CGFloat(Double.pi/6)
    armRight.physicsBody!.isDynamic = true

    addChild(armRight)

    armLeft.anchorPoint = CGPoint(x: 0.5, y: 1)
    armLeft.position = anchorSprite.position
    armLeft.zPosition = 20
    armLeft.physicsBody = SKPhysicsBody(rectangleOf: armRight.frame.size)
    armLeft.zRotation = CGFloat(Double(-15).degreesToRadians)//CGFloat(-Double.pi/6)
    armLeft.physicsBody!.isDynamic = true
    addChild(armLeft)

    // Create joint between two objects
    //Pin joint
    var pinAndRightArmJoint = SKPhysicsJointPin.joint(withBodyA: anchorSprite.physicsBody!, bodyB: armRight.physicsBody!, anchor: CGPoint(x: anchorSprite.position.x, y: self.armRight.frame.maxY))
    self.physicsWorld.add(pinAndRightArmJoint)

    var pinAndLeftArmJoint = SKPhysicsJointPin.joint(withBodyA: anchorSprite.physicsBody!, bodyB: armLeft.physicsBody!, anchor: CGPoint(x: anchorSprite.position.x, y: self.armLeft.frame.maxY))
    self.physicsWorld.add(pinAndLeftArmJoint)

    var fixArms = SKPhysicsJointFixed.joint(withBodyA: armLeft.physicsBody!, bodyB: armRight.physicsBody!, anchor: CGPoint.zero)
    self.physicsWorld.add(fixArms)

    pinAndRightArmJoint.shouldEnableLimits = true
    pinAndRightArmJoint.lowerAngleLimit = CGFloat(Double(-60).degreesToRadians)
    pinAndRightArmJoint.upperAngleLimit = CGFloat(Double(60).degreesToRadians)

 }


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    //armRight.physicsBody?.angularVelocity = -100.0

     let seq = SKAction.sequence([
        SKAction.rotate(byAngle: CGFloat(Double(45).degreesToRadians), duration: 0.5),
        SKAction.rotate(byAngle: CGFloat(Double(-45).degreesToRadians), duration: 1.0),
        SKAction.rotate(byAngle: CGFloat(Double(45).degreesToRadians), duration: 1.0),
        SKAction.rotate(byAngle: CGFloat(Double(-45).degreesToRadians), duration: 1.0),
        SKAction.rotate(byAngle: CGFloat(Double(45).degreesToRadians), duration: 1.0),
        SKAction.rotate(byAngle: CGFloat(Double(-45).degreesToRadians), duration: 1.0)
])
    armRight.run(seq)
}
Run Code Online (Sandbox Code Playgroud)

从上面的代码我设置了较低和较高的角度限制,并尝试运行一个动作,但这只是使线条以一种非常不切实际的方式横向倾斜.我也尝试在物理体上应用角速度,但这只是使它以不一致的速度短暂摆动(我需要它从一端到另一端一致地摆动).

NB

由于每次都需要它从头到尾摆动,我需要摆动周期每次都保持一致,不一定是恒定的.当线条移动到中心时,一个周期通常会更快地摆动,而当从一个方向改变到另一个方向时,一个周期会减慢一点.这就是我想要运动的感觉.

mog*_*ter 7

这是实际的答案:

替换addChild(armRight)anchorSprite.addChild(armRight).替换addChild(armLeft)anchorSprite.addChild(armLeft).删除armRight.position = anchorSprite.position并删除armLeft.position = anchorSprite.position.此外,除非您在代码中使用物理关节进行其他移动,否则请删除所有这些,因为我的解决方案不需要关节.

现在你的手臂是儿童,anchorSprite并受到其坐标系统的影响.如果要同时在同一方向旋转两个手臂,可以在anchorSprite上运行旋转动作.如果您希望手臂朝不同方向旋转,则必须分别在每个手臂上执行旋转动作.对于这两种情况,你可以使用我为这个问题上的赏金所做的这个方便的功能:-P

func runPendulumRotationOnNode(_ node:SKNode, withAngle angle:CGFloat, period:TimeInterval, key:String) {
    let initialRotate = SKAction.rotate(byAngle: angle/2, duration: period/2)
    initialRotate.timingMode = .easeOut
    let rotate = SKAction.rotate(byAngle: angle, duration: period)
    rotate.timingMode = .easeInEaseOut
    let rotateForever = SKAction.repeatForever(SKAction.sequence([rotate.reversed(), rotate]))
    let rotateSequence = SKAction.sequence([initialRotate, rotateForever])
    node.run(rotateSequence, withKey:key)
}
Run Code Online (Sandbox Code Playgroud)

我测试过它,效果很好!您可以像这样调用它来将两个手臂旋转在一起:

runPendulumRotationOnNode(anchorSprite, withAngle:CGFloat.pi/2, period:0.5, key:"")
Run Code Online (Sandbox Code Playgroud)

或者以相反的方向旋转手臂,您可以像这样使用它:

runPendulumRotationOnNode(armRight, withAngle:CGFloat.pi/2, period:0.5, key:"")
runPendulumRotationOnNode(armLeft, withAngle:-CGFloat.pi/2, period:0.5, key:"")
Run Code Online (Sandbox Code Playgroud)

一些小笔记,注意我的使用方式CGFloat.pi,π的简单常数.此功能还假设摆锤在旋转的中点开始,因此π/ 2(90度)将使臂π/ 4(45度)向任一方向旋转.