Shooting Behavior


Causing an Explosion

The explosion is best explained by considering the subgraph created inside ExplosionsClip (see Figure 23-8).

The visual component of the explosion is implemented as a series of transparent GIF images, drawn one after another onto the surface of a QuadArray inside explShape. explTG is utilized to position the explosion shape at the point where the user clicked the mouse and to rotate it around the y-axis to face the user's viewpoint. The Switch node is used to hide the explosion until needed.

The explosion sound is the PointSound node, explPS. The showExplosion( ) method positions it at the intercept point and then enables it (plays it).

The original design for the explosion had the PointSound attached to the explTG TransformGroup, which meant that would automatically move as the explShape node

Figure 23-8. Scenegraph branch for ExplosionsClip


moved. Unfortunately, a runtime exception rose as the sound was enabled, making this approach impossible. After some testing, I discovered the exception was caused by the PointSound object being attached below the Switch node, explSwitch. This attachment should be possible; the exception is a bug in Java 3D 1.3.1.

I coded around the problem by moving the PointSound node to a different branch from the Switch node (as shown in Figure 23-8). This avoids the exception but means that the sound node must be explicitly translated to stay with the explShape node as it moves.

The subgraph is created in the constructor for ExplosionsClip, and a reference to explBG is retrieved by WrapShooter3D via calling getExplBG( ).

The explosion is displayed by showExplosion( ), which is called from FireBeam, after the laser beam has reached the click point:

     public void showExplosion(double turnAngle, Point3d intercept)     // turn to face eye and move to click point     {       endVec.set(intercept.x, intercept.y, intercept.z);       rotateMove(turnAngle, endVec);            explSwitch.setWhichChild( Switch.CHILD_ALL );   // make visible       explPS.setPosition((float)intercept.x,                      (float)intercept.y, (float)intercept.z);                      // move sound to click point       explPS.setEnable(true);         // switch on explosion sound       explShape.showSeries(  );         // show the explosion       explPS.setEnable(false);        // switch off sound       explSwitch.setWhichChild( Switch.CHILD_NONE ); // invisible           // face front again, and reset position       rotateMove(-turnAngle, startVec);     }  // end of showExplosion(  ) 

FireBeam passes the user's click point (intercept) and the turning angle for the explosion (turnAngle) to showExplosion( ). The rotation is handled by rotateMove( ) (explained below), and the animation is triggered by a call to showSeries( ) in the ImagesSeries object.

The PointSound, explPS, requires certain capabilities so it can be positioned and enabled; the capabilities are set by initSound( ). After the explosion has finished, it is hidden, and rotated back to its original orientation.

Rotating the Explosion

rotateMove( ) uses the supplied turning angle to rotate the explosion around the y-axis, so can employ rotY( ) rather than an AxisAngle4d object. As usual, the object must be translated to the origin before the rotation and then translated to its new position afterward:

     private void rotateMove(double turn, Vector3d vec)     // rotate the explosion around the Y-axis, and move to vec     {       explTG.getTransform(explT3d);      // get transform info       explT3d.setTranslation(ORIGIN);    // move to origin           rotT3d.rotY(turn);        // rotate around the y-axis       explT3d.mul(rotT3d);           explT3d.setTranslation(vec);      // move to vector       explTG.setTransform(explT3d);     // update transform     } 

Displaying a Series of Images

The constructor for the ImagesSeries class takes a partial filename (e.g., images/explo) and a number (e.g., 6) and attempts to loads GIF files which use that name and numbering scheme (e.g., images/explo0.gif through images/explo5.gif). The images are stored as ImageComponent2D objects in an ims[] array.

ImagesSeries is a Shape3D subclass, containing a QuadArray placed on the XZ plane centered at (0,0). The quad is a single square, of size screenSize, with its front face oriented along the positive z-axis, as in Figure 23-9.

Figure 23-9. The ImagesSeries QuadArray


Implicit in the quad's square shape is the assumption that the GIFs will be square; otherwise, each one will be distorted as it's laid over the face of the quad. The texture coordinates are assigned counterclockwise from the bottom-left coordinate of the quad, so the texture will be the right way up and facing out along the positive z-axis toward the viewer.

The quad's face is covered with a series of transparent GIFs, so the shape's appearance must use blended transparency. This means that the transparent parts of a GIF will remain transparent as the GIF is applied to the shape as a texture:

     Appearance app = new Appearance(  );     // blended transparency so texture can be irregular     TransparencyAttributes tra = new TransparencyAttributes(  );     tra.setTransparencyMode( TransparencyAttributes.BLENDED );     app.setTransparencyAttributes( tra ); 

No Material node component is assigned to the shape, which means that lighting cannot be enabled, so the shape is unaffected by the lighting in the scene. This is the code to do this:

     // mix the texture and the material color     TextureAttributes ta = new TextureAttributes(  );     ta.setTextureMode(TextureAttributes.MODULATE);     app.setTextureAttributes(ta);         Material mat = new Material(  );    // set material and lighting     mat.setLightingEnable(true);     app.setMaterial(mat); 

The Texture2D object that holds the texture is based on the size of the first image in ims[]. The code assumes that all the subsequent GIFs are the same size:

     // Set the texture from the first loaded image     texture = new Texture2D(Texture2D.BASE_LEVEL, Texture.RGBA,                                    ims[0].getWidth(  ), ims[0].getHeight(  ));     texture.setImage(0, ims[0]);     texture.setCapability(Texture.ALLOW_IMAGE_WRITE);   // texture can change     app.setTexture(texture);          setAppearance(app); 

The capability bit allows the texture to be changed by showSeries( ), which is called from ExplosionsClip:

     public void showSeries(  )     { for (int i=0; i < ims.length; i++) {         texture.setImage(0, ims[i]);         try {           Thread.sleep(DELAY);  // wait a while         }         catch (Exception ex) {}       }     } 

showSeries( ) defines an animation sequence that's played once and then stops. Variants of this idea allow the animation to cycle or to be played from some arbitrary point in the sequence. For example, a cyclic animation might be useful for showing trees waving in the breeze.



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net