Updating the Alien Sprite


Controlling the Touring Sprite

The TouristControls object responds to key presses by moving the robot sprite or by changing the user's viewpoint. As the sprite moves, the viewpoint is automatically adjusted so the sprite and viewpoint stay a fixed distance apart. This is a simple form of third-person camera.

What's a Third-Person Camera?

A third-person camera is a viewpoint that semiautomatically or automatically tracks the user's sprite as it moves through a game. This is difficult to automate since the best vantage point for a camera depends on the sprite's position and orientation and on the location of nearby scenery and other sprites, as well as the focal point for the current action. A common solution is to offer the player a selection of several cameras.

Tour3D is simpler: the camera stays at a certain distance from the sprite, offset along the positive z-axis. This distance is maintained as the sprite moves forward, backward, left, and right. The only permitted adjustment to the camera is a zoom capability that reduces or increases the offset. Though this approach is simple, it is quite effective. The coding can be extended to support more complex changes in the camera's position and orientation.

As an added bonus, having a camera means that I no longer need to use Java 3D's OrbitBehavior class.


Setting Up TouristControls

The TourSprite and TouristControls are created and linked inside addTourist( ) in WrapTour3D:

     private void addTourist( )     {       bob = new TourSprite("Coolrobo.3ds", obs);   // sprite       bob.setPosition(2.0, 1.0);       sceneBG.addChild( bob.getTG( ) );       ViewingPlatform vp = su.getViewingPlatform( );       TransformGroup viewerTG = vp.getViewPlatformTransform( );                       // TransformGroup for the user's viewpoint       TouristControls tcs = new TouristControls(bob, viewerTG);                    // sprite's controls       tcs.setSchedulingBounds( bounds );       sceneBG.addChild( tcs );     }

The TouristControls object (tcs) requires a reference to the TourSprite (called bob) to monitor and change its position, and a reference to the user's viewpoint transformGroup (viewerTG) to move the viewpoint in line with the TourSprite's position.

The WakeupCondition for TouristControls is an AWT key press, which is specified in the constructor:

     keyPress = new WakeupOnAWTEvent( KeyEvent.KEY_PRESSED );

The key press is then registered in initialize( ):

     wakeupOn( keyPress );

processStimulus( ) checks that the criterion is an AWT event and responds to key presses:

     public void processStimulus(Enumeration criteria)     { WakeupCriterion wakeup;       AWTEvent[] event;       while( criteria.hasMoreElements( ) ) {         wakeup = (WakeupCriterion) criteria.nextElement( );         if( wakeup instanceof WakeupOnAWTEvent ) {  // is it AWT?           event = ((WakeupOnAWTEvent)wakeup).getAWTEvent( );           for( int i = 0; i < event.length; i++ ) { // many events             if( event[i].getID( ) == KeyEvent.KEY_PRESSED )               processKeyEvent((KeyEvent)event[i]);  // do something           }         }       }       wakeupOn( keyPress );  // re-register     }

All the testing and iteration through the event[] array leads to a call to processKeyEvent( ), which reacts to the key press.

Keys Understood by TouristControls

The user sprite can move in four directions: forward, backward, left, and right; it can also rotate left or right around the y-axis. The down, up, left, and right arrow keys cover forward, backward, rotate left, and rotate right. The Alt key combined with the left and right arrows support left and right movement (a sort of sidestepping).

One subtlety here is the choice of keys to denote direction. The down arrow key is most natural for representing forward when the sprite is facing out of the world, along the +z axis but is less appealing when the sprite has been rotated by 180 degrees and is facing into the scene. For this reason, it may be better to use letter keys such as f, b, l, and r for movement; however, I'm not convinced that letters are easier to remember (e.g., does r mean reverse or right?). The arrow keys have the advantage of being placed together on the keyboard.

The viewpoint can be zoomed in and out along the z-axis; those two operations are activated by the i and o keys.

processKeyEvent( )'s definition is shown here:

     private void processKeyEvent(KeyEvent eventKey)     { int keyCode = eventKey.getKeyCode( );       if( eventKey.isAltDown( ) )         altMove(keyCode);       else         standardMove(keyCode);       viewerMove( );     }

Every key has a unique key code constant; each is listed at length in the documentation for the KeyEvent class. Checking for modifier keys, such as alt and shift, can be done by testing the KeyEvent object, e.g., see the isAltDown( ) test in processKeyEvent( ).

standardMove( ) calls the relevant methods in the TourSprite (called bob) depending on which key is pressed:

     if(keycode == forwardKey )       bob.moveForward( );     else if(keycode == backKey)       bob.moveBackward( );

forwardKey and backKey (and others) are constants defined in TouristControls:

     private final static int forwardKey = KeyEvent.VK_DOWN;     private final static int backKey = KeyEvent.VK_UP;

Viewpoint Initialization

The initial positioning of the user's viewpoint is done in TouristControls in the setViewer( ) method:

     private void setViewer( )     { bobPosn = bob.getCurrLoc( );   // start location for bob       viewerTG.getTransform( t3d );       t3d.lookAt( new Point3d(bobPosn.x, HEIGHT, bobPosn.z + ZOFFSET),                 new Point3d(bobPosn.x, HEIGHT, bobPosn.z),                 new Vector3d(0,1,0));       t3d.invert( );       viewerTG.setTransform(t3d);     }

TRansform3D.lookAt( ) specifies the viewer's position, the point being looked at, and the up direction. The coordinates are obtained from the TourSprite's original position. The viewpoint is raised HEIGHT units up the y-axis and ZOFFSET units away down the positive z-axis to give an overview of the robot.

It's important that the vector between the user's viewpoint and the sprite is at right angles to the XY plane. This means that a translation applied to the sprite will have the same effect when applied to the viewpoint. This issue is a consequence of the translation and rotation components of the viewer being applied to a single transformGroup.

Moving the Camera

The camera is moved by viewerMove( ), which is called at the end of processKeyEvent( ) after the sprite's position or orientation has been altered.

viewerMove( ) obtains the new position of the sprite and calculates the translation relative to the previous position. This translation is then applied to the viewer:

     private void viewerMove( )     { Point3d newLoc = bob.getCurrLoc( );       Vector3d trans = new Vector3d( newLoc.x - bobPosn.x,                                      0, newLoc.z - bobPosn.z);       viewerTG.getTransform( t3d );       toMove.setTranslation(trans);       t3d.mul(toMove);       viewerTG.setTransform(t3d);       bobPosn = newLoc;   // save for next time     }

Figure 18-8 shows two screenshots of Tour3D with the sprite in different locations and orientations, but the viewpoint is in the same relative position in both pictures.

Figure 18-8. Sprite movement affects the viewpoint


Zooming the Camera

Camera zooming is achieved by adjusting the z-axis distance between the viewpoint and the sprite. When the user presses i or o, shiftViewer( ) is called inside standardMove( ):

     // other key processing in standardMove( )     else if(keycode == inKey)   // letter 'i'       shiftViewer(-ZSTEP);     else if(keycode == outKey)  // letter 'o'       shiftViewer(ZSTEP);

ZSTEP is set to be 1.0. shiftViewer( ) moves the TRansformGroup by the required amount along the z-axis:

     private void shiftViewer(double zDist)     { Vector3d trans = new Vector3d(0,0,zDist);       viewerTG.getTransform( t3d );       toMove.setTranslation(trans);       t3d.mul(toMove);       viewerTG.setTransform(t3d);     }

Figure 18-9 shows the result of pressing i five times. Compare the viewpoint's position with the images in Figure 18-8 to see the effect of zooming.

Rotating the Camera

The TouristControls class doesn't support viewpoint rotation, but it's interesting to discuss the issues involved in implementing some form of rotation.

Figure 18-9. A closer view of the sprite


The first problem is to make sure that the rotations and translations applied to the sprite are echoed by the same rotations and translations of the viewpoint. If the viewpoint rotates by a different amount, then the sprite's translations will have a different effect on the viewpoint since it will be facing in a different direction. This echoing is best implemented by duplicating the Sprite3D methods for translation and rotation inside TouristControls. The coding will require some modifications since the viewpoint is facing toward the sprite, so its notions of forward, backward, left, and right are different.

Even if the rotations of the sprite and viewpoint are always aligned, problems will still occur. For instance, a 180-degree rotation of the sprite will cause a 180-degree rotation of the viewpoint, and the viewpoint will now be facing away from the sprite. This is a result of rotating the sprite and the viewpoint around their own centers, and the rotation of the viewpoint must use the sprite's position as its center of rotation.

Figure 18-10 shows the desired viewpoint rotation after the sprite has rotated 30 degrees.

In coding terms, this requires the viewpoint transformGroup to be translated to the sprite's position, rotated, and then translated back. The translation back will be the negative of the first translation since the viewpoint's coordinate system will have been changed by the rotation.

A more fundamental question still remains: does rotation give the user a better view of the sprite? Unfortunately, the answer is "maybe." The problem is that the rotation may move the viewpoint inside a piece of scenery or otherwise block the view in some way. One solution is to offer the user several alternative viewpoints, in the hope that at least one of them will be useful. You'll learn how to implement multiple viewpoints in the Maze3D application in Chapter 25.

Figure 18-10. Viewpoint rotation




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