我的两样东西是:一个球和一个桶。水桶由两个子节点组成,每当球进入水桶并接触水桶的“圆柱体”时,我就要做些什么。但是,当我将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/

10-10 22:52