Preparing the Laser BeamThe LaserBeam object is a red cylinder, hidden inside the gun cone when not in use, so there's no need for a Switch or visibility-controlling code. ShootingBehaviour rotates the cylinder (and gun cone) to point at the location picked by the user on the checkerboard. It lets FireBeam handle the shooting of the beam and subsequent explosion. The laser beam is accompanied by a PointSound, which moves along with it. This means that the sound's volume increases (or diminishes) as the beam travels towards (or away from) the user's viewpoint. The class diagram for LaserBeam is in Figure 23-5; all public methods are shown. Figure 23-5. LaserBeam's public methodsWrapShooter3D uses getBeamBG( ) to retrieve the beam's BranchGroup for addition to the scene. The scene graph branch built inside LaserBeam (by makeBeam( )) is shown in Figure 23-6. Figure 23-6. Scenegraph branch for LaserBeamThe cylinder is made unpickable, as only the floor should be pickable by the user: beam.setPickable(false); The capability bits of beamTG are set to allow it to be rotated and translated. ShootingBehaviour rotates the beam with makeRotation( ), which is identical to the method in GunTurret, except that it applies the rotation to the beam's transformGroup, beamTG. public void makeRotation(AxisAngle4d rotAxis) // rotate the laser beam { beamTG.getTransform( beamT3d ); // get current transform beamT3d.get( currTrans ); // get current translation beamT3d.setTranslation( ORIGIN ); // translate to origin rotT3d.setRotation( rotAxis ); // apply rotation beamT3d.mul(rotT3d); beamT3d.setTranslation( currTrans ); // translate back beamTG.setTransform( beamT3d ); } // end of makeRotation( ) Global transform3D and Vector3D objects are used for the calculations (beamT3d, rotT3d, and currTrans) rather than temporary objects. Shooting the BeamshootBeam( ) is called from FireBeam to deliver the beam to the position on the floor clicked on by the user. What the user sees as a mighty laser beam, is a red cylinder moving along a straight line path from the gun's cone to an intersection point on a tile, taking a few seconds to complete the journey. The intersection coordinate in the scene is called intercept in shootBeam( ) below. It's calculated using picking, which translates the user's mouse click into a coordinate on the floor. (I'll explain the implementation details a little later in this chapter.) shootBeam( ) moves the beam toward intercept, in incremental steps defined by stepVec, with a brief delay between each move of SLEEP_TIME ms. As the beam is in flight, a sound is played: public void shootBeam(Point3d intercept) { double travelDist = startPt.distance(intercept); calcStepVec(intercept, travelDist); beamPS.setEnable(true); // switch on laser-beam sound double currDist = 0.0; currVec.set(startVec); beamTG.getTransform(beamT3d); // get current beam transform while (currDist <= travelDist) { // not at destination yet beamT3d.setTranslation(currVec); // move the laser beam beamTG.setTransform(beamT3d); currVec.add(stepVec); currDist += STEP_SIZE; try { Thread.sleep(SLEEP_TIME); // wait a while } catch (Exception ex) {} } // reset beam to its original coordinates beamT3d.setTranslation(startVec); beamTG.setTransform(beamT3d); beamPS.setEnable(false); // switch off laser-beam sound } // end of shootBeam( ) shootBeam( ) first calculates the distance to be traveled (travelDist) from the starting point to the intercept, as well as a translation increment (stepVec) based on a hardwired step size constant. These values are shown graphically in Figure 23-7. Figure 23-7. Moving the laser beamThe step size affects the user's perception of how fast the laser beam is moving. The larger the step, the quicker the beam reaches intercept. setEnable( ) controls the playing of the sound, which requires the WRITE capability bit to be set in initSound( ). The beam's current position is stored in currVec and its current distance along the path to the intercept in currDist. currVec is used to update the beam's position by modifying its transformGroup, beamTG. The while loop continues this process until the required distance has been traveled. When the beam reaches the intercept point, it's reset to its original position at startVec, which hides it from the user back inside the cone. |