如何在SceneKit中移动SCNNode并受重力影响?SCNAction.move(to:SCNVector3)无效
解决SceneKit中移动节点同时保留重力的问题
嗨,这问题我之前也碰到过!其实核心原因是SCNAction.move(to:)是直接强制设置节点的位置,会完全接管节点的位置控制,导致SceneKit的物理引擎(包括重力)暂时失效——毕竟物理引擎没法和硬编码的位置更新抢控制权嘛。
给你两个靠谱的解决方案,根据你的需求选就行:
方案一:用物理引擎驱动移动(推荐)
既然要保留重力,那最好让物理引擎全权负责节点的运动。给节点添加动态物理体后,用力/冲量或者直接设置速度来实现移动,这样重力会自动和移动效果叠加。
举个Swift代码例子:
// 第一步:给节点添加动态物理体(必须是.dynamic类型才会受重力影响) node.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(node: node, options: nil)) // 可选:如果需要调整重力大小,可以修改场景的物理世界参数 scene.physicsWorld.gravity = SCNVector3(0, -9.8, 0) // 第二步:施加冲量让节点移动(比如朝X轴正方向移动) let moveImpulse = SCNVector3(20, 0, 0) node.physicsBody?.applyForce(moveImpulse, asImpulse: true)
这样节点会一边向前移动,一边受重力影响自然下落,完全符合物理规律。
方案二:自定义SCNAction同步物理体状态
如果你一定要用SCNAction的方式(比如需要精确控制移动路径和时长),可以用SCNAction.customAction,在每一步更新节点位置的同时,同步更新物理体的位置,让物理引擎继续处理重力。
代码示例:
// 先确保节点有动态物理体 node.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(node: node, options: nil)) // 自定义移动动作:2秒内从(0,5,0)移动到(10,5,0),同时保留重力 let customMoveAction = SCNAction.customAction(duration: 2.0) { (node, elapsedTime) in let progress = elapsedTime / 2.0 let startPos = SCNVector3(0, 5, 0) let endPos = SCNVector3(10, 5, 0) // 计算当前帧的位置 let currentPos = SCNVector3( startPos.x + (endPos.x - startPos.x) * progress, startPos.y + (endPos.y - startPos.y) * progress, startPos.z + (endPos.z - startPos.z) * progress ) // 同时更新节点位置和物理体位置 node.position = currentPos node.physicsBody?.position = currentPos } // 执行动作 node.runAction(customMoveAction)
这种方法下,节点会按照你设定的路径移动,同时物理引擎依然会给节点施加重力,你会看到节点一边移动一边慢慢下落。
最后提醒一句:不管用哪种方案,节点的物理体类型必须是.dynamic,static或者kinematic类型的节点是不会受重力影响的哦!
内容的提问来源于stack exchange,提问作者Andrea P.
相关产品推荐
相关产品推荐

