如何在 swift 中沿着车轮移动车身?
How to move car body along wheels in swift?
我一直在尝试移动车身和车轮。我创建了增强现实项目,其中将汽车模型放置在水平面上,汽车由四个按钮控制,即加速、转向、倒车和刹车。车左、右在加速和倒车的时候都是通过转向控制的。
实际上我现在可以将 3d 汽车模型放置在水平面上,但不知道如何随着车身向前和向后旋转车轮。
这是我一直在尝试放置 3d 对象的代码:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
// gives us the location of where we touched on the 2D screen.
let touchLocation = touch.location(in: sceneView)
// hitTest is performed to get the 3D coordinates corresponding to the 2D coordinates that we got from touching the screen.
// That 3d coordinate will only be considered when it is on the existing plane that we detected.
let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
// if we have got some results using the hitTest then do this.
if let hitResult = results.first {
let boxScene = SCNScene(named: "art.scnassets/porsche.scn")!
if let boxNode = boxScene.rootNode.childNode(withName: "car", recursively: true) {
print("box:::\(boxNode.childNodes)")
boxNode.position = SCNVector3(x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y + 0.15, z: hitResult.worldTransform.columns.3.z)
// finally the box is added to the scene.
sceneView.scene.rootNode.addChildNode(boxNode)
}
}
}
}
检测水平面功能代码:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if anchor is ARPlaneAnchor {
// anchors can be of many types, as we are just dealing with horizontal plane detection we need to downcast anchor to ARPlaneAnchor
let planeAnchor = anchor as! ARPlaneAnchor
// creating a plane geometry with the help of dimentions we got using plane anchor.
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
// a node is basically a position.
let planeNode = SCNNode()
// setting the position of the plane geometry to the position we got using plane anchor.
planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
// when a plane is created its created in xy plane instead of xz plane, so we need to rotate it along x axis.
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)
//create a material object
let gridMaterial = SCNMaterial()
//setting the material as an image. A material can also be set to a color.
gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")
// assigning the material to the plane
plane.materials = [gridMaterial]
// assigning the position to the plane
planeNode.geometry = plane
//adding the plane node in our scene
node.addChildNode(planeNode)
}
else {
return
}
}
非常感谢任何帮助!!!
这是一项相当全面的任务。
你应该把你的车做成 SCNPhysicsVehicle 的子类。
SCNPhysicsVehicle 是一种物理行为,它修改物理体使其表现得像汽车、摩托车或其他轮式车辆。
要构建车辆,请指定一个 SCNPhysicsBody 对象作为其底盘,并指定一组 SCNPhysicsVehicleWheel 对象作为其车轮。对于每个轮子,您定义物理特性,例如悬架和牵引力,并在场景中关联一个节点以提供轮子的大小和视觉表示。构建车辆后,您可以控制它的加速、制动和转向。
一般:https://developer.apple.com/documentation/scenekit/scnphysicsbody
车轮:https://developer.apple.com/documentation/scenekit/scnphysicsvehiclewheel
示例:
var vehicle = SCNPhysicsVehicle()
你需要用静态体创建地面。
func createGround(planeAnchor: ARPlaneAnchor) -> SCNNode {
let ground = SCNNode(geometry: SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(CGFloat(planeAnchor.extent.z))))
ground.position = SCNVector3(planeAnchor.center.x,planeAnchor.center.y,planeAnchor.center.z)
ground.eulerAngles = SCNVector3(90.degreesToRadians, 0, 0)
let staticBody = SCNPhysicsBody.static() // it must be static
ground.physicsBody = staticBody
return ground
}
您需要设置您的汽车。
func setupCar() {
let scene = SCNScene(named: "YourScene.scn")
let chassis = (scene?.rootNode.childNode(withName: "chassis", recursively: true))! // Your chassis
let frontLeftWheel = chassis.childNode(withName: "frontLeftWheel", recursively: true)!
let frontRightWheel = chassis.childNode(withName: "frontRightWheel", recursively: true)!
let rearLeftWheel = chassis.childNode(withName: "rearLeftWheel", recursively: true)!
let rearRightWheel = chassis.childNode(withName: "rearRightWheel", recursively: true)!
// physic behavior for wheels
let v_frontLeftWheel = SCNPhysicsVehicleWheel(node: frontLeftWheel)
let v_frontRightWheel = SCNPhysicsVehicleWheel(node: frontRightWheel)
let v_rearRightWheel = SCNPhysicsVehicleWheel(node: rearLeftWheel)
let v_rearLeftWheel = SCNPhysicsVehicleWheel(node: rearRightWheel)
chassis.position = SCNVector(0,0,0) // insert your desired position
let body = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(node: chassis, options: [SCNPhysicsShape.Option.keepAsCompound: true]))
body.mass = 1
chassis.physicsBody = body
self.vehicle = SCNPhysicsVehicle(chassisBody: chassis.physicsBody!, wheels: [v_rearRightWheel, v_rearLeftWheel, v_frontRightWheel, v_frontLeftWheel])
self.sceneView.scene.physicsWorld.addBehavior(self.vehicle)
self.sceneView.scene.rootNode.addChildNode(chassis)
}
现在你可以操纵你的车了。
func renderer(_ renderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: TimeInterval) {
var engineForce: CGFloat = 5
var brakingForce: CGFloat = 0
// here you can manipulate your car steering angle
self.vehicle.setSteeringAngle(0, forWheelAt: 2)
self.vehicle.setSteeringAngle(0, forWheelAt: 3)
self.vehicle.applyEngineForce(engineForce, forWheelAt: 0)
self.vehicle.applyEngineForce(engineForce, forWheelAt: 1)
self.vehicle.applyBrakingForce(0, forWheelAt: 0)
self.vehicle.applyBrakingForce(0, forWheelAt: 1)
}
P.S。不要忘记添加到您的 viewDidLoad():
self.sceneView.delegate = self
self.sceneView.scene?.physicsWorld.contactDelegate = self
P.P.S 这只是一般的想法,您必须做一些研究并找到适合您的具体情况的工作解决方案。
给你一个小提示,转向可以通过 CoreMotion 完成。
希望对您有所帮助!
我一直在尝试移动车身和车轮。我创建了增强现实项目,其中将汽车模型放置在水平面上,汽车由四个按钮控制,即加速、转向、倒车和刹车。车左、右在加速和倒车的时候都是通过转向控制的。
实际上我现在可以将 3d 汽车模型放置在水平面上,但不知道如何随着车身向前和向后旋转车轮。
这是我一直在尝试放置 3d 对象的代码:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
// gives us the location of where we touched on the 2D screen.
let touchLocation = touch.location(in: sceneView)
// hitTest is performed to get the 3D coordinates corresponding to the 2D coordinates that we got from touching the screen.
// That 3d coordinate will only be considered when it is on the existing plane that we detected.
let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
// if we have got some results using the hitTest then do this.
if let hitResult = results.first {
let boxScene = SCNScene(named: "art.scnassets/porsche.scn")!
if let boxNode = boxScene.rootNode.childNode(withName: "car", recursively: true) {
print("box:::\(boxNode.childNodes)")
boxNode.position = SCNVector3(x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y + 0.15, z: hitResult.worldTransform.columns.3.z)
// finally the box is added to the scene.
sceneView.scene.rootNode.addChildNode(boxNode)
}
}
}
}
检测水平面功能代码:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if anchor is ARPlaneAnchor {
// anchors can be of many types, as we are just dealing with horizontal plane detection we need to downcast anchor to ARPlaneAnchor
let planeAnchor = anchor as! ARPlaneAnchor
// creating a plane geometry with the help of dimentions we got using plane anchor.
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
// a node is basically a position.
let planeNode = SCNNode()
// setting the position of the plane geometry to the position we got using plane anchor.
planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
// when a plane is created its created in xy plane instead of xz plane, so we need to rotate it along x axis.
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)
//create a material object
let gridMaterial = SCNMaterial()
//setting the material as an image. A material can also be set to a color.
gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")
// assigning the material to the plane
plane.materials = [gridMaterial]
// assigning the position to the plane
planeNode.geometry = plane
//adding the plane node in our scene
node.addChildNode(planeNode)
}
else {
return
}
}
非常感谢任何帮助!!!
这是一项相当全面的任务。
你应该把你的车做成 SCNPhysicsVehicle 的子类。
SCNPhysicsVehicle 是一种物理行为,它修改物理体使其表现得像汽车、摩托车或其他轮式车辆。
要构建车辆,请指定一个 SCNPhysicsBody 对象作为其底盘,并指定一组 SCNPhysicsVehicleWheel 对象作为其车轮。对于每个轮子,您定义物理特性,例如悬架和牵引力,并在场景中关联一个节点以提供轮子的大小和视觉表示。构建车辆后,您可以控制它的加速、制动和转向。
一般:https://developer.apple.com/documentation/scenekit/scnphysicsbody
车轮:https://developer.apple.com/documentation/scenekit/scnphysicsvehiclewheel
示例:
var vehicle = SCNPhysicsVehicle()
你需要用静态体创建地面。
func createGround(planeAnchor: ARPlaneAnchor) -> SCNNode { let ground = SCNNode(geometry: SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(CGFloat(planeAnchor.extent.z)))) ground.position = SCNVector3(planeAnchor.center.x,planeAnchor.center.y,planeAnchor.center.z) ground.eulerAngles = SCNVector3(90.degreesToRadians, 0, 0) let staticBody = SCNPhysicsBody.static() // it must be static ground.physicsBody = staticBody return ground }
您需要设置您的汽车。
func setupCar() { let scene = SCNScene(named: "YourScene.scn") let chassis = (scene?.rootNode.childNode(withName: "chassis", recursively: true))! // Your chassis let frontLeftWheel = chassis.childNode(withName: "frontLeftWheel", recursively: true)! let frontRightWheel = chassis.childNode(withName: "frontRightWheel", recursively: true)! let rearLeftWheel = chassis.childNode(withName: "rearLeftWheel", recursively: true)! let rearRightWheel = chassis.childNode(withName: "rearRightWheel", recursively: true)! // physic behavior for wheels let v_frontLeftWheel = SCNPhysicsVehicleWheel(node: frontLeftWheel) let v_frontRightWheel = SCNPhysicsVehicleWheel(node: frontRightWheel) let v_rearRightWheel = SCNPhysicsVehicleWheel(node: rearLeftWheel) let v_rearLeftWheel = SCNPhysicsVehicleWheel(node: rearRightWheel) chassis.position = SCNVector(0,0,0) // insert your desired position let body = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(node: chassis, options: [SCNPhysicsShape.Option.keepAsCompound: true])) body.mass = 1 chassis.physicsBody = body self.vehicle = SCNPhysicsVehicle(chassisBody: chassis.physicsBody!, wheels: [v_rearRightWheel, v_rearLeftWheel, v_frontRightWheel, v_frontLeftWheel]) self.sceneView.scene.physicsWorld.addBehavior(self.vehicle) self.sceneView.scene.rootNode.addChildNode(chassis) }
现在你可以操纵你的车了。
func renderer(_ renderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: TimeInterval) { var engineForce: CGFloat = 5 var brakingForce: CGFloat = 0 // here you can manipulate your car steering angle self.vehicle.setSteeringAngle(0, forWheelAt: 2) self.vehicle.setSteeringAngle(0, forWheelAt: 3) self.vehicle.applyEngineForce(engineForce, forWheelAt: 0) self.vehicle.applyEngineForce(engineForce, forWheelAt: 1) self.vehicle.applyBrakingForce(0, forWheelAt: 0) self.vehicle.applyBrakingForce(0, forWheelAt: 1) }
P.S。不要忘记添加到您的 viewDidLoad():
self.sceneView.delegate = self
self.sceneView.scene?.physicsWorld.contactDelegate = self
P.P.S 这只是一般的想法,您必须做一些研究并找到适合您的具体情况的工作解决方案。
给你一个小提示,转向可以通过 CoreMotion 完成。
希望对您有所帮助!