Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Essential Java 3D Fast
- Ian Palmer
- Publisher: Springer-Verlag
- ISBN: 1-85233-394-4
- */
- import java.awt.AWTEvent;
- import java.awt.BorderLayout;
- import java.awt.Button;
- import java.awt.Frame;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.KeyEvent;
- import java.util.Enumeration;
- import javax.media.j3d.Alpha;
- import javax.media.j3d.AmbientLight;
- import javax.media.j3d.Appearance;
- import javax.media.j3d.Behavior;
- import javax.media.j3d.BoundingSphere;
- import javax.media.j3d.Bounds;
- import javax.media.j3d.BranchGroup;
- import javax.media.j3d.Canvas3D;
- import javax.media.j3d.DirectionalLight;
- import javax.media.j3d.Locale;
- import javax.media.j3d.Material;
- import javax.media.j3d.Node;
- import javax.media.j3d.PhysicalBody;
- import javax.media.j3d.PhysicalEnvironment;
- import javax.media.j3d.PositionInterpolator;
- import javax.media.j3d.Switch;
- import javax.media.j3d.Transform3D;
- import javax.media.j3d.TransformGroup;
- import javax.media.j3d.View;
- import javax.media.j3d.ViewPlatform;
- import javax.media.j3d.VirtualUniverse;
- import javax.media.j3d.WakeupCriterion;
- import javax.media.j3d.WakeupOnAWTEvent;
- import javax.media.j3d.WakeupOnCollisionEntry;
- import javax.media.j3d.WakeupOnElapsedTime;
- import javax.media.j3d.WakeupOr;
- import javax.vecmath.Color3f;
- import javax.vecmath.Matrix3d;
- import javax.vecmath.Point3d;
- import javax.vecmath.Vector3d;
- import javax.vecmath.Vector3f;
- import com.sun.j3d.loaders.Scene;
- import com.sun.j3d.loaders.objectfile.ObjectFile;
- import com.sun.j3d.utils.geometry.Box;
- import com.sun.j3d.utils.geometry.Cylinder;
- import com.sun.j3d.utils.geometry.Sphere;
- /**
- * This application demonstrates a number of things in the implementation of a
- * simple shooting game. The object of the the game is to shoot a duck that
- * repeatedly moves across the screen from left to right. There are two duck
- * models, one for the 'live' duck and one for the 'dead' one. These are loaded
- * from 'duck.obj' and 'deadduck.obj' files. The 'gun' is built from primitives.
- * The duck and the ball that is used to shoot the duck use interpolators for
- * their animation. The gun uses key board input to aim and fire it, and
- * collision detection is used to 'kill' the duck.
- *
- * @author I.J.Palmer
- * @version 1.0
- */
- public class SimpleGame extends Frame implements ActionListener {
- protected Canvas3D myCanvas3D = new Canvas3D(null);
- protected Button exitButton = new Button("Exit");
- protected BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0,
- 0.0), 100.0);
- /** Switch that is used to swap the duck models */
- Switch duckSwitch;
- /** Alpha used to drive the duck animation */
- Alpha duckAlpha;
- /** Used to drive the ball animation */
- Alpha ballAlpha;
- /** Used to move the ball */
- PositionInterpolator moveBall;
- /** Used to rotate the gun */
- TransformGroup gunXfmGrp = new TransformGroup();
- /**
- * This builds the view branch of the scene graph.
- *
- * @return BranchGroup with viewing objects attached.
- */
- protected BranchGroup buildViewBranch(Canvas3D c) {
- BranchGroup viewBranch = new BranchGroup();
- Transform3D viewXfm = new Transform3D();
- Matrix3d viewTilt = new Matrix3d();
- viewTilt.rotX(Math.PI / -6);
- viewXfm.set(viewTilt, new Vector3d(0.0, 10.0, 10.0), 1.0);
- TransformGroup viewXfmGroup = new TransformGroup(viewXfm);
- ViewPlatform myViewPlatform = new ViewPlatform();
- PhysicalBody myBody = new PhysicalBody();
- PhysicalEnvironment myEnvironment = new PhysicalEnvironment();
- viewXfmGroup.addChild(myViewPlatform);
- viewBranch.addChild(viewXfmGroup);
- View myView = new View();
- myView.addCanvas3D(c);
- myView.attachViewPlatform(myViewPlatform);
- myView.setPhysicalBody(myBody);
- myView.setPhysicalEnvironment(myEnvironment);
- return viewBranch;
- }
- /**
- * This adds some lights to the content branch of the scene graph.
- *
- * @param b
- * The BranchGroup to add the lights to.
- */
- protected void addLights(BranchGroup b) {
- Color3f ambLightColour = new Color3f(0.5f, 0.5f, 0.5f);
- AmbientLight ambLight = new AmbientLight(ambLightColour);
- ambLight.setInfluencingBounds(bounds);
- Color3f dirLightColour = new Color3f(1.0f, 1.0f, 1.0f);
- Vector3f dirLightDir = new Vector3f(-1.0f, -1.0f, -1.0f);
- DirectionalLight dirLight = new DirectionalLight(dirLightColour,
- dirLightDir);
- dirLight.setInfluencingBounds(bounds);
- b.addChild(ambLight);
- b.addChild(dirLight);
- }
- /**
- * This builds the gun geometry. It uses box and cylinder primitives and
- * sets up a transform group so that we can rotate the gun.
- */
- protected BranchGroup buildGun() {
- BranchGroup theGun = new BranchGroup();
- Appearance gunApp = new Appearance();
- Color3f ambientColour = new Color3f(0.5f, 0.5f, 0.5f);
- Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f);
- Color3f specularColour = new Color3f(1.0f, 1.0f, 1.0f);
- Color3f diffuseColour = new Color3f(0.5f, 0.5f, 0.5f);
- float shininess = 20.0f;
- gunApp.setMaterial(new Material(ambientColour, emissiveColour,
- diffuseColour, specularColour, shininess));
- TransformGroup init = new TransformGroup();
- TransformGroup barrel = new TransformGroup();
- Transform3D gunXfm = new Transform3D();
- Transform3D barrelXfm = new Transform3D();
- barrelXfm.set(new Vector3d(0.0, -2.0, 0.0));
- barrel.setTransform(barrelXfm);
- Matrix3d gunXfmMat = new Matrix3d();
- gunXfmMat.rotX(Math.PI / 2);
- gunXfm.set(gunXfmMat, new Vector3d(0.0, 0.0, 0.0), 1.0);
- init.setTransform(gunXfm);
- gunXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- gunXfmGrp.addChild(new Box(1.0f, 1.0f, 0.5f, gunApp));
- barrel.addChild(new Cylinder(0.3f, 4.0f, gunApp));
- gunXfmGrp.addChild(barrel);
- theGun.addChild(init);
- init.addChild(gunXfmGrp);
- return theGun;
- }
- /**
- * Creates the duck. This loads the two duck geometries from the files
- * 'duck.obj' and 'deadduck.obj' and loads these into a switch. The access
- * rights to the switch are then set so we can write to this switch to swap
- * between the two duck models. It also creates a transform group and an
- * interpolator to move the duck.
- *
- * @return BranchGroup with content attached.
- */
- protected BranchGroup buildDuck() {
- BranchGroup theDuck = new BranchGroup();
- duckSwitch = new Switch(0);
- duckSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
- ObjectFile f1 = new ObjectFile();
- ObjectFile f2 = new ObjectFile();
- Scene s1 = null;
- Scene s2 = null;
- try {
- s1 = f1.load("duck.obj");
- s2 = f2.load("deadduck.obj");
- } catch (Exception e) {
- System.exit(1);
- }
- TransformGroup duckRotXfmGrp = new TransformGroup();
- Transform3D duckRotXfm = new Transform3D();
- Matrix3d duckRotMat = new Matrix3d();
- duckRotMat.rotY(Math.PI / 2);
- duckRotXfm.set(duckRotMat, new Vector3d(0.0, 0.0, -30.0), 1.0);
- duckRotXfmGrp.setTransform(duckRotXfm);
- duckRotXfmGrp.addChild(duckSwitch);
- duckSwitch.addChild(s1.getSceneGroup());
- duckSwitch.addChild(s2.getSceneGroup());
- TransformGroup duckMovXfmGrp = new TransformGroup();
- duckMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- duckMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- duckMovXfmGrp.addChild(duckRotXfmGrp);
- duckAlpha = new Alpha(-1, 0, 0, 3000, 0, 0);
- Transform3D axis = new Transform3D();
- PositionInterpolator moveDuck = new PositionInterpolator(duckAlpha,
- duckMovXfmGrp, axis, -30.0f, 30.0f);
- moveDuck.setSchedulingBounds(bounds);
- theDuck.addChild(moveDuck);
- theDuck.addChild(duckMovXfmGrp);
- return theDuck;
- }
- /**
- * This builds the ball that acts as the bullet for our gun. The ball is
- * created from a sphere primitive, and a transform group and interpolator
- * are added so that we can 'fire' the bullet.
- *
- * @return BranchGroup that is the root of the ball branch.
- */
- protected BranchGroup buildBall() {
- BranchGroup theBall = new BranchGroup();
- Appearance ballApp = new Appearance();
- Color3f ambientColour = new Color3f(1.0f, 0.0f, 0.0f);
- Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f);
- Color3f specularColour = new Color3f(1.0f, 1.0f, 1.0f);
- Color3f diffuseColour = new Color3f(1.0f, 0.0f, 0.0f);
- float shininess = 20.0f;
- ballApp.setMaterial(new Material(ambientColour, emissiveColour,
- diffuseColour, specularColour, shininess));
- Sphere ball = new Sphere(0.2f, ballApp);
- TransformGroup ballMovXfmGrp = new TransformGroup();
- ballMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- ballMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- ballMovXfmGrp.addChild(ball);
- theBall.addChild(ballMovXfmGrp);
- ballAlpha = new Alpha(1, 0, 0, 500, 0, 0);
- Transform3D axis = new Transform3D();
- axis.rotY(Math.PI / 2);
- moveBall = new PositionInterpolator(ballAlpha, ballMovXfmGrp, axis,
- 0.0f, 50.0f);
- moveBall.setSchedulingBounds(bounds);
- theBall.addChild(moveBall);
- return theBall;
- }
- /**
- * This puts all the content togther. It used the three 'build' functions to
- * create the duck, the gun and the ball. It also creates the two behaviours
- * from the DuckBehaviour and GunBehaviour classes. It then puts all this
- * together.
- *
- * @return BranchGroup that is the root of the content.
- */
- protected BranchGroup buildContentBranch() {
- BranchGroup contentBranch = new BranchGroup();
- Node theDuck = buildDuck();
- contentBranch.addChild(theDuck);
- Node theBall = buildBall();
- contentBranch.addChild(theBall);
- DuckBehaviour hitTheDuck = new DuckBehaviour(theDuck, duckSwitch,
- duckAlpha, bounds);
- GunBehaviour shootTheGun = new GunBehaviour(ballAlpha, moveBall,
- gunXfmGrp, bounds);
- contentBranch.addChild(hitTheDuck);
- contentBranch.addChild(shootTheGun);
- contentBranch.addChild(buildGun());
- addLights(contentBranch);
- return contentBranch;
- }
- /** Exit the application */
- public void actionPerformed(ActionEvent e) {
- dispose();
- System.exit(0);
- }
- public SimpleGame() {
- VirtualUniverse myUniverse = new VirtualUniverse();
- Locale myLocale = new Locale(myUniverse);
- myLocale.addBranchGraph(buildViewBranch(myCanvas3D));
- myLocale.addBranchGraph(buildContentBranch());
- setTitle("Duck Shoot!");
- setSize(400, 400);
- setLayout(new BorderLayout());
- add("Center", myCanvas3D);
- exitButton.addActionListener(this);
- add("South", exitButton);
- setVisible(true);
- }
- public static void main(String[] args) {
- SimpleGame sg = new SimpleGame();
- }
- }
- /**
- * This is used in the SimpleGame application. It defines the behaviour for the
- * duck, which is the target in the shooting game. If something collides with
- * the duck, it swaps a switch value to 'kill' the duck The duck is revived when
- * it's alpha value passes through zero.
- *
- * @author I.J.Palmer
- * @version 1.0
- */
- class DuckBehaviour extends Behavior {
- /** The shape that is being watched for collisions. */
- protected Node collidingShape;
- /** The separate criteria that trigger this behaviour */
- protected WakeupCriterion[] theCriteria;
- /** The result of the 'OR' of the separate criteria */
- protected WakeupOr oredCriteria;
- /** The switch that is used to swap the duck shapes */
- protected Switch theSwitch;
- /** The alpha generator that drives the animation */
- protected Alpha theTargetAlpha;
- /** Defines whether the duck is dead or alive */
- protected boolean dead = false;
- /**
- * This sets up the data for the behaviour.
- *
- * @param theShape
- * Node that is to be watched for collisions.
- * @param sw
- * Switch that is used to swap shapes.
- * @param a1
- * Alpha that drives the duck's animation.
- * @param theBounds
- * Bounds that define the active region for this behaviour.
- */
- public DuckBehaviour(Node theShape, Switch sw, Alpha a1, Bounds theBounds) {
- collidingShape = theShape;
- theSwitch = sw;
- theTargetAlpha = a1;
- setSchedulingBounds(theBounds);
- }
- /**
- * This sets up the criteria for triggering the behaviour. It creates an
- * collision crtiterion and a time elapsed criterion, OR's these together
- * and then sets the OR'ed criterion as the wake up condition.
- */
- public void initialize() {
- theCriteria = new WakeupCriterion[2];
- theCriteria[0] = new WakeupOnCollisionEntry(collidingShape);
- theCriteria[1] = new WakeupOnElapsedTime(1);
- oredCriteria = new WakeupOr(theCriteria);
- wakeupOn(oredCriteria);
- }
- /**
- * This is where the work is done. If there is a collision, then if the duck
- * is alive we switch to the dead duck. If the duck was already dead then we
- * take no action. The other case we need to check for is when the alpha
- * value is zero, when we need to set the duck back to the live one for its
- * next traversal of the screen. Finally, the wake up condition is set to be
- * the OR'ed criterion again.
- */
- public void processStimulus(Enumeration criteria) {
- while (criteria.hasMoreElements()) {
- WakeupCriterion theCriterion = (WakeupCriterion) criteria
- .nextElement();
- if (theCriterion instanceof WakeupOnCollisionEntry) {
- //There'sa collision so if the duck is alive swap
- //it to the dead one
- if (dead == false) {
- theSwitch.setWhichChild(1);
- dead = true;
- }
- } else if (theCriterion instanceof WakeupOnElapsedTime) {
- //If there isn't a collision, then check the alpha
- //value and if it's zero, revive the duck
- if (theTargetAlpha.value() < 0.1) {
- theSwitch.setWhichChild(0);
- dead = false;
- }
- }
- }
- wakeupOn(oredCriteria);
- }
- }
- /**
- * This is used in the SimpleGame application. It defines a behaviour that
- * allows a 'gun' to be rotated when left and right cursor keys are pressed and
- * then a ball is 'fired' when the space bar is pressed. The 'firing' is
- * achieved by setting the start time of an interpolator to the current time.
- *
- * @author I.J.Palmer
- * @version 1.0
- */
- class GunBehaviour extends Behavior {
- /** The separate criteria that trigger this behaviour */
- protected WakeupCriterion theCriterion;
- /** The alpha that is used to 'fire' the ball */
- protected Alpha theGunAlpha;
- /** Used to animate the ball */
- protected PositionInterpolator theInterpolator;
- /** Used to calculate the current direction of the gun */
- protected int aim = 0;
- /** This is used to rotate the gun */
- protected TransformGroup aimXfmGrp;
- /** Used to aim the ball */
- protected Matrix3d aimShotMat = new Matrix3d();
- /** Used to aim the gun */
- protected Matrix3d aimGunMat = new Matrix3d();
- /** Used to define the ball's direction */
- protected Transform3D aimShotXfm = new Transform3D();
- /** Used to define the gun's direction */
- protected Transform3D aimGunXfm = new Transform3D();
- /**
- * Set up the data for the behaviour.
- *
- * @param a1
- * Alpha that drives the ball's animation.
- * @param pi
- * PositionInterpolator used for the ball.
- * @param gunRotGrp
- * TransformGroup that is used to rotate the gun.
- * @param theBounds
- * Bounds that define the active region for this behaviour.
- */
- public GunBehaviour(Alpha a1, PositionInterpolator pi,
- TransformGroup gunRotGrp, Bounds theBounds) {
- theGunAlpha = a1;
- theInterpolator = pi;
- setSchedulingBounds(theBounds);
- aimXfmGrp = gunRotGrp;
- }
- /**
- * This sets up the criteria for triggering the behaviour. We simple want to
- * wait for a key to be pressed.
- */
- public void initialize() {
- theCriterion = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
- wakeupOn(theCriterion);
- }
- /**
- * This is where the work is done. This identifies which key has been
- * pressed and acts accordingly: left key cursor rotate left, right cursor
- * key rotate right, spacebar fire.
- *
- * @criteria Enumeration that represents the trigger conditions.
- */
- public void processStimulus(Enumeration criteria) {
- while (criteria.hasMoreElements()) {
- WakeupCriterion theCriterion = (WakeupCriterion) criteria
- .nextElement();
- if (theCriterion instanceof WakeupOnAWTEvent) {
- AWTEvent[] triggers = ((WakeupOnAWTEvent) theCriterion)
- .getAWTEvent();
- //Check if it's a keyboard event
- if (triggers[0] instanceof KeyEvent) {
- int keyPressed = ((KeyEvent) triggers[0]).getKeyCode();
- if (keyPressed == KeyEvent.VK_LEFT) {
- //It's a left key so move the turret
- //and the aim of the gun left unless
- //we're at our maximum angle
- if (aim < 8)
- aim += 1;
- System.out.println("Left " + aim);
- aimShotMat.rotY(((aim / 32.0) + 0.5) * Math.PI);
- aimGunMat.rotZ(((aim / -32.0)) * Math.PI);
- aimShotXfm.setRotation(aimShotMat);
- aimGunXfm.setRotation(aimGunMat);
- aimXfmGrp.setTransform(aimGunXfm);
- theInterpolator.setAxisOfTranslation(aimShotXfm);
- } else if (keyPressed == KeyEvent.VK_RIGHT) {
- //It's the right key so do the same but rotate right
- if (aim > -8)
- aim -= 1;
- System.out.println("Right " + aim);
- aimShotMat.rotY(((aim / 32.0) + 0.5) * Math.PI);
- aimGunMat.rotZ(((aim / -32.0)) * Math.PI);
- aimGunXfm.setRotation(aimGunMat);
- aimShotXfm.setRotation(aimShotMat);
- aimXfmGrp.setTransform(aimGunXfm);
- theInterpolator.setAxisOfTranslation(aimShotXfm);
- } else if (keyPressed == KeyEvent.VK_SPACE) {
- //It's the spacebar so reset the start time
- //of the ball's animation
- theGunAlpha.setStartTime(System.currentTimeMillis());
- }
- }
- }
- }
- wakeupOn(theCriterion);
- }
- }
Add Comment
Please, Sign In to add comment