Reputation: 2982
I'm new to ARKit
and I'm trying to make a relatively simple app where you create a "wall" and the user "throws" balls at it, and it bounces back.
I create the wall as a SCNPlane
where the user is pointing the camera to like so:
private func createWall(withPosition position: SCNVector3) -> SCNNode {
let wallGeometry = SCNPlane(width: 0.3, height: 0.3)
wallGeometry.firstMaterial?.isDoubleSided = true
wallGeometry.firstMaterial?.diffuse.contents = UIColor.green.withAlphaComponent(0.7)
let parentNode = SCNNode(geometry: wallGeometry)
let (position, _) = cameraPosition()
parentNode.position = position
parentNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: wallGeometry, options: nil))
parentNode.physicsBody?.isAffectedByGravity = false
self.wall = parentNode
return parentNode
}
I get the direction and position of camera with this function:
cameraPosition()
:
func cameraPosition() -> (SCNVector3, SCNVector3) {
guard let frame = sceneView.session.currentFrame else { return (SCNVector3(0, 0, -1), (SCNVector3(0, 0, 0))) }
let matrix = SCNMatrix4(frame.camera.transform)
let direction = SCNVector3(-matrix.m31, -matrix.m32, -matrix.m33)
let location = SCNVector3(matrix.m41, matrix.m42, matrix.m43)
return ((location + direction), direction)
}
// Helper function
func +(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
return SCNVector3(left.x + right.x, left.y + right.y, left.z + right.z)
}
I create instances of Ball()
and throw them like this:
let (position, direction) = cameraPosition()
// throw ball
let ball = Ball()
ball.position = position //SCNVector3(0,0,0)
sceneView.scene.rootNode.addChildNode(ball)
let impulseModifier = Float(10)
ball.physicsBody!.applyForce(SCNVector3(direction.x*impulseModifier, direction.y*impulseModifier, direction.z*impulseModifier), asImpulse: true)
The Ball class:
class Ball: SCNNode {
override init() {
super.init()
let sphere = SCNSphere(radius: 0.05)
sphere.firstMaterial?.diffuse.contents = UIColor.red
self.geometry = sphere
self.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: sphere, options: nil))
}
}
The problem is that many times, instead of the ball actually hitting the wall, it will just travel through it, as if the physics body does not function properly. I noticed that sometimes it will work better when I change the distance and angle between the camera and the wall, but the results are never consistent as far as I've tried.
I have also tried to change the wall position to: SCNVector3(0, 0, -1)
to position it exactly 1 meter deep away from the world origin, and the results were somewhat better but still not consistent.
Where could the problem lay and why?
Thanks in advance!
Upvotes: 0
Views: 724
Reputation: 5742
Most likely this is due to the ball being too small for the collision detection to work properly. Try setting continuousCollisionDetectionThreshold equal to half of the ball radius. In this case:
ball.physicsBody?.continuousCollisionDetectionThreshold = 0.025
Upvotes: 0
Reputation: 31
Set your wall physics to be kinematic so that the ball can react with it.
Static objects don't react with anything.
Kinematic objects react with other objects but other objects don't affect them.
Dynamic of course means it works in both directions.
Upvotes: 3