我创建了两条固定在精灵上的线,它们相距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)
}
从上面的代码中我设置了下限和上限角度,并尝试运行一个动作,但这只是使线条以一种非常不现实的方式向侧面倾斜。我也尝试在物理体上应用角速度,但这只是让它以不一致的速度短暂摆动(我需要它从一端到另一端一直摆动)。
NB
由于我每次都需要它从头到尾摆动,我需要摆动周期每次都保持一致,不一定是恒定的。当线条移动到中心时,一个周期通常会更快地摆动,当从一个方向改变到另一个方向时,一个周期会减慢一点。这就是我想要运动的感觉。
答案 0 :(得分: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)
}
我测试了它,效果很好!您可以像这样调用它来将两个手臂旋转在一起:
runPendulumRotationOnNode(anchorSprite, withAngle:CGFloat.pi/2, period:0.5, key:"")
或者以相反方向旋转手臂,您可以像这样使用它:
runPendulumRotationOnNode(armRight, withAngle:CGFloat.pi/2, period:0.5, key:"")
runPendulumRotationOnNode(armLeft, withAngle:-CGFloat.pi/2, period:0.5, key:"")
一些小注,请注意我如何使用CGFloat.pi
,这是π的简单常量。此功能还假设摆锤在旋转的中点处开始,因此π/ 2(90度)将使臂π/ 4(45度)向任一方向旋转。
答案 1 :(得分:0)
快速的5 扩展版本,用于优质的mogelbuster code:
extension SKAction {
class func pendulum(withAngle angle:CGFloat, period:TimeInterval, key:String) -> SKAction {
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]))
return SKAction.sequence([initialRotate, rotateForever])
}
}
用法:
let pendulum = SKAction.pendulum(withAngle: CGFloat.pi/2, period: 0.5, key: "pendulum")
self.mynode.run(pendulum)