我的两样东西是:一个球和一个桶。水桶由两个子节点组成,每当球进入水桶并接触水桶的“圆柱体”时,我就要做些什么。但是,当我将baseNode添加为名为childNode的childNode时,我的bucket将消失在场景中,不会加载任何内容。我怎样才能让这件事和正在发生的联系一起工作。
import UIKit
import SceneKit
import ARKit
enum BodyType: Int{
case ballNode = 1
case baseNode = 2
}
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
@IBOutlet weak var AddBasketBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
sceneView.scene.physicsWorld.contactDelegate = self as? SCNPhysicsContactDelegate
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene()
// Set the scene to the view
sceneView.scene = scene
registerGestureRecognizer()
}
func registerGestureRecognizer(){
let directions : [UISwipeGestureRecognizer.Direction] = [.up]
for direction in directions{
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
swipe.direction = direction
sceneView.addGestureRecognizer(swipe)
}
}
@objc func handleSwipe(gestureRecognizer: UISwipeGestureRecognizer){
//print ("will it work?")
//sceneview to be accessed
//access the point of view of the sceneView, the center point
guard let sceneView = gestureRecognizer.view as? ARSCNView else{
return
}
guard let centerPoint = sceneView.pointOfView else {
return
}
//transform matrix
//the orientation
//position of camera
// orientation and position are needed to determine the camera where the ball needs to be placed
let cameraTransform = centerPoint.transform
let cameraLocation = SCNVector3(x: cameraTransform.m41, y: cameraTransform.m42, z: cameraTransform.m43)
let cameraOrientation = SCNVector3(x: -cameraTransform.m31, y: -cameraTransform.m32, z: -cameraTransform.m33)
//x1 + x2, y1+y2, z1+z2
let cameraPosition = SCNVector3Make(cameraLocation.x + cameraOrientation.x, cameraLocation.y + cameraOrientation.y, cameraLocation.z + cameraOrientation.z)
let ball = SCNSphere(radius:0.04)
// Bucketnode.scale = SCNVector3Make(0.2,0.2,0.2);
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "basketballSkin.png")
ball.materials = [material]
let ballNode = SCNNode(geometry: ball)
ballNode.position = cameraPosition
let physicsShape = SCNPhysicsShape(node: ballNode, options:nil)
let physicsBody = SCNPhysicsBody(type: .dynamic, shape: physicsShape)
ballNode.physicsBody = physicsBody
ballNode.physicsBody?.categoryBitMask = BodyType.ballNode.rawValue
ballNode.physicsBody?.collisionBitMask = BodyType.ballNode.rawValue
ballNode.physicsBody?.contactTestBitMask = BodyType.ballNode.rawValue
let forceVector:Float = 2.7
ballNode.physicsBody?.applyForce(SCNVector3Make(cameraPosition.x * forceVector, cameraPosition.y * forceVector, cameraPosition.z*forceVector), asImpulse: true)
sceneView.scene.rootNode.addChildNode(ballNode)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { // change 2 to desired number of seconds
ballNode.removeFromParentNode()
}
}
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
let contactMask = contact.nodeA.categoryBitMask | contact.nodeB.categoryBitMask
switch (contactMask) {
case BodyType.baseNode.rawValue | BodyType.ballNode.rawValue :
print("hit")
default:
return
}
}
func addBackboard(){
guard let bucketScene = SCNScene(named:"art.scnassets/BucketBlue.scn") else {
return
}
guard let bucketNode = bucketScene.rootNode.childNode(withName: "tube", recursively: false) else {
return
}
guard let baseNode = bucketScene.rootNode.childNode(withName: "cylinder", recursively: true) else {
return
} //this part makes my bucket disappear, without it, it works fine but no contact action can be recognised
baseNode.physicsBody?.categoryBitMask = BodyType.baseNode.rawValue
baseNode.physicsBody?.collisionBitMask = BodyType.baseNode.rawValue
baseNode.physicsBody?.contactTestBitMask = BodyType.baseNode.rawValue
bucketNode.scale = SCNVector3Make(0.15,0.15,0.15);
bucketNode.worldPosition = SCNVector3(x: 0, y: -1.35, z: -1.4)
let physicsShape = SCNPhysicsShape(node: bucketNode, options: [SCNPhysicsShape.Option.type: SCNPhysicsShape.ShapeType.concavePolyhedron])
let physicsBody = SCNPhysicsBody(type: .static, shape: physicsShape)
bucketNode.physicsBody = physicsBody
sceneView.scene.rootNode.addChildNode(bucketNode)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
/*
// Override to create and configure nodes for anchors added to the view's session.
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
let node = SCNNode()
return node
}
*/
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
@IBAction func AddBasket(_ sender: Any) {
addBackboard()
AddBasketBtn.isHidden = true
}
}
最佳答案
很少有事情,首先是ARKit空间是以米为单位测量的,所以在放置对象时要记住它,其次你并没有真正利用ARKit(也许稍后会用到它,好吧),但是如果这是你的计划,也许用锚来创建一个scnnode,然后把你的桶放在锚的上面是好的:
下一段代码主要来自苹果的开发者网站。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
// Place content only for anchors found by plane detection.
guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
// Create a SceneKit plane to visualize the plane anchor using its position and extent.
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
let planeNode = SCNNode(geometry: plane)
planeNode.simdPosition = float3(planeAnchor.center.x, 0, planeAnchor.center.z)
// `SCNPlane` is vertically oriented in its local coordinate space, so
// rotate the plane to match the horizontal orientation of `ARPlaneAnchor`.
planeNode.eulerAngles.x = -.pi / 2
// Make the plane visualization semitransparent to clearly show real-world placement.
planeNode.opacity = 0.25
// Add the plane visualization to the ARKit-managed node so that it tracks
// changes in the plane anchor as plane estimation continues.
node.addChildNode(planeNode)
node.addChildNode(bucketNode)
}
所以你应该先让ARKit创建锚,然后放置SCNPlane,然后你会看到你的桶正好在SCNPlane的中间(只是不要给你的桶设置任何位置)。
最后将SCNTorus定位在float3(0.0,0.20,0.0)这样的地方,这是20厘米。锚中心上方
关于swift - 当两个对象处于接触/碰撞状态时尝试打印一些东西。稍后当球触及铲斗底部时增加得分,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50945971/