I'm trying to play a sound and then destroy two objects of two different types when they collide using Sceneform. I see that Sceneform has a collision api (https://developers.google.com/ar/reference/java/com/google/ar/sceneform/collision/package-summary), but I can't figure out how to act on a collision. I've tried extending a collision shape, overriding the shapeIntersection methods, and setting the Collision Shape property for each node, but that doesn't seem to do anything. There doesn't seem to be any sample code, but the documentation mentions collision listeners. So far, I've just been doing checks the brute force way, but I was hoping there was a more efficient way.
EDIT: I've been trying to do something like this:
public class PassiveNode extends Node{
public PassiveNode() {
PassiveCollider passiveCollider = new PassiveCollider(this);
passiveCollider.setSize(new Vector3(1, 1, 1));
this.setCollisionShape(passiveCollider);
}
public class PassiveCollider extends Box {
public Node node; // Remeber Node this is attached to
public PassiveCollider(Node node) {
this.node = node;
}
}
}
public class ActiveNode extends Node {
private Node node;
private Node target;
private static final float metersPerSecond = 1F;
public ActiveNode(Node target) {
node = this;
this.target = target;
BallCollision ball = new BallCollision();
ball.setSize(new Vector3(1, 1, 1));
this.setCollisionShape(ball);
}
@Override
public void onUpdate(FrameTime frameTime) {
super.onUpdate(frameTime);
Vector3 currPos = this.getWorldPosition();
Vector3 targetPos = target.getWorldPosition();
Vector3 direction = Vector3.subtract(targetPos, currPos).normalized();
this.setWorldPosition(Vector3.add(currPos, direction.scaled(metersPerSecond * frameTime.getDeltaSeconds())));
}
private class BallCollision extends Box {
@Override
protected boolean boxIntersection(Box box) {
if (box instanceof PassiveNode.PassiveCollider) {
//Play Sound
node.setEnabled(false);
((PassiveNode.PassiveCollider) box).node.setEnabled(false);
return true;
}
return false;
}
}
}
Where a PassiveNode lies on a plane and the ActiveNode is "thrown" from the camera to a point on a plane.
The intersection methods you are trying to override do the math to calculate if two collision shapes are intersecting, I recommend against overriding them.
Currently, there is no listener or method you can override to detect when nodes overlap. However, there are functions you can call to test for overlapping nodes.
You can use Scene.overlapTest or Scene.overlapTestAll, which uses the CollisionShape from the Node.
By default, it will automatically use a collision shape based on the dimensions of the Renderable attached to the Node. You can use Node.setCollisionShape to override the collision shape for the node, or to set collisions on a Node that doesn't have a Renderable.
You can achieve the effect you are looking for by doing something like this:
private void onUpdate(FrameTime frameTime) {
ArrayList<Node> overlappedNodes = arSceneView.getScene().overlapTestAll(ballNode);
for (Node node : overlappedNodes) {
if (node instanceof PassiveNode) {
// May want to use a flag to check that the node wasn't overlapping the previous frame.
// Play sound if overlapping started.
}
}
}