At 13:25 23/08/99 +0400, you wrote:
>Hi,
>
>Can anyone here give some example and comprehensive explanations on
>Collision Detection topic? What bounds trigger this event? If i use
>USE_BOUNDS flag, bounds of what objects should be set and by means of
>what functions? setBounds or setCollisionBounds? Should bounds of the
>object i add CollisionBehavior to be set to some value and do they mean
>anything 4 collision detection?
>
>Some example (other than the one in Java3D package - TickTockCollision)
>would be very appretiated as well.
>
Collision detection happens when two Shape3D/ primitives overlap (or at
least, their collision bounds do) Vladimir.
To set up a collision detection, you need a collision detector class (the
one from TickTock was the model I used). This should respond like any
behavior node.
Start by writing any needed setup code in the constructor and/or initialize
routine.
The collision node will be /can be triggered by collision, end of collision
or movement while in collision. Select the wakeups that you want.
Collision doesn't do a lot, just detects it. Now you need to write some
code to make something happen when there is a collision. You've got two
choices really. Write all the handling code in the collision detection
class, or pass the fact of a collision back to the parent node by a method
call. I think this is best because then the right object handles the
collision and the collision detector simply needs to know the parent, not
what the parent needs to do. There is a problem though (of course). You
can't get the parent at run-time. What I do is to pass the parent to the
collision detector in the constructor. That way, I can hold a reference to
it and call its collision() method as needed. To illustrate:
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.Primitive;
public class collider extends Behavior {
private boolean inCollision = false;
private WakeupOnCollisionEntry wEnter;
private WakeupOnCollisionExit wExit;
private WakeupOnElapsedTime wElapsed;
private WakeupCriterion[] wInTime;
private WakeupCriterion[] wOutTime;
private collidableTransform p;
private Primitive shape;
private int timeslice = 5;
/**
*
* Core collision detector and scene animation timer
*
* s is a reference to the geometry of the node which holds the collision
detector
* so that it can be accessed if needed.
* theParent is the node which holds the collision detector. a
collidableTransform object
* is a subclass of TransformGroup. The only difference is that it MUST
have a method called
* bump() which the collision detector calls when a collision occurs.
*
* The System.out.print is there purely to check on what is going on.
Remove after testing.
*
* The behavior wakes up when collision happens, continues or ends. It
also wakes up every
* timeslice milliseconds to animate behavior. This is BAD since a class
should only do one job
* but it was a quick and dirty bit of code to solve a problem.
*
* c Tony Burrows March 99, based on code from Sun Inc.
*/
public collider (Primitive s, collidableTransform theParent) {
p = theParent;
shape = s;
inCollision = false;
System.out.print("Collider Created ... ");
}
public void initialize() { // Just set the wake up conditions
wEnter = new WakeupOnCollisionEntry(shape); //wake up call for
colliding
wExit = new WakeupOnCollisionExit(shape); //wake up call for end
of colliding
wElapsed = new WakeupOnElapsedTime(timeslice); //wake up call every
timeslice milliseconds
wInTime = new WakeupCriterion[2]; //List to hold wake up
conditions
wInTime[0] = wEnter; // The conditions in
the list
wInTime[1] = wElapsed;
wOutTime = new WakeupCriterion[2]; // The other wake up list
wOutTime[0] = wExit; // and conditions
wOutTime[1] = wElapsed;
wakeupOn(new WakeupOr(wInTime)); // Make the wake up
call from the list
System.out.println("Initialized");
}
public void processStimulus( Enumeration criteria) {
/* The whole scene is in a baseboard. This has a boolean variable
started. If started is false,
no action is taken. Simpler and fewer problems than using the
enable feature of behaviors
*/
if (baseboard.started) {
if(wEnter.hasTriggered()) {
inCollision = !inCollision; //update collision state
if (inCollision) {
/* Get the path to the node which has been collided with and pass
to the collision
detector parent for possible use if needed
*/
SceneGraphPath tp = wEnter.getTriggeringPath();
wakeupOn(new WakeupOr(wOutTime)); //If in collision, wake up
when collision over
p.bump(tp); //bump(SceneGraphPath) is a required method of
collidableTransform
}
else {
wakeupOn(new WakeupOr(wInTime)); //Wake up when collision happens
}
}
if (wElapsed.hasTriggered()) { //Timed behavior, nothing to do
with collisions
p.doTimed(timeslice); // required method of
collidableTransform
if (inCollision) {wakeupOn(new WakeupOr(wOutTime));}
else {wakeupOn(new WakeupOr(wInTime));}
}
}
else {
wakeupOn(new WakeupOr(wInTime));
}
}
}
I make no claims as to the quality of the code, but it does work.
There has been a certain amount of discussion over collision detection with
Java3D, and in particular with problems when Sun Primitives are used, or
multiple objects all with collision detectors. Perhaps I'm doing something
wrong, but I haven't been able to reproduce the problems using this collider.
Now the bounds.
The detection works on the collision bounds of the geometric shapes. You
would normally set these to (just) enclose the shapes you have. Note that
you need to set the collision bounds for _every_ shape which could be
collided with, otherwise collisions can occur before objects actually
collide. Most odd behaviour seems to be because of errors here. You set
these collision bounds in a few steps.
Make sure the shape can have its collision bounds read (not strictly
necessary perhaps, but safer)
Create a Bounds object the size and shape you want
Now make these the collisionBounds of the collidable shape using
setCollisionBounds(bounds object)
eg:
Sphere ch1 = new Sphere((float)radius, Sphere.GENERATE_NORMALS |
Sphere.GENERATE_TEXTURE_COORDS, 20, app);
ch1.setCapability(Primitive.ALLOW_COLLISION_BOUNDS_READ);
ch1.setCapability(Primitive.ALLOW_COLLISION_BOUNDS_WRITE);
BoundingSphere bs = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
radius);
ch1.setCollisionBounds(bs);
I've tried USE_SHAPE and can't see any real difference (I need to
investigate this a bit more).
Make sure that you set the scheduling bounds when you create the collider
instance and add it to the transform. This is true for _all_ behavior
nodes and is the region within which the action will be noticed. The
number of times it hasn't worked for me because I forgot this step!
collider cd = new collider(ch1, this);
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
100.0);
cd.setSchedulingBounds(bounds);
Hopefully at this point, everything should work.
Mind you, don't expect too much from this. Currently the detector simply
tells you a collision has happened and will let you find out what object
has been collided with. It will _not_ give the collision point, surface
normal or other important information for proper handling of the collision.
I'm currently trying to get this working while still using the collision
detection from java3D but I've run into problems when Primitive classes are
used. If you need more powerful, faster and reliable collision detection
you have to use something like V-Clip, and that isn't in Java (yet). I've
got references to a lot of literature and code on collision detection if
you need it.
This has been a bit long and rambling Vladimir. I hope its of use, but I'm
doing a fair bit with collision detection at the moment so get back to me
if you need any further help.
Tony
===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST". For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".