【问题标题】:How to apply a SCNAction & An Impulse Force to a SCNNode如何将 SCNAction 和脉冲力应用于 SCNNode
【发布时间】:2017-01-11 10:04:07
【问题描述】:

嘿,我有一个球,可以通过施加力移动。我试图让它做的基本上是重力作用于它的因果效应,同时它在空气中移动到目的地。基本上,当“移动到”动作正在播放时,重力不会产生影响,因此它不会慢慢地落到地面上,而是移动到最终位置,然后当“移动到”动作停止时它会直接落下。对场景中的重力做。

我试图让球以弧线投掷并落在目标上?

代码:

                   func CreateBall() {
    let BallScene = SCNScene(named: "art.scnassets/Footballs.dae")
    Ball = BallScene!.rootNode.childNodeWithName("Armature", recursively: true)! //the Amature/Bones
    Ballbody = BallScene!.rootNode.childNodeWithName("Ball", recursively: true)!

    let collisionCapsuleRadius3 = CGFloat(0.01) // Width of physicsBody
    let collisionCapsuleHeight3 = CGFloat(0.01) // Height of physicsBody
    Ball.position = SCNVector3Make(Guy.position.x, Guy.position.y, Guy.position.z)
    Ball.scale = SCNVector3Make(5, 5, 5)
    Ball.rotation = SCNVector4Make(0.0,0.0,0.0,0.0) // x,y,z,w

    Ball.physicsBody = SCNPhysicsBody(type: .Dynamic, shape:SCNPhysicsShape(geometry: SCNCapsule(capRadius: collisionCapsuleRadius3, height: collisionCapsuleHeight3), options:nil))
    Ball.physicsBody?.affectedByGravity = true
    Ball.physicsBody?.friction = 1 //
    Ball.physicsBody?.restitution = 0 //bounceness of the object. 1.0 will boounce forever
    Ball.physicsBody?.angularDamping = 1 // ability to rotate
    Ball.physicsBody?.mass = 1
    Ball.physicsBody?.rollingFriction = 1
    Ball.physicsBody!.categoryBitMask = BitmaskCollision4
    Ball.physicsBody?.contactTestBitMask = BitmaskCollision3 //| BitmaskCollision2
    Ballbody.physicsBody?.collisionBitMask = BitmaskCollision2 | BitmaskCollision3 | BitmaskCollision//| BitmaskCollision2

    scnView.scene!.rootNode.addChildNode(Ball)
    scnView.scene!.rootNode.addChildNode(Ballbody)


    }
    CreateBall()

现在这就是魔法发生的地方:

                   scnView.scene!.physicsWorld.gravity = SCNVector3(x: 0, y: -9.8, z: 0)

                    let location = SCNVector3(Guy2.presentationNode.position.x, 0.0, Guy2.presentationNode.position.z + Float(50) )
                    let moveAction = SCNAction.moveTo(location, duration: 2.0)
                    Ball.runAction(SCNAction.sequence([moveAction]))


                    let forceApplyed = SCNVector3(x: 0.0, y: 100.0 , z: 0.0)
                     Ball.physicsBody?.applyForce(forceApplyed, atPosition: Ball.presentationNode.position, impulse: true)

【问题讨论】:

  • 您实际上应该只通过在运动学体上使用动作或在动态体上使用物理来移动节点。但不能将两者结合起来。您是否想让您的球以弧线投掷并落在目标上?
  • 是的,这正是我想要做的 :) @JamesP 看到我可以对物体施加一个力并将它向左、右、后、前、上、下发射。但是它只会朝那个方向发射它不会去一个特定的点目标
  • 我前几天做了这个,我现在没有代码(我可以在我发布的时候发布),但是我从这个链接修改了BallisticVel 函数: answers.unity3d.com/questions/248788/…
  • 好的,我会看看谢谢@JamesP
  • 翻译成 swift 有点困难,但大多数我只是不知道它到底是做什么的。希望你在发布 ti 时编码会解释一切@JamesP

标签: ios swift scnnode


【解决方案1】:

将 SCNActions 和物理结合起来是行不通的,你需要使用其中之一。使用物理学,您可以计算将节点推向目标所需的确切力。

我已经为 Unity found here 调整了一个解决方案,并使用了一个 SCNVector3 extension,这使得一些计算变得更加容易。

基本上你传入一个你想要抛出的SCNNode,一个目标的SCNVector3和一个你想要抛出节点的angle(以弧度为单位)。然后,此函数将计算出达到目标所需的力。

func shootProjectile() {
    let velocity = ballisticVelocity(ball, target: target.position, angle: Float(0.4))
    ball.physicsBody?.applyForce(velocity, impulse: true)
}

func ballisticVelocity(projectile:SCNNode, target: SCNVector3, angle: Float) -> SCNVector3 {
        let origin = projectile.presentationNode.position
        var dir = target - origin       // get target direction
        let h = dir.y                   // get height difference
        dir.y = 0                       // retain only the horizontal direction
        var dist = dir.length()         // get horizontal distance
        dir.y = dist * tan(angle)       // set dir to the elevation angle
        dist += h / tan(angle)          // correct for small height differences
        // calculate the velocity magnitude
        let vel = sqrt(dist * -scene.physicsWorld.gravity.y / sin(2 * angle))
        return dir.normalized() * vel * Float(projectile.physicsBody!.mass)
}

还要将physicsBody的damping设置为0,否则会受到空气阻力的影响。

我不会假装确切地知道它是如何工作的,但 Wikipedia 有文章解释了它背后的所有数学原理。

更新

自从使用上面的代码后,我注意到它并不总是有效,尤其是当原点和目标的高度不同时。从同一个论坛这个功能似乎更可靠。

func calculateBestThrowSpeed(origin: SCNVector3, target: SCNVector3, timeToTarget:Float) -> SCNVector3 {

    let gravity:SCNVector3 = sceneView.scene!.physicsWorld.gravity

    let toTarget = target - origin
    var toTargetXZ = toTarget
    toTargetXZ.y = 0

    let y = toTarget.y
    let xz = toTargetXZ.length()

    let t = timeToTarget
    let v0y = y / t + 0.5 * gravity.length() * t
    let v0xz = xz / t


    var result = toTargetXZ.normalized()
    result *= v0xz
    result.y = v0y

    return result
}

【讨论】:

  • 我在'var dir = target - origin'上也遇到了一点错误它说二进制运算符'-'不能应用于两个'SCNVector3'操作数@James P
  • 您需要在您的项目中包含 SCNVector3 扩展(上面链接)。
  • 有没有一种方法可以计算它的方向,就像它可以确定它需要多少功率,但是它需要向哪个方向扔,就像这样向左或向右。 @詹姆斯P
  • 我觉得和'dir.y = 0 //只保留水平方向有关 var dist = dir.length() //得到水平距离'
  • 这就是它的作用,它会给你一个 SCNVector3,在 x、y 和 z 上具有正确的力。如果你将该力施加到节点上,它将朝着目标的方向前进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
相关资源
最近更新 更多