Animating the Sprite


The Animated 3D Sprite

Figure 19-5 shows the visible methods of AnimSprite3D.

The interface of this class is almost identical to Sprite3D (from the Tour3D application in Chapter 18). The setPosition( ), moveBy( ), and doRotateY( ) operations adjust the position and orientation of the sprite, isActive( ) and setActive( ) relate to the sprite's activity (i.e., whether it is visible on the screen or not), getCurrLoc( ) returns the sprite's position, and getTG( ) returns its top-level transformGroup.

The only new method is setPose( ), which takes a pose name as an argument and changes the displayed model accordingly. Its implementation is explained later in this section.

Figure 19-4. Scene graph for the application


Figure 19-5. The public methods of AnimSprite3D


Loading the Poses

The choice of models is hardwired into AnimSprite3D, which makes things simpler than having to deal with arbitrary input. The names of the models are predefined in the poses[] array:

     private final static String poses[] =            {"stand", "walk1", "walk2", "rev1", "rev2", "rotClock",             "rotCC", "mleft", "mright", "punch1", "punch2"};

The names in poses[] are used by loadPoses( ) to load the same-named 3D Studio Max files using PropManager. The loaded models (the different sprite poses) are attached to the scene using a Java 3D Switch node:

     private void loadPoses( )     { PropManager propMan;       imSwitch = new Switch(Switch.CHILD_MASK);       imSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);       maxPoses = poses.length;       for (int i=0; i < maxPoses; i++) {         propMan = new PropManager(poses[i] + ".3ds", true);         imSwitch.addChild( propMan.getTG( ) );   // add obj to switch       }       visIms = new BitSet( maxPoses );    // bitset used for switching       currPoseNo = STAND_NUM;  // sprite standing still       setPoseNum( currPoseNo );     }

The Switch node (imSwitch) is shown in the scene graph in Figure 19-4. It's a child of the objectTG TransformGroup, which is used for positioning and rotating the sprite. The purpose of the Switch node is to allow the sprite to strike up a different pose by choosing one from the selection hanging below the Switch.

imSwitch is created with the CHILD_MASK value, which permits pose switching to be carried out using a Java 3D BitSet object (visIms). The bits of the BitSet are mapped to the children of the Switch: bit 0 corresponds to child 0, bit 1 to child 1, and so on. BitSet offers various methods for clearing bits and setting them.

The bit manipulation is hidden inside the setPoseNum( ) method, which takes as its input the bit index that should be turned on in imSwitch:

     private void setPoseNum(int idx)     { visIms.clear( );       visIms.set( idx );   // show child with index idx       imSwitch.setChildMask( visIms );       currPoseNo = idx;     }

The model stored in the idx position below the Switch node is made visible when setChildMask( ) is called.

The runtime adjustment of the Switch requires its write capability to be turned on.

Where Did These Models Come From?

I created the models using Poser (http://www.curiouslabs.com), which specializes in 3D figure creation and animation and includes a range of predefined models, poses, and animation sequences. Poser fans should check out the collection of links in the Google directory: http://directory.google.com/Top/Computers/Software/Graphics/3D/Animation_and_Design_Tools/Poser/. I used one of Poser's existing figures, the stick child, and exported different versions of it in various standard poses to 3DS files. Poser animation sequences weren't utilized; each file only contains a single figure.

Though I used Poser, any 3D modeling tool would be fine. MilkShape 3D, for example, is a good shareware product (http://www.swissquake.ch/chumbalum-soft/ms3d/).


The models were loaded into the Loader3D application (developed in Chapter 16) to adjust their position and orientation. Poser exports 3DS models orientated with the XZ plane as their base, which means that the model is lying flat on its back when loaded into Loader3D.

Each 3DS file is about 20 KB due to the choice of a simple model.


Setting a Pose

A sprite's pose is changed by calling setPose( ), which takes a pose name as its input argument. The method determines the index position of that name in the poses[] array and calls setPoseNum( ):

     public boolean setPose(String name)     { if (isActive( )) {         int idx = getPoseIndex(name);         if ((idx < 0) || (idx > maxPoses-1))           return false;         setPoseNum( idx );         return true;       }       else         return false;     }

The code is complicated by the need to check for sprite activity. An inactive sprite is invisible, so there's no point changing its pose.

The use of a name as the setPose( ) argument means that the caller must know the pose names used in poses[]. The alternative would be to use the child index position in the Switch node, which is harder to remember.


Sprite Activity

Sprite activity can be toggled on and off by calls to setActive( ) with a Boolean argument:

     public void setActive(boolean b)     { isActive = b;       if (!isActive) {         visIms.clear( );         imSwitch.setChildMask( visIms );   // display nothing       }       else if (isActive)         setPoseNum( currPoseNo );   // make visible     }

This approach requires a global integer, currPoseNo, which records the index of the current pose. It's used to make the sprite visible after a period of inactivity.

Floor Boundary Detection

The movement and rotation methods in AnimSprite3D are unchanged from Sprite3D except in the case of the moveBy( ) method. The decision not to use obstacles means there's no Obstacle object available for checking if the sprite is about to move off the floor. This is remedied by a beyondEdge( ) method, which determines if the sprite's (x, z) coordinate is outside the limits of the floor:

     public boolean moveBy(double x, double z)     // move the sprite by an (x,z) offset     { if (isActive( )) {         Point3d nextLoc = tryMove( new Vector3d(x, 0, z));              if (beyondEdge(nextLoc.x) || beyondEdge(nextLoc.z))           return false;         else {           doMove( new Vector3d(x, 0, z) );           return true;         }       }       else    // not active         return false;}  // end of moveBy( )     private boolean beyondEdge(double pos)     { if ((pos < -FLOOR_LEN/2) || (pos > FLOOR_LEN/2))         return true;       return false;     }



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