Contrary to popular belief, you can trick VRML to appear to have this object collision functionality. The concept is simple: the targets secretly fire back at you when you fire at them. Since you need to properly position or aim yourself at the targets, you fundamentally have the power to re-route that act of positioning so that a secret object does collide with you as your projectile collides with the target. This rule is applicable under wide range of circumstances.
In the 3D Invaders game engine that follows, we have a grey cone, the users firebase. It uses a TouchSensor to follow the movement of the mouse and from it a yellow missile is fired on the touchTime. The target PROTO consists of a red box and a ProximitySensor is positioned higher and forward. Esstentially the sensor is positioned directly above the viewers position. So when the viewer fires up at the red box target, the sensor is fired down at the viewer. Both the red box and the sensor are animated with the same positionInterloper and they move unified manner. The key is that we route the same TouchSensor data that moves the grey cone to the PromixitySensor via a separate Transform node. This node has a rotational value of 0 1 0 3.14. This value inverts it and makes the incoming TouchSensor data move the PromixitySensor in reverse. In the beginning, the unmoving sensor was positioned above the viewer, this reverse action compensates for that change of position. When the grey cone is positioned under the red box, the PromixitySensor is positioned directly above the viewer. Firing activates both the yellow missile upwards animation and the PromixitySensor downwards animation.
About the Code
The game code that follows is a single complete .wrl file. It has all the elements mentioned above. The code has been formatted to minimize its size, unneed spaces and Tabs have been removed. Printed, it runs about three pages. The reader may note seemingly the extra levels of Tranform nodes. These appear because the multiple animative forces are applied at different levels.
An example of a slightly upgrading the game with sound, multiple targets and a game board is linked to at the end of this article. A third example with "proxy shapes" which show the position of the Avatar and ProximitySensor(s) is also linked at the end.
The Proto
Every VRML world begins with the following Header
#VRML V2.0 utf8
The PROTO's first eventIn, set_fireTime, represents the act of firing the missile. (A TouchSensor is the trigger.) The proxyTranslation values are created by moving the firebase via the TouchSensor. This sensor appears later, in the Body Code.
PROTO TARGET_PROTO [
eventIn SFTime set_fireTime
eventIn SFVec3f set_proxyTranslation
]
{
The primary animation or behavior is routed to TARGET_ANIMATION01
DEF TARGET_ANIMATION01 Transform {
translation 0 3.5 0
children
The object you shoot at is defined below as TARGET. Here it is a simple red box, but any conceiveable shape or form could be inlined into the file at this point. Note that the size of the box is one meter cubed, 1 1 1. The ProximitySensor (listed next) is also one meter cubed. A change in the objects size means that the ProximitySensor size should change accordingly. Multiple sensors could be used to produce more complicated events. Also the animation triggered by a hit is routed here.
DEF TARGET Transform {
translation 0 3.5 0
children
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 } }
geometry Box { size 1 1 1 } }
}}
End of TARGET_ANIMATION01
This is the parent level of the ProximitySensor, TARGET_HITTER. The same animation that moves TARGET_ANIMATION01 also moves TARGET_HIT_ME_MOVER. In addition, the animation triggered by a hit is routed here.
DEF TARGET_HIT_ME_MOVER Transform {
translation 0 0 0
children [
The TARGET_INITIAL_POSITIONER uses the proxyTranslation values brought by the eventIn of the PROTO. The parent Transform has the rotation value of 0 1 0 3.14, and inverts the child TARGET_INITIAL_POSITIONER so that the motion is applied in reverse
Transform {
rotation 0 1 0 3.14
translation 0 4 12
children [
DEF TARGET_INITIAL_POSITIONER Transform {
set_translation IS set_proxyTranslation
children [
When the firing mechanism is activated the animation which secretly moves the sensor down torward the viewer is routed to TARGET_HIT_ME
DEF TARGET_HIT_ME Transform {
translation 0 0 0
children [
DEF TARGET_HITTER ProximitySensor
{ size 1 1 1 },
]}
]}
]}
]}
End of TARGET_HIT_ME_MOVER
This first set of Clock and PositionInterpolater moves the ProximitySensor when the fire mechanism is activated. The fireTime eventIn is used.
DEF Clock2 TimeSensor {
set_startTime IS set_fireTime
cycleInterval .5
loop FALSE
},
DEF TARGET_HIT_ME_BLAST_SHAPE PositionInterpolator {
key [ 0.0, 1.0 ]
keyValue [ 0 8 0, 0 -1 0]
}
Primary animation clock and path
DEF TARGETSPEED TimeSensor { cycleInterval 4 loop TRUE }
DEF TARGETPATH PositionInterpolator {
key [ 0, .5, 1, ]
keyValue [ 3 0 0, -3 0 0, 3 0 0, ]
}
Animation clock and path activated by TARGET being hit
DEF TARGET_DIE_CLOCK TimeSensor { cycleInterval 5 loop FALSE }
DEF TARGET_DIE_PATH PositionInterpolator {
key [ 0.00, 0.04, 0.11, .96, .9999, 1 ]
keyValue [ 0 3.5 0, 0 7 0, 0 -20 0, 0 0 500, 0 -2.5 -10 0 3.5 0 ]
}
]}
Routes for all the PROTOs animations and behaviors
ROUTE Clock2.fraction_changed TO TARGET_HIT_ME_BLAST_SHAPE.set_fraction
ROUTE TARGET_HIT_ME_BLAST_SHAPE.value_changed TO TARGET_HIT_ME.set_translation
ROUTE TARGETSPEED.fraction_changed TO TARGETPATH.set_fraction
ROUTE TARGETPATH.value_changed TO TARGET_ANIMATION01.set_translation
ROUTE TARGETPATH.value_changed TO TARGET_HIT_ME_MOVER.set_translation
ROUTE TARGET_HITTER.enterTime TO TARGET_DIE_CLOCK.set_startTime
ROUTE TARGET_DIE_CLOCK.fraction_changed TO TARGET_DIE_PATH.set_fraction
ROUTE TARGET_DIE_PATH.value_changed TO TARGET_HIT_ME_MOVER.set_translation
ROUTE TARGET_DIE_PATH.value_changed TO TARGET.set_translation
}
This ends the PROTO target code.
The Body
We start this section with NavigationInfo set to type NONE. The ProximitySensor is positioned relative to the Viewpoint below and if the user moves, the ProximitySensor will miss.
NavigationInfo { type NONE }
DirectionalLight { direction 1.0 -1.5 1}
Viewpoint {
position 0 8 12 orientation 1 0 0 -.45 description "overview"
}
Use the PROTO. For multiple targets repeat the code using MY_TARGET02, MY_TARGET03 etc. Remember to add additional ROUTEs as well.
DEF MY_TARGET01 TARGET_PROTO { }
WEAPON_SHAPE is the form you weapon takes. At present, a grey cone is used. A child of this Transform is LASERBLAST_SHAPE. This is the missile that is fired upwards an appears to collide with the TARGET. Because it is a child, it is moved as the WEAPON_SHAPE is moved.
DEF WEAPON_SHAPE Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor .6 .6 .6 }}
geometry Cone { bottomRadius 1 height .9 }}
DEF LASERBLAST_SHAPE Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 1 0 }}
geometry Cone { bottomRadius .10 height .6 }}
]}
]}
End of WEAPON_SHAPE
The code that follows is for the TOUCH TouchSensor. This is the sensor that determines; the movement of the WEAPON_SHAPE, the movement of the ProximitySensor(s) in the PROTO, and is the firing mechanism for the LASERBLAST_SHAPE as well as the ProximitySensor(s) in the PROTO.
The sensor is attached to transparent box that is 10 .1 10 in size. Change the transparency value to .5 to see the range of motion it allows. If you have a gameboard I suggest you inline it here and be careful to position it beneath the TouchSensor box.
Transform {
translation 0 .5 2
children [
Shape {
appearance Appearance {
material Material { transparency 1 }}
geometry Box { size 10 .1 10 }}
DEF TOUCH TouchSensor { },
]}
End of WEAPON_SHAPE
Animation clock and path for LASERBLAST_SHAPE
DEF Clock2 TimeSensor {
cycleInterval .5
loop FALSE
},
DEF LASERBLAST PositionInterpolator {
key [ 0, .9999, 1 ]
keyValue [ 0 -.5 0, 0 8 0, 0 16 0 ]
}
The information from the TOUCH TouchSensor is ROUTED to; WEAPON_SHAPE, LASERBLAST_SHAPE and the MY_TARGET01 PROTO. Further PROTOs will require additional ROUTES
ROUTE TOUCH.touchTime TO Clock2.set_startTime
ROUTE TOUCH.touchTime TO MY_TARGET01.set_fireTime
ROUTE TOUCH.hitPoint_changed TO MY_TARGET01.set_proxyTranslation
ROUTE Clock2.fraction_changed TO LASERBLAST.set_fraction
ROUTE LASERBLAST.value_changed TO LASERBLAST_SHAPE.set_translation
ROUTE TOUCH.hitPoint_changed TO WEAPON_SHAPE.set_translation
End Game
The code presented is only a beginning. More elements and functionality can be added without much difficulty. So enjoy, the code is free.
To play some examples of the game above try:
The Basic Engine ( the code the same as what presented here )
The Advanced Version ( watch for updates )
The Example Version ( proxy shapes added to show the action)