import java.awt.event.*; import java.util.Enumeration; // SimpleBehaviorApp renders a single, rotated cube. public class SimpleBehaviorApp extends Applet { public class SimpleBehavior extends Behavior{ private TransformGroup targetTG; private Transform3D rotation = new Transform3D(); private double angle = 0.0; // create SimpleBehavior - set TG object of change SimpleBehavior(TransformGroup targetTG){ this.targetTG = targetTG; } // initialize the Behavior // set initial wakeup condition // called when behavior becomes live public void initialize(){ // set initial wakeup condition this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED)); } // called by Java 3D when appropriate stimulus occurs public void processStimulus(Enumeration criteria){ // do what is necessary in response to stimulus angle += 0.1; rotation.rotY(angle); targetTG.setTransform(rotation); this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED)); } } // end of class SimpleBehavior SimpleBehavior Class in SimpleBehaviorApp.java
As an example of using the custom behavior class recipe of Figure 4-2, this section goes through the process of writing a custom behavior class. For the example custom behavior, the class will implement a simple behavior of making something rotate in response to a keyboard key press.
To create such a behavior class, all that is needed is a reference to a TransformGroup (the object of change for this class), and an angle variable. In response to a key press, the angle variable is changed and the angle of the target TransformGroup is set to the angle. Since the behavior will act on a TransformGroup object, what is being rotated is not an issue.
To create this class nothing more than the three essential
programming ingredients listed in the recipe are needed: a constructor, the
initialization method, and the processStimulus method. The constructor will
store a reference to the TransformGroup object of change. The initialization
method sets the initial trigger to WakeOnAWTEvent, and sets the rotation angle
to zero. As mentioned above, the stimulus to a behavior
is specified as a WakeupCondition object. Section 4.3 introduces WakeupCondition
classes.
Since there is only one possible triggering wakeup condition, the processStimulus
method does not decode the triggering wakeup condition. It is possible to further
decode the key press event to determine which key, or combination of keys, was
pressed.
The processStimulus method always increments the angle variable, then uses it to adjust the TransformGroup object of change. The last job of the processStimulus method is to reset the trigger. In this example, the trigger is always reset to a key press. Behaviors can change their trigger event over time for changing behaviors (another reason for having to decode the trigger event), or not set another trigger for one time behaviors.
The import statements listed in Code Fragment 4-1 are necessary for the behavior class. The java.awt.event import is necessary for the keyboard interaction. The java.util.eumeration import is necessary for decoding the WakeupCondition; and therefore necessary for virtually any custom behavior class. The normal Java 3D API import statements are needed in addition to the listed import statements.
The last step for adding a behavior is to provide a scheduling bounds for the behavior. To improve efficiency, Java 3D uses the scheduling bounds to perform execution culling. Behavior is only active when its scheduling bounds intersects a ViewPlatform's activation volume. Only active behaviors are eligible to receive stimuli. In this way, stimuli can be ignored for some behaviors. The programmer has control over the execution culling through the selection of the scheduling bounds of the behavior.
This class only demonstrates the basic programming necessary for this simple behavior. Enhancements to this custom class are possible. For example, the angle of rotation and/or the axis of rotation could be setby class methods. The behavior class could be further customizable with a method for setting a specific key, or set of keys, that it will respond to. Another definite improvement in the class would prevent overflow of the angle variable. In the current class, the value of angle could grow without bound even though values of 0.0 to 2P are all that is necessary. Although unlikely, it is possible for this variable to overflow and cause a run time exception.