kellex

SimpleGame.java

Jun 17th, 2014
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.30 KB | None | 0 0
  1. /*
  2. Essential Java 3D Fast
  3.  
  4. Ian Palmer
  5.  
  6. Publisher: Springer-Verlag
  7.  
  8. ISBN: 1-85233-394-4
  9.  
  10. */
  11.  
  12. import java.awt.AWTEvent;
  13. import java.awt.BorderLayout;
  14. import java.awt.Button;
  15. import java.awt.Frame;
  16. import java.awt.event.ActionEvent;
  17. import java.awt.event.ActionListener;
  18. import java.awt.event.KeyEvent;
  19. import java.util.Enumeration;
  20.  
  21. import javax.media.j3d.Alpha;
  22. import javax.media.j3d.AmbientLight;
  23. import javax.media.j3d.Appearance;
  24. import javax.media.j3d.Behavior;
  25. import javax.media.j3d.BoundingSphere;
  26. import javax.media.j3d.Bounds;
  27. import javax.media.j3d.BranchGroup;
  28. import javax.media.j3d.Canvas3D;
  29. import javax.media.j3d.DirectionalLight;
  30. import javax.media.j3d.Locale;
  31. import javax.media.j3d.Material;
  32. import javax.media.j3d.Node;
  33. import javax.media.j3d.PhysicalBody;
  34. import javax.media.j3d.PhysicalEnvironment;
  35. import javax.media.j3d.PositionInterpolator;
  36. import javax.media.j3d.Switch;
  37. import javax.media.j3d.Transform3D;
  38. import javax.media.j3d.TransformGroup;
  39. import javax.media.j3d.View;
  40. import javax.media.j3d.ViewPlatform;
  41. import javax.media.j3d.VirtualUniverse;
  42. import javax.media.j3d.WakeupCriterion;
  43. import javax.media.j3d.WakeupOnAWTEvent;
  44. import javax.media.j3d.WakeupOnCollisionEntry;
  45. import javax.media.j3d.WakeupOnElapsedTime;
  46. import javax.media.j3d.WakeupOr;
  47. import javax.vecmath.Color3f;
  48. import javax.vecmath.Matrix3d;
  49. import javax.vecmath.Point3d;
  50. import javax.vecmath.Vector3d;
  51. import javax.vecmath.Vector3f;
  52.  
  53. import com.sun.j3d.loaders.Scene;
  54. import com.sun.j3d.loaders.objectfile.ObjectFile;
  55. import com.sun.j3d.utils.geometry.Box;
  56. import com.sun.j3d.utils.geometry.Cylinder;
  57. import com.sun.j3d.utils.geometry.Sphere;
  58.  
  59. /**
  60.  * This application demonstrates a number of things in the implementation of a
  61.  * simple shooting game. The object of the the game is to shoot a duck that
  62.  * repeatedly moves across the screen from left to right. There are two duck
  63.  * models, one for the 'live' duck and one for the 'dead' one. These are loaded
  64.  * from 'duck.obj' and 'deadduck.obj' files. The 'gun' is built from primitives.
  65.  * The duck and the ball that is used to shoot the duck use interpolators for
  66.  * their animation. The gun uses key board input to aim and fire it, and
  67.  * collision detection is used to 'kill' the duck.
  68.  *
  69.  * @author I.J.Palmer
  70.  * @version 1.0
  71.  */
  72. public class SimpleGame extends Frame implements ActionListener {
  73.   protected Canvas3D myCanvas3D = new Canvas3D(null);
  74.  
  75.   protected Button exitButton = new Button("Exit");
  76.  
  77.   protected BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0,
  78.       0.0), 100.0);
  79.  
  80.   /** Switch that is used to swap the duck models */
  81.   Switch duckSwitch;
  82.  
  83.   /** Alpha used to drive the duck animation */
  84.   Alpha duckAlpha;
  85.  
  86.   /** Used to drive the ball animation */
  87.   Alpha ballAlpha;
  88.  
  89.   /** Used to move the ball */
  90.   PositionInterpolator moveBall;
  91.  
  92.   /** Used to rotate the gun */
  93.   TransformGroup gunXfmGrp = new TransformGroup();
  94.  
  95.   /**
  96.    * This builds the view branch of the scene graph.
  97.    *
  98.    * @return BranchGroup with viewing objects attached.
  99.    */
  100.   protected BranchGroup buildViewBranch(Canvas3D c) {
  101.     BranchGroup viewBranch = new BranchGroup();
  102.     Transform3D viewXfm = new Transform3D();
  103.     Matrix3d viewTilt = new Matrix3d();
  104.     viewTilt.rotX(Math.PI / -6);
  105.     viewXfm.set(viewTilt, new Vector3d(0.0, 10.0, 10.0), 1.0);
  106.     TransformGroup viewXfmGroup = new TransformGroup(viewXfm);
  107.     ViewPlatform myViewPlatform = new ViewPlatform();
  108.     PhysicalBody myBody = new PhysicalBody();
  109.     PhysicalEnvironment myEnvironment = new PhysicalEnvironment();
  110.     viewXfmGroup.addChild(myViewPlatform);
  111.     viewBranch.addChild(viewXfmGroup);
  112.     View myView = new View();
  113.     myView.addCanvas3D(c);
  114.     myView.attachViewPlatform(myViewPlatform);
  115.     myView.setPhysicalBody(myBody);
  116.     myView.setPhysicalEnvironment(myEnvironment);
  117.     return viewBranch;
  118.   }
  119.  
  120.   /**
  121.    * This adds some lights to the content branch of the scene graph.
  122.    *
  123.    * @param b
  124.    *            The BranchGroup to add the lights to.
  125.    */
  126.   protected void addLights(BranchGroup b) {
  127.     Color3f ambLightColour = new Color3f(0.5f, 0.5f, 0.5f);
  128.     AmbientLight ambLight = new AmbientLight(ambLightColour);
  129.     ambLight.setInfluencingBounds(bounds);
  130.     Color3f dirLightColour = new Color3f(1.0f, 1.0f, 1.0f);
  131.     Vector3f dirLightDir = new Vector3f(-1.0f, -1.0f, -1.0f);
  132.     DirectionalLight dirLight = new DirectionalLight(dirLightColour,
  133.         dirLightDir);
  134.     dirLight.setInfluencingBounds(bounds);
  135.     b.addChild(ambLight);
  136.     b.addChild(dirLight);
  137.   }
  138.  
  139.   /**
  140.    * This builds the gun geometry. It uses box and cylinder primitives and
  141.    * sets up a transform group so that we can rotate the gun.
  142.    */
  143.   protected BranchGroup buildGun() {
  144.     BranchGroup theGun = new BranchGroup();
  145.     Appearance gunApp = new Appearance();
  146.     Color3f ambientColour = new Color3f(0.5f, 0.5f, 0.5f);
  147.     Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f);
  148.     Color3f specularColour = new Color3f(1.0f, 1.0f, 1.0f);
  149.     Color3f diffuseColour = new Color3f(0.5f, 0.5f, 0.5f);
  150.     float shininess = 20.0f;
  151.     gunApp.setMaterial(new Material(ambientColour, emissiveColour,
  152.         diffuseColour, specularColour, shininess));
  153.     TransformGroup init = new TransformGroup();
  154.     TransformGroup barrel = new TransformGroup();
  155.     Transform3D gunXfm = new Transform3D();
  156.     Transform3D barrelXfm = new Transform3D();
  157.     barrelXfm.set(new Vector3d(0.0, -2.0, 0.0));
  158.     barrel.setTransform(barrelXfm);
  159.     Matrix3d gunXfmMat = new Matrix3d();
  160.     gunXfmMat.rotX(Math.PI / 2);
  161.     gunXfm.set(gunXfmMat, new Vector3d(0.0, 0.0, 0.0), 1.0);
  162.     init.setTransform(gunXfm);
  163.     gunXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
  164.     gunXfmGrp.addChild(new Box(1.0f, 1.0f, 0.5f, gunApp));
  165.     barrel.addChild(new Cylinder(0.3f, 4.0f, gunApp));
  166.     gunXfmGrp.addChild(barrel);
  167.     theGun.addChild(init);
  168.     init.addChild(gunXfmGrp);
  169.     return theGun;
  170.   }
  171.  
  172.   /**
  173.    * Creates the duck. This loads the two duck geometries from the files
  174.    * 'duck.obj' and 'deadduck.obj' and loads these into a switch. The access
  175.    * rights to the switch are then set so we can write to this switch to swap
  176.    * between the two duck models. It also creates a transform group and an
  177.    * interpolator to move the duck.
  178.    *
  179.    * @return BranchGroup with content attached.
  180.    */
  181.   protected BranchGroup buildDuck() {
  182.     BranchGroup theDuck = new BranchGroup();
  183.     duckSwitch = new Switch(0);
  184.     duckSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
  185.  
  186.     ObjectFile f1 = new ObjectFile();
  187.     ObjectFile f2 = new ObjectFile();
  188.     Scene s1 = null;
  189.     Scene s2 = null;
  190.     try {
  191.       s1 = f1.load("duck.obj");
  192.       s2 = f2.load("deadduck.obj");
  193.     } catch (Exception e) {
  194.       System.exit(1);
  195.     }
  196.  
  197.     TransformGroup duckRotXfmGrp = new TransformGroup();
  198.     Transform3D duckRotXfm = new Transform3D();
  199.     Matrix3d duckRotMat = new Matrix3d();
  200.     duckRotMat.rotY(Math.PI / 2);
  201.     duckRotXfm.set(duckRotMat, new Vector3d(0.0, 0.0, -30.0), 1.0);
  202.     duckRotXfmGrp.setTransform(duckRotXfm);
  203.     duckRotXfmGrp.addChild(duckSwitch);
  204.  
  205.     duckSwitch.addChild(s1.getSceneGroup());
  206.     duckSwitch.addChild(s2.getSceneGroup());
  207.  
  208.     TransformGroup duckMovXfmGrp = new TransformGroup();
  209.     duckMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
  210.     duckMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
  211.     duckMovXfmGrp.addChild(duckRotXfmGrp);
  212.  
  213.     duckAlpha = new Alpha(-1, 0, 0, 3000, 0, 0);
  214.     Transform3D axis = new Transform3D();
  215.     PositionInterpolator moveDuck = new PositionInterpolator(duckAlpha,
  216.         duckMovXfmGrp, axis, -30.0f, 30.0f);
  217.     moveDuck.setSchedulingBounds(bounds);
  218.     theDuck.addChild(moveDuck);
  219.     theDuck.addChild(duckMovXfmGrp);
  220.     return theDuck;
  221.   }
  222.  
  223.   /**
  224.    * This builds the ball that acts as the bullet for our gun. The ball is
  225.    * created from a sphere primitive, and a transform group and interpolator
  226.    * are added so that we can 'fire' the bullet.
  227.    *
  228.    * @return BranchGroup that is the root of the ball branch.
  229.    */
  230.   protected BranchGroup buildBall() {
  231.     BranchGroup theBall = new BranchGroup();
  232.  
  233.     Appearance ballApp = new Appearance();
  234.     Color3f ambientColour = new Color3f(1.0f, 0.0f, 0.0f);
  235.     Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f);
  236.     Color3f specularColour = new Color3f(1.0f, 1.0f, 1.0f);
  237.     Color3f diffuseColour = new Color3f(1.0f, 0.0f, 0.0f);
  238.     float shininess = 20.0f;
  239.     ballApp.setMaterial(new Material(ambientColour, emissiveColour,
  240.         diffuseColour, specularColour, shininess));
  241.  
  242.     Sphere ball = new Sphere(0.2f, ballApp);
  243.  
  244.     TransformGroup ballMovXfmGrp = new TransformGroup();
  245.     ballMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
  246.     ballMovXfmGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
  247.     ballMovXfmGrp.addChild(ball);
  248.     theBall.addChild(ballMovXfmGrp);
  249.  
  250.     ballAlpha = new Alpha(1, 0, 0, 500, 0, 0);
  251.     Transform3D axis = new Transform3D();
  252.     axis.rotY(Math.PI / 2);
  253.     moveBall = new PositionInterpolator(ballAlpha, ballMovXfmGrp, axis,
  254.         0.0f, 50.0f);
  255.     moveBall.setSchedulingBounds(bounds);
  256.     theBall.addChild(moveBall);
  257.  
  258.     return theBall;
  259.  
  260.   }
  261.  
  262.   /**
  263.    * This puts all the content togther. It used the three 'build' functions to
  264.    * create the duck, the gun and the ball. It also creates the two behaviours
  265.    * from the DuckBehaviour and GunBehaviour classes. It then puts all this
  266.    * together.
  267.    *
  268.    * @return BranchGroup that is the root of the content.
  269.    */
  270.   protected BranchGroup buildContentBranch() {
  271.     BranchGroup contentBranch = new BranchGroup();
  272.     Node theDuck = buildDuck();
  273.     contentBranch.addChild(theDuck);
  274.     Node theBall = buildBall();
  275.     contentBranch.addChild(theBall);
  276.     DuckBehaviour hitTheDuck = new DuckBehaviour(theDuck, duckSwitch,
  277.         duckAlpha, bounds);
  278.     GunBehaviour shootTheGun = new GunBehaviour(ballAlpha, moveBall,
  279.         gunXfmGrp, bounds);
  280.     contentBranch.addChild(hitTheDuck);
  281.     contentBranch.addChild(shootTheGun);
  282.     contentBranch.addChild(buildGun());
  283.     addLights(contentBranch);
  284.     return contentBranch;
  285.   }
  286.  
  287.   /** Exit the application */
  288.   public void actionPerformed(ActionEvent e) {
  289.     dispose();
  290.     System.exit(0);
  291.   }
  292.  
  293.   public SimpleGame() {
  294.     VirtualUniverse myUniverse = new VirtualUniverse();
  295.     Locale myLocale = new Locale(myUniverse);
  296.     myLocale.addBranchGraph(buildViewBranch(myCanvas3D));
  297.     myLocale.addBranchGraph(buildContentBranch());
  298.     setTitle("Duck Shoot!");
  299.     setSize(400, 400);
  300.     setLayout(new BorderLayout());
  301.     add("Center", myCanvas3D);
  302.     exitButton.addActionListener(this);
  303.     add("South", exitButton);
  304.     setVisible(true);
  305.  
  306.   }
  307.  
  308.   public static void main(String[] args) {
  309.     SimpleGame sg = new SimpleGame();
  310.   }
  311.  
  312. }
  313. /**
  314.  * This is used in the SimpleGame application. It defines the behaviour for the
  315.  * duck, which is the target in the shooting game. If something collides with
  316.  * the duck, it swaps a switch value to 'kill' the duck The duck is revived when
  317.  * it's alpha value passes through zero.
  318.  *
  319.  * @author I.J.Palmer
  320.  * @version 1.0
  321.  */
  322.  
  323. class DuckBehaviour extends Behavior {
  324.   /** The shape that is being watched for collisions. */
  325.   protected Node collidingShape;
  326.  
  327.   /** The separate criteria that trigger this behaviour */
  328.   protected WakeupCriterion[] theCriteria;
  329.  
  330.   /** The result of the 'OR' of the separate criteria */
  331.   protected WakeupOr oredCriteria;
  332.  
  333.   /** The switch that is used to swap the duck shapes */
  334.   protected Switch theSwitch;
  335.  
  336.   /** The alpha generator that drives the animation */
  337.   protected Alpha theTargetAlpha;
  338.  
  339.   /** Defines whether the duck is dead or alive */
  340.   protected boolean dead = false;
  341.  
  342.   /**
  343.    * This sets up the data for the behaviour.
  344.    *
  345.    * @param theShape
  346.    *            Node that is to be watched for collisions.
  347.    * @param sw
  348.    *            Switch that is used to swap shapes.
  349.    * @param a1
  350.    *            Alpha that drives the duck's animation.
  351.    * @param theBounds
  352.    *            Bounds that define the active region for this behaviour.
  353.    */
  354.   public DuckBehaviour(Node theShape, Switch sw, Alpha a1, Bounds theBounds) {
  355.     collidingShape = theShape;
  356.     theSwitch = sw;
  357.     theTargetAlpha = a1;
  358.     setSchedulingBounds(theBounds);
  359.   }
  360.  
  361.   /**
  362.    * This sets up the criteria for triggering the behaviour. It creates an
  363.    * collision crtiterion and a time elapsed criterion, OR's these together
  364.    * and then sets the OR'ed criterion as the wake up condition.
  365.    */
  366.   public void initialize() {
  367.     theCriteria = new WakeupCriterion[2];
  368.     theCriteria[0] = new WakeupOnCollisionEntry(collidingShape);
  369.     theCriteria[1] = new WakeupOnElapsedTime(1);
  370.     oredCriteria = new WakeupOr(theCriteria);
  371.     wakeupOn(oredCriteria);
  372.   }
  373.  
  374.   /**
  375.    * This is where the work is done. If there is a collision, then if the duck
  376.    * is alive we switch to the dead duck. If the duck was already dead then we
  377.    * take no action. The other case we need to check for is when the alpha
  378.    * value is zero, when we need to set the duck back to the live one for its
  379.    * next traversal of the screen. Finally, the wake up condition is set to be
  380.    * the OR'ed criterion again.
  381.    */
  382.   public void processStimulus(Enumeration criteria) {
  383.     while (criteria.hasMoreElements()) {
  384.       WakeupCriterion theCriterion = (WakeupCriterion) criteria
  385.           .nextElement();
  386.       if (theCriterion instanceof WakeupOnCollisionEntry) {
  387.         //There'sa collision so if the duck is alive swap
  388.         //it to the dead one
  389.         if (dead == false) {
  390.           theSwitch.setWhichChild(1);
  391.           dead = true;
  392.         }
  393.       } else if (theCriterion instanceof WakeupOnElapsedTime) {
  394.         //If there isn't a collision, then check the alpha
  395.         //value and if it's zero, revive the duck
  396.         if (theTargetAlpha.value() < 0.1) {
  397.           theSwitch.setWhichChild(0);
  398.           dead = false;
  399.         }
  400.       }
  401.  
  402.     }
  403.     wakeupOn(oredCriteria);
  404.   }
  405. }
  406.  
  407. /**
  408.  * This is used in the SimpleGame application. It defines a behaviour that
  409.  * allows a 'gun' to be rotated when left and right cursor keys are pressed and
  410.  * then a ball is 'fired' when the space bar is pressed. The 'firing' is
  411.  * achieved by setting the start time of an interpolator to the current time.
  412.  *
  413.  * @author I.J.Palmer
  414.  * @version 1.0
  415.  */
  416.  
  417. class GunBehaviour extends Behavior {
  418.   /** The separate criteria that trigger this behaviour */
  419.   protected WakeupCriterion theCriterion;
  420.  
  421.   /** The alpha that is used to 'fire' the ball */
  422.   protected Alpha theGunAlpha;
  423.  
  424.   /** Used to animate the ball */
  425.   protected PositionInterpolator theInterpolator;
  426.  
  427.   /** Used to calculate the current direction of the gun */
  428.   protected int aim = 0;
  429.  
  430.   /** This is used to rotate the gun */
  431.   protected TransformGroup aimXfmGrp;
  432.  
  433.   /** Used to aim the ball */
  434.   protected Matrix3d aimShotMat = new Matrix3d();
  435.  
  436.   /** Used to aim the gun */
  437.   protected Matrix3d aimGunMat = new Matrix3d();
  438.  
  439.   /** Used to define the ball's direction */
  440.   protected Transform3D aimShotXfm = new Transform3D();
  441.  
  442.   /** Used to define the gun's direction */
  443.   protected Transform3D aimGunXfm = new Transform3D();
  444.  
  445.   /**
  446.    * Set up the data for the behaviour.
  447.    *
  448.    * @param a1
  449.    *            Alpha that drives the ball's animation.
  450.    * @param pi
  451.    *            PositionInterpolator used for the ball.
  452.    * @param gunRotGrp
  453.    *            TransformGroup that is used to rotate the gun.
  454.    * @param theBounds
  455.    *            Bounds that define the active region for this behaviour.
  456.    */
  457.   public GunBehaviour(Alpha a1, PositionInterpolator pi,
  458.       TransformGroup gunRotGrp, Bounds theBounds) {
  459.     theGunAlpha = a1;
  460.     theInterpolator = pi;
  461.     setSchedulingBounds(theBounds);
  462.     aimXfmGrp = gunRotGrp;
  463.   }
  464.  
  465.   /**
  466.    * This sets up the criteria for triggering the behaviour. We simple want to
  467.    * wait for a key to be pressed.
  468.    */
  469.   public void initialize() {
  470.     theCriterion = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
  471.     wakeupOn(theCriterion);
  472.   }
  473.  
  474.   /**
  475.    * This is where the work is done. This identifies which key has been
  476.    * pressed and acts accordingly: left key cursor rotate left, right cursor
  477.    * key rotate right, spacebar fire.
  478.    *
  479.    * @criteria Enumeration that represents the trigger conditions.
  480.    */
  481.   public void processStimulus(Enumeration criteria) {
  482.     while (criteria.hasMoreElements()) {
  483.       WakeupCriterion theCriterion = (WakeupCriterion) criteria
  484.           .nextElement();
  485.       if (theCriterion instanceof WakeupOnAWTEvent) {
  486.         AWTEvent[] triggers = ((WakeupOnAWTEvent) theCriterion)
  487.             .getAWTEvent();
  488.         //Check if it's a keyboard event
  489.         if (triggers[0] instanceof KeyEvent) {
  490.           int keyPressed = ((KeyEvent) triggers[0]).getKeyCode();
  491.           if (keyPressed == KeyEvent.VK_LEFT) {
  492.             //It's a left key so move the turret
  493.             //and the aim of the gun left unless
  494.             //we're at our maximum angle
  495.             if (aim < 8)
  496.               aim += 1;
  497.             System.out.println("Left " + aim);
  498.             aimShotMat.rotY(((aim / 32.0) + 0.5) * Math.PI);
  499.             aimGunMat.rotZ(((aim / -32.0)) * Math.PI);
  500.             aimShotXfm.setRotation(aimShotMat);
  501.             aimGunXfm.setRotation(aimGunMat);
  502.             aimXfmGrp.setTransform(aimGunXfm);
  503.             theInterpolator.setAxisOfTranslation(aimShotXfm);
  504.           } else if (keyPressed == KeyEvent.VK_RIGHT) {
  505.             //It's the right key so do the same but rotate right
  506.             if (aim > -8)
  507.               aim -= 1;
  508.             System.out.println("Right " + aim);
  509.             aimShotMat.rotY(((aim / 32.0) + 0.5) * Math.PI);
  510.             aimGunMat.rotZ(((aim / -32.0)) * Math.PI);
  511.             aimGunXfm.setRotation(aimGunMat);
  512.             aimShotXfm.setRotation(aimShotMat);
  513.             aimXfmGrp.setTransform(aimGunXfm);
  514.             theInterpolator.setAxisOfTranslation(aimShotXfm);
  515.           } else if (keyPressed == KeyEvent.VK_SPACE) {
  516.             //It's the spacebar so reset the start time
  517.             //of the ball's animation
  518.             theGunAlpha.setStartTime(System.currentTimeMillis());
  519.           }
  520.         }
  521.       }
  522.     }
  523.     wakeupOn(theCriterion);
  524.   }
  525. }
Add Comment
Please, Sign In to add comment