Other Articulated Figures


Modeling a Limb

The main job of the Limb class is to convert limb information into a Java 3D subgraph, like the one in Figure 20-14.

The start and end joints are represented by transformGroups. startLimbTG isn't created by the limb but obtained from the parent limb. It's the parent's endLimbTG, and in this way are children attached to parents. The limb creates endLimbTG, which is positioned along the y-axis, 90 percent of the way along the length of the limb's shape. Child limbs can be attached to endLimbTG, meaning that they will overlap the

Figure 20-14. The subgraph representing a limb


parent limb shape. This enhances the effect that the limbs are connected, especially when a limb is rotated.

In between the joint transformGroups are four more TRansformGroups and a LatheShape3D node representing the limb shape and its position. These are the details hidden by the thick gray lines between the TRansformGroups in Figure 20-10. Each of those lines should be expanded into the five nodes surrounded by the gray dotted box in Figure 20-14.

orientTG is used to orient the shape initially. The other TRansformGroups are located below it as its children, so they view the new orientation as pointing along the positive y-axis. The xAxisTG, yAxisTG, and zAxisTG TransformGroups are employed to rotate the limb around the x-, y-, and z-axes at runtime. The separation of these rotations into three parts makes it much easier to undo them if the limb is reset.

Though the Limb class creates the Figure 20-14 subgraph, it does not allow the xAxisTG, yAxisTG, or zAxisTGs to be affected. The MoveableLimb class offers implementations of the methods that adjust these TRansformGroups.

Limb contains various limb data, supplied by its constructor:

     private int limbNo;     private String startJoint, endJoint;     private int orientAxis;       // limb's axis of initial orientation     private double orientAngle = 0;      // angle to orientation axis     private double limbLen;     private boolean visibleLimb = false;     protected double xsIn[], ysIn[];     // coordinates of lathe shape     protected String texPath;            // shape's texture filename

The Limb class doesn't have a limb name; only moveable limbs utilize names. The length of a limb is usually obtained from the lathe shape coordinates. I assume the final value in the lathe shape's y-coordinates is the maximum y-value for the entire shape (i.e., its height). If the limb is to be invisible, then the constructor will have to a limb length, which is directly assigned to limbLen.

The visibleLimb Boolean is used to distinguish between visible and invisible limbs. The lathe shape coordinates and texture are protected since they need to be accessible by Limb subclasses that override the lathe shape creation method, makeShape( ).

Growing a Limb

growLimb( ) starts the process of subgraph creation for the limb:

     public void growLimb(HashMap joints)     {       TransformGroup startLimbTG =             (TransformGroup) joints.get(startJoint);       if (startLimbTG == null)         System.out.println("No transform group for " + startJoint);       else {         setOrientation(startLimbTG);         makeLimb(joints);       }     }

The start joint name is used to find the startLimbTG TransformGroup in the joints HashMap. This should have been created by the parent of this limb.

setOrientation( ) creates the four rotational TRansformGroups (orientTG, xAxisTg, yAxisTG, and zAxisTG) below startLimbTG:

     private void setOrientation(TransformGroup tg)     {       TransformGroup orientTG = new TransformGroup( );       if (orientAngle != 0) {         Transform3D trans = new Transform3D( );         if (orientAxis == X_AXIS)           trans.rotX( Math.toRadians(orientAngle));         else if (orientAxis == Y_AXIS)            trans.rotY( Math.toRadians(orientAngle));         else    // must be z-axis           trans.rotZ( Math.toRadians(orientAngle));         orientTG.setTransform(trans);       }       xAxisTG = new TransformGroup( );       xAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_READ);       xAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE);       yAxisTG = new TransformGroup( );       yAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_READ);       yAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE);       zAxisTG = new TransformGroup( );       zAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_READ);       zAxisTG.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE);       // scene graph's sequence of TG's       tg.addChild(orientTG);       orientTG.addChild(xAxisTG);       xAxisTG.addChild(yAxisTG);       yAxisTG.addChild(zAxisTG);     } // end of setOrientation( )

The capability bits are set to allow the axis transformGroups to change during execution, but orientTG remains fixed after being positioned at build time.

makeLimb( ) creates the endLimbTG TransformGroup and may create a lathe shape if the limb is set to be visible:

     private void makeLimb(HashMap joints)     {       if (visibleLimb)         makeShape( );  // create the lathe shape       TransformGroup endLimbTG = new TransformGroup( );       Transform3D trans = new Transform3D( );       trans.setTranslation(            new Vector3d(0.0, limbLen*(1.0-OVERLAP), 0.0) );       /* The end position is just short of the actual length of the          limb so that any child limbs will be placed so they overlap          with this one. */       endLimbTG.setTransform(trans);       zAxisTG.addChild(endLimbTG);       joints.put(endJoint, endLimbTG);    // store (jointName, TG) pair     }

The endLimbTG TransformGroup is stored in the joints HashMap at the end of the method, so it is available for use by this limb's children.

makeShape( ) creates a LatheShape3D object and attaches it to the zAxisTG node:

              protected void makeShape( )     {       LatheShape3D ls;       if (texPath != null) {         TextureLoader texLd =                 new TextureLoader("textures/"+texPath, null);         Texture tex = texLd.getTexture( );         ls = new LatheShape3D(xsIn, ysIn, tex);       }       else         ls = new LatheShape3D(xsIn, ysIn, null);       zAxisTG.addChild(ls);  // add the shape to the limb's graph     }  // end of makeShape( )

makeShape( ) is a protected method since it may be overridden by Limb's subclasses. For example, EllipticLimb replaces the call to LatheShape3D by EllipseShape3D. This causes the limb to have an elliptical cross-section.

Updating and Resetting

Limb( ) contains empty updateLimb( ) and reset( ) methods:

     public void updateLimb(int axis, double angleStep) {}     public void reset( ) {}

updateLimb( ) and reset( ) affect the position of the limb, so they aren't used in Limb. They are overridden by the MoveableLimb subclass.



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