CMSC325 - Game Design and Development

Week 1 Participation Topic: Personal Experience

Please reply to this topic with your background in gaming.

Specify your first experience of gaming and the game system.

What game system do you currently own/use, including consoles, mobile devices or PC?

What is your favorite game and game type? Why do you like it most?

Lastly, please outline your future career plan in gaming industry, if any.

Specify your first experience of gaming and the game system.

My first game console I ever used was Nintendo Family Computer known as Nintendo Entertainment System (NES) in the U.S., and my first game titles were a Dragon Ball's fighting game and Renegade, which is a beat 'em up game developed by TECHNOS JAPAN.

Also my first mobile device I used was Game Boy, and what I first played on it was FINAL FANTASY LEGEND II developed by SQUARE ENIX.

What game system do you currently own/use, including consoles, mobile devices or PC?

Game systems I currently own are as follows.

Consoles: PlayStation, PlayStation 2
Mobile devices: Game Boy Light, Android Phone, iPhone 5
Mac: iBook G4, Macbook

What is your favorite game and game type? Why do you like it most?

Role-playing Games (RPGs) are the most favorite because imaginary world experiences seem like reading a novel. Also it is very exciting that the main characters become stronger by earning experience points. I was especially absorbed in Pokemon and Dragon Quest series for Game Boy, FINAL FANTASY series for Play Station and Play Station 2 when I was little.

In addition to RPGs, I also like simulation games. I often used to play Capcom's Monster Hunter and KONAMI's Live Powerful Pro Baseball, a popular baseball simulation game series in Japan, on PS and PS2.

Lastly, please outline your future career plan in gaming industry, if any.

In my future, I am interested in working for creating social games and developing their game systems as a technical director.

Week 1 Homework 1

Your task for this first homework assignment is to install your development environment (IDE) if you haven't already (NetBeans or Eclipse for Java, Visual Studio for C#), and create a basic coin-flip guessing game. The game should prompt the player to choose heads or tails, flip a virtual coin and then display the results to the player. You do not need to actually show the coin. However, you have to keep track of the coin flipping outcomes and the player’s guesses. Try the game for 100 times (use a loop), and generate a statistics on the odds of getting the right guess.

What to submit:

All of the above should be attached to your assignment as a single *.zip file.

import java.util.*;
import javax.swing.*;

public class CoinFlipTest {
	
	public static void main(String[] args) {
		int select, rand, result;
		String selectvalues[] = {"Heads", "Tails"};
		String coinSides=null, userGuess=null;
		
		/** Instantiate an array list for storing outcomes. **/
		ArrayList<Integer> outcomes = new ArrayList<Integer>();
		
		for (int i=0; i<100; i++) {	// Determine the number of coin flips
			
			/** Flip the coin, and then it comes up heads or tails randomly **/
			rand = generateRandomValue();
			if (rand == 0) {
				coinSides = "Heads";
			} else {
				coinSides = "Tails";
			}

			/** User selection **/
			int j = i + 1;
			select = JOptionPane.showOptionDialog(null, 
					"Choose Heads or Tails. " + "(Number of times: " + j + ")", 
					"Your Guess", 
					JOptionPane.YES_NO_OPTION, 
					JOptionPane.QUESTION_MESSAGE, 
					null, 
					selectvalues, 
					selectvalues[0]);
			
			// if user click on the close button, break out of the loop.
			if (select == JOptionPane.CLOSED_OPTION) {
				break;
			}
		
			/** Determine if user guess is right or wrong. **/
			if (rand == select) {
				userGuess = "right";
				outcomes.add(0); // if right => 0
			} else {
				userGuess = "wrong";
				outcomes.add(1); // if wrong => 1
			}

			/** Display a result. **/
			JOptionPane.showMessageDialog(null, 
					"The result is " + coinSides + "! " + "Your guess is " + userGuess +"!", 
					"Result", 
					JOptionPane.INFORMATION_MESSAGE);
		}
		
		/** Display the odds **/
		JOptionPane.showMessageDialog(null, 
				"Your odds of getting the right guess are " + calculateOdds(outcomes), 
				"Your Odds", 
				JOptionPane.INFORMATION_MESSAGE);		
	}
	
	/** Generate a random value for flip of a coin. **/
	private static int generateRandomValue() {
		int r = (int) (Math.random()*2);
		return r;
	}
	
	/** Calculate user odds. **/
	private static float calculateOdds(ArrayList<Integer> list) {
		int numOfRightAnswers=0, numOfWrongAnswers=0;

		Iterator it = list.iterator();
		while(it.hasNext()) {
			Integer e = (Integer) (it.next());
			if (e == 0) {
				numOfRightAnswers++;
			} else {
				numOfWrongAnswers++;
			}
		}
		// odds = the number of desirable outcomes/the number of undesirable outcomes
		return (float) numOfRightAnswers/numOfWrongAnswers;
	}

}

Week 2 Participation Topic: Storytelling in Games

Pick a story-driven game that you have recently played. Share the story with us.

Describe what the game was, what captivated you about the story, and what made you think of it now.

If you cannot think of any games for your story-telling, how do you think can a game be story-driven? Consider the premises and the characters involved in the game.

One of the best story-driven games that I ever played was "Metal Gear Solid 3: Snake Eater" developed and published by Konami for Play Station 2.

The story is set in 1964 after the Cuban Missile Crisis in the middle of the Cold War. The main character is a CIA. agent and FOX operative codenamed "Naked Snake." FOX is a high-tech special covert forces unit in the game. His mission is to rescue USSR's scientist named Sokolov who is developing a nuclear-equipped weapon called Shagohod.

In addition to its splendid story, its 3D depiction makes a very realistic world view.

Week 2 Homework 2

Within 500 words, describe the social implications of gaming. Besides entertainment, think of other aspect of our society that can be affected by gaming.

As with all written assignments, please review your paper for the correct use of grammar and spelling. Don’t forget to cite the references for your paper in proper format. There is a link in the syllabus for UMUC writing guideline.

fileCMSC325_Homework2.pdf

Week 3 Project 1: Questions and Comments

I am wondering which I should choose Java or C++ as my language for my projects.

Hopefully I would like to use OpenGL with C++ because I took Computer Graphics class in the last term and I learned them. But there is a problem that my development environment for OpenGL and C++ is XCode on Mac OS X Snow Leopard (10.6).

Can I submit only header files and source codes? Or, do I have to change them to exe file? I might be able to do so by running Windows on my Mac with VMWare Fusion and installing Visual C++, but that process won't be simple.

What do you recommend?

I would recommend you to use JMonkey 3d engine, which is Java based. You can develop the project games easily with this package.

Just go over the tutorials to get started.

Week3 Project 1

You will use an existing game engine and map to modify and create your own level. Your instructor will provide some possible engines to use but the student is also free to recommend a game engine they have used before that has modification features.

The level you create must be unique, realistic and playable by multiple players.

The following components and design criteria should be used:

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import java.util.ArrayList;

/**
 * @author yujishimojo
 */
public class BouncingBallsMain extends SimpleApplication {
    public static void main(String args[]) {
    BouncingBallsMain app = new BouncingBallsMain();
    app.start();
  }
 
  /** Prepare the Physics Application State (jBullet) */
  private BulletAppState bulletAppState;
 
  /** Prepare Materials */
  Material ball_mat, floor_mat, red_wall_mat, blue_wall_mat, 
           green_wall_mat, yellow_wall_mat;
 
  /** Prepare geometries and physical nodes for walls and balls. */
  private RigidBodyControl    ball_phy, floor_phy, red_wall_phy, 
                              blue_wall_phy, green_wall_phy, yellow_wall_phy;
  private static final Sphere sphere;
  private static final Box    floor, red_wall, blue_wall, green_wall, yellow_wall;
  private static Node shootables;
  private static Geometry ball_geo, floor_geo, red_wall_geo, blue_wall_geo, 
                          green_wall_geo, yellow_wall_geo; 
  private static ArrayList list1, list2;
  
  static {
    /** Initialize the ball geometry */
    sphere = new Sphere(32, 32, 0.4f, true, false);
    /** Initialize the floor geometry */
    floor = new Box(Vector3f.ZERO, 5f, 0.1f, 5f);
    /** Initialize the walls geometry */
    red_wall = new Box(Vector3f.ZERO, 5f, 5f, 0.1f);
    blue_wall = new Box(Vector3f.ZERO, 5f, 5f, 0.1f);
    green_wall = new Box(Vector3f.ZERO, 0.1f, 5f, 5f);
    yellow_wall = new Box(Vector3f.ZERO, 0.1f, 5f, 5f);
    list1 = new ArrayList();
    list2 = new ArrayList();
  }
 
  @Override
  public void simpleInitApp() {
    /** Set up Physics Game */
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    
    // This array is used to decide camera location
    float[] array = generateRandomLocation();
    
    /** Configure cam to look at scene */
    // Cam location and direction will be selected randomly between 4 patterns.
    cam.setLocation(new Vector3f(array[0], 20f, array[1]));
    cam.lookAt(new Vector3f(array[2], 10, array[3]), Vector3f.UNIT_Y);
    /** Add InputManager action: Left click triggers shooting. */
    inputManager.addMapping("shoot", 
            new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(actionListener, "shoot");
    
    /** Initialize the scene, materials, and physics space */
    initMaterials();
    initFloor();
    initRedWall();
    initBlueWall();
    initGreenWall();
    initYellowWall();
    initCrossHairs();
    
    /** create a floor and four walls to shoot at: */
    shootables = new Node("Shootables");
    rootNode.attachChild(shootables);
    shootables.attachChild(floor_geo);
    shootables.attachChild(red_wall_geo);
    shootables.attachChild(blue_wall_geo);
    shootables.attachChild(green_wall_geo);
    shootables.attachChild(yellow_wall_geo);
  }
 
  /**
   * Every time the shoot action is triggered, a new ball is produced.
   * The ball is set up to fly from the camera position in the camera direction.
   */
  private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      initCrossHairs();
      if (name.equals("shoot") && !keyPressed) {
        makeBall();
        // Reset results list.
        CollisionResults results = new CollisionResults();
        // Aim the ray from cam loc to cam direction.
        Ray ray = new Ray(cam.getLocation(), cam.getDirection());
        // Collect intersections between Ray and Shootables in results list.
        shootables.collideWith(ray, results);
        // Print the results
        for (int i = 0; i < results.size(); i++) {
          float dist = results.getCollision(i).getDistance();
          Vector3f pt = results.getCollision(i).getContactPoint();
          String hit = results.getCollision(i).getGeometry().getName();
          // Display a position of a shpere on collision
          // For each hit, we know distance, impact point, name of geometry.
          guiNode.detachAllChildren();
          guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
          BitmapText text = new BitmapText(guiFont, false);
          text.setSize(guiFont.getCharSet().getRenderedSize());
          text.setText("Ball hits " + hit + " at " + pt);
          text.setLocalTranslation(250, text.getLineHeight(), 0);
          guiNode.attachChild(text);
          // Store 3D vector positions to an array list and show them
          list1.add(pt);
          System.out.println("(x, y, z) = " + list1);
        }
        if (results.size() > 0) {
            CollisionResult closest = results.getClosestCollision();
            ball_geo.setLocalTranslation(closest.getContactPoint());
            rootNode.attachChild(ball_geo);
        } else {
            rootNode.detachChild(ball_geo);
        }            
      }
    }
  };
 
   /** Initialize the materials used in this scene. */
   public void initMaterials() {
    ball_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    ball_mat.setColor("Color", new ColorRGBA(0.4f,0,0.2f,0.5f));
    
    floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    floor_mat.setColor("Color", new ColorRGBA(0.6f,0.3f,0,0.5f));
    //floor_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
    
    red_wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    red_wall_mat.setColor("Color", new ColorRGBA(0.5f,0f,0f,0.5f));
    //red_wall_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
    
    blue_wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    blue_wall_mat.setColor("Color", new ColorRGBA(0f,0f,0.5f,0.5f));
    //blue_wall_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
    
    green_wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    green_wall_mat.setColor("Color", new ColorRGBA(0f,0.5f,0,0.5f));
    //green_wall_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
    
    yellow_wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    yellow_wall_mat.setColor("Color", new ColorRGBA(0.5f,0.5f,0,0.5f));
    //yellow_wall_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
   }
  
   /** Make a solid floor. */
   public void initFloor() {
    floor_geo = new Geometry("floor", floor);
    floor_geo.setMaterial(floor_mat);
    //make the floor translucent
    floor_geo.setQueueBucket(RenderQueue.Bucket.Translucent);
    floor_geo.setLocalTranslation(0, 1, 0);
    this.rootNode.attachChild(floor_geo);
    /* Make the floor physical with mass 0.0f! */
    floor_phy = new RigidBodyControl(0.0f);
    floor_geo.addControl(floor_phy);
    bulletAppState.getPhysicsSpace().add(floor_phy);
   }

   /** Make solid walls. */
   public void initRedWall() {
    red_wall_geo = new Geometry("red wall", red_wall);
    red_wall_geo.setMaterial(red_wall_mat);
    //make the wall translucent
    red_wall_geo.setQueueBucket(RenderQueue.Bucket.Translucent);
    red_wall_geo.setLocalTranslation(0, 5.9f, 5.1f);
    this.rootNode.attachChild(red_wall_geo);
    /* Make the wall physical with mass 0.0f! */
    red_wall_phy = new RigidBodyControl(0.0f);
    red_wall_geo.addControl(red_wall_phy);
    bulletAppState.getPhysicsSpace().add(red_wall_phy);
   }

   public void initBlueWall() {
    blue_wall_geo = new Geometry("blue wall", blue_wall);
    blue_wall_geo.setMaterial(blue_wall_mat);
    //make the wall translucent
    blue_wall_geo.setQueueBucket(RenderQueue.Bucket.Translucent);
    blue_wall_geo.setLocalTranslation(0, 5.9f, -5.1f);
    this.rootNode.attachChild(blue_wall_geo);
    blue_wall_phy = new RigidBodyControl(0.0f);
    blue_wall_geo.addControl(blue_wall_phy);
    bulletAppState.getPhysicsSpace().add(blue_wall_phy);
   } 
   
   public void initGreenWall() {
    green_wall_geo = new Geometry("green wall", green_wall);
    green_wall_geo.setMaterial(green_wall_mat);
    //make the wall translucent
    green_wall_geo.setQueueBucket(RenderQueue.Bucket.Translucent);
    green_wall_geo.setLocalTranslation(-5.1f, 5.9f, 0);
    this.rootNode.attachChild(green_wall_geo);
    green_wall_phy = new RigidBodyControl(0.0f);
    green_wall_geo.addControl(green_wall_phy);
    bulletAppState.getPhysicsSpace().add(green_wall_phy);
   }

   public void initYellowWall() {
    yellow_wall_geo = new Geometry("yellow wall", yellow_wall);
    yellow_wall_geo.setMaterial(yellow_wall_mat);
    //make the wall translucent
    yellow_wall_geo.setQueueBucket(RenderQueue.Bucket.Translucent);
    yellow_wall_geo.setLocalTranslation(5.1f, 5.9f, 0);
    this.rootNode.attachChild(yellow_wall_geo);
    yellow_wall_phy = new RigidBodyControl(0.0f);
    yellow_wall_geo.addControl(yellow_wall_phy);
    bulletAppState.getPhysicsSpace().add(yellow_wall_phy);
   }
 
  /** This method creates one individual physical ball.
   * The ball is accelerated and flies
   * from the camera position in the camera direction.*/
   public void makeBall() {
    /** Create a ball geometry. */
    ball_geo = new Geometry("ball", sphere);
    ball_geo.setMaterial(ball_mat);
    shootables.attachChild(ball_geo);
    /** Position the ball  */
    ball_geo.setLocalTranslation(cam.getLocation());
    /** Make the ball physcial with a mass > 0.0f */
    ball_phy = new RigidBodyControl(1f);
    /** Add physical ball to physics space. */
    ball_geo.addControl(ball_phy);
    bulletAppState.getPhysicsSpace().add(ball_phy);
    /** Accelerate the physcial ball to shoot it. */
    int velocity = generateRandomVelocity();
    ball_phy.setLinearVelocity(cam.getDirection().mult(velocity));
    // Store linear velocities to an array list and show them
    list2.add(velocity);
    System.out.println("Velocity is " + list2);
    /** Set gravity on y-axis. */
    ball_phy.setGravity(new Vector3f(0, -5, 0));
  }
   
    /** Generate a random velocity from 20 to 80. **/
    private int generateRandomVelocity() {
        int v = (int) Math.ceil(Math.random()*61)+20;
        return v;
    }
    
    /** Generate a random camera location between 4. **/
    private float[] generateRandomLocation() {
        float[] a0 = {5f, 10f, 1f, -1f};
        float[] a1 = {10f, -10f, -1f, -1f};
        float[] a2 = {-5f, -10f, -1f, 1f};
        float[] a3 = {-10f, 5f, 1f, 1f};
        int n = (int) Math.floor(Math.random()*4);
        switch (n) {
            case 0: return a0;
            case 1: return a1;
            case 2: return a2;
            case 3: return a3;
            default: return a0;
        }
    }
 
    /** A plus sign used as crosshairs to help the player with aiming.*/
    protected void initCrossHairs() {
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont, false);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+");        // fake crosshairs :)
        ch.setLocalTranslation( // center
            settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
            settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
        guiNode.attachChild(ch);
    } 
}

Week 4 Participation Topic: Painting with Triangles

Since the advent of polygons to draw game objects and move gaming fully into three dimensions, there has been much debate about whether certain games would be better using sprites instead of polygons. For instances, many "2D" fighting games, games in which players only move in two dimensions, are moving from traditional hand-drawn sprites to rendered 3D models using polygons. Choose a game that uses one of these techniques (polygons or sprites), and detail why you think it would be better if it used the other. Reading the posts from the other students, reply to at least two and describe whether you agree or disagree with them.

Metal Gear Solid series are definitely suited for 3D polygons. I also think most of story-driven games such as RPGs are more thrilling and impressive in 3D by realistic models, advanced animations, and appropriate camera views. Thus, players will be more deep into the game.

I agree with the point that the positioning would be easier to get correct if this was a sprite based game.

In fighting games, it is important for users to be able to predict timing and perceive distance and direction accurately. Because of only X and Y axes, 2D is easier to do so.

I agree that Super Mario Bros. is a successful example to migrate from 2D to 3D.

I think such migration of this kind of game is quite a hard work because in Super Mario Bros, the user needs to predict timing and perceive distance and direction. I suppose Nintendo achieved a redesign of the game with keeping the core concept.

Week 4 Homework 3

The conference discussion this week will have you looking at the differences in sprites versus polygons, arguably "old" versus "new" technology. Though they have been used for many years now, there is no reason to expect that polygons will never be replaced with something newer and more advanced. In at least 500 words, describe what a "voxel" is and how it differs from both sprites and polygons. What would be some advantages and disadvantages of using voxels?

As with all written assignments, please review your paper for the use of proper grammar and spelling. Please also make sure to properly and consistently cite any sources that you use.

fileCMSC325_Homework3.pdf

Week 5 Participation Topic: Acting Out

When you think about artificial intelligence, you might imagine something like an autonomous enemy chasing the player down or an AI companion (who usually runs out of his or her way to get shot). However, artificial intelligence is used in quite a few places. For example, a game which immerses a player in a world with a rich ecosystem, might use AI to control the weather.

This week, I would like everyone to think about and describe an example of how AI could used in a "non-traditional" sense.

An example of non-traditional AI based game I ever played that comes to mind is SEGA's soccer club management and player development simulation game named Soccer Tsuku 2002: J-League Pro Soccer Club o Tsukurou! that means let's make a J-League pro soccer club!

You run your own pro soccer club by making training programs and acquiring players for the purpose of building world's most powerful team. Although you can give instructions during games, you cannot operate any players directly.

Sorry! I could find the only Japanese Web site as below.
http://www.sakatsuku.com/history/06/

Week 5 Homework 4

Especially with online multiplayer games, companies are heavily vested in protecting both their intellectual property from theft (digital rights management, "DRM") and other players from cheating (hack/bot detection). In at least 500 words, describe some of the ethical and legal issues with involved with these techniques. Is it fair to subject players to increasingly invasive protection mechanisms, or is it necessary in order to protect the experience?

As with all written assignments, please review your paper for the use of proper grammar and spelling. Please also make sure to properly and consistently cite any sources that you use.

fileCMSC325_Homework4.pdf

Week 6 Finding Your Own Path

As you should all have realized by now, designing and making a video game isn't fun all of the time. I know that most of you probably have had to turn to outside resources to find solutions to problems. This is part of the learning process (this is a 300-level course afterall) and there is really no way to encapsulate all of the knowledge necessary for every possible game in one course.

This week, I want to know what you had to go searching for and how (if) you found it. Did you have to look up specific formulas for your physics calculations? Did you have to find the right method to call for your graphics API to get something on screen? Did you have to look for something else? (these are only examples)

I created both PR1 and PR2 by using jMonkeyEngine for the first time. Actually, the most of its syntax and methods I learned are from the tutorials below.
http://jmonkeyengine.org/wiki/doku.php/jme3

Sometimes, I can hardly understand of exact behavior and parameter meanings of a particular method of a jME API class. When that happens, I check jME API documentation.
http://www.jmonkeyengine.com/doc/

Because jME org offers a lot of materials, I can find out its information to develop easily. But there is very few Japanese information, so I hopefully would like the system to support Japanese in the near future.

Week 6 Project 2

Create a Java or C# application that simulates a minimum of 3 spheres moving through a frictionless environment with gravity. The environment should be a confined cube area for the spheres to collide and respond. The application does need to display the positions of the spheres in real time, but the 3D vector positions should be saved for each sphere to an output file for future plotting. Set initial velocities and positions and run the simulation for at least 100 iterations. Design your application such that collisions and their associated responses will occur during the simulation.

You should submit your completed application Java source code and required deliverables in compressed format (winzip.com) in your WebTycho portfolio by the due date listed in the syllabus.

Deliverables include:

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import java.util.Random;

/**
 * @author yujishimojo
 */
public class BouncingBallsMain2 extends SimpleApplication implements PhysicsCollisionListener {
    public static BouncingBallsMain2 app = new BouncingBallsMain2();
    
    //create a new file for storing position and velocity data
    public static java.io.File file = new java.io.File("positions.txt");
    public static java.io.PrintWriter output;
    public static java.io.File file2 = new java.io.File("collision_points.txt");
    public static java.io.PrintWriter output2;
    
    // initiate the objects for generating random numbers
    private Random positionGenerator = new Random();
    private Random velGenerator = new Random();
    private Random posNegGenerator = new Random();
    private Random gravGenerator = new Random();
    
    private Vector3f pt;    // 3D vector position of ball on collision
    private String hit;     // which the object ball hits
    
    // intiate the variable for storing time
    long startTime;
    long startGravTime;
    long estimatedTime;
    
    // variable determines whether gravity is universal
    //  or seperate for the balls
    boolean randGrav = false;
    
    private BitmapText gravText;

    // Set the number of generated balls
    final int NUMBALLS = 8;
    
    // Set the initial velocity in XYZ
    final int IVX = 5;
    final int IVY = 5;
    final int IVZ = 5;
    
    // intiate the objects that will allow for the application of physics
    private BulletAppState   bulletAppState;

    private RigidBodyControl[] ball_physics = new RigidBodyControl[NUMBALLS];
    
    BouncingBallsMain2.BallTextDisplay[] ballDisplays = new BallTextDisplay[NUMBALLS];
    
    public static void main(String[] args) throws Exception {
        output = new java.io.PrintWriter(file);        
        output2 = new java.io.PrintWriter(file2);
        app.start(); // start the game
    }    
    
    @Override
    public void simpleInitApp() {
        
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        bulletAppState.getPhysicsSpace().addCollisionListener(this);
        
        // Set the location of the camera to be in one of the
        // top corners of the cube looking in towards the center
        cam.setLocation(new Vector3f(45, 40, 40));
        cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
        
        flyCam.setEnabled(true);
        flyCam.setMoveSpeed(10);
        
        // Start the timer
        startTime = System.currentTimeMillis();
        startGravTime = System.currentTimeMillis();
        
        BouncingBallsMain2.SphereObj[] sphereObjects = new BouncingBallsMain2.SphereObj[NUMBALLS];
        
        //Create the spheres
        for (int i = 0; i < NUMBALLS; i++) {
            if (i < 2) {
                // posX: -15 to -10, posY: -3 to 2, posZ: -3 to 2
                sphereObjects[i] = new BouncingBallsMain2.SphereObj("yellow", -15);
            }
            else if(i < 4) {
                // posX: -5 to 0, posY: -3 to 2, posZ: -3 to 2
                sphereObjects[i] = new BouncingBallsMain2.SphereObj("red", -5);
            }
            else if (i < 6) {
                // posX: 5 to 10, posY: -3 to 2, posZ: -3 to 2
                sphereObjects[i] = new BouncingBallsMain2.SphereObj("green", 5);
            }
            else {
                // posX: 15 to 20, posY: -3 to 2, posZ: -3 to 2
                sphereObjects[i] = new BouncingBallsMain2.SphereObj("purple", 15);
            }
        }
        
        // Give the balls a physical presence
        for (int i = 0; i < NUMBALLS; i++) {
            ball_physics[i] = new RigidBodyControl(1f);
        }
        // Add the balls to the scene
        for (int i = 0; i < NUMBALLS; i++) {
            sphereObjects[i].addControl(ball_physics[i]);
        }
        
        for (int i = 0; i < NUMBALLS; i++) {
            bulletAppState.getPhysicsSpace().add(ball_physics[i]);
        }
        
        // Make the balls bouncy
        for (int i = 0; i < NUMBALLS; i++) {
            ball_physics[i].setRestitution(1.5f);
        }
        
        // Add the fllor, walls, and ceiling to the scene
        BouncingBallsMain2.WallObj floor1 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor1", "blue", 0, -5f, 0);
        BouncingBallsMain2.WallObj floor2 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor2", "orange", 10f, -5f, 0);
        BouncingBallsMain2.WallObj floor3 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor3", "orange", -10f, -5f, 0);
        //BouncingBallsMain2.WallObj floor4 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor4", "blue", 20f, -5f, 0);

        BouncingBallsMain2.WallObj floor4 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor4", "orange", 0, -15f, 0);
        BouncingBallsMain2.WallObj floor5 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor5", "blue", 10f, -15f, 0);
        BouncingBallsMain2.WallObj floor6 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor6", "blue", -10f, -15f, 0);
        BouncingBallsMain2.WallObj floor7 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "floor7", "orange", 20f, -15f, 0);        
        
        BouncingBallsMain2.WallObj wall1 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall1","pink", -15f, 0, 0);
        BouncingBallsMain2.WallObj wall1_1 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall1_1","pink", -15f, 10f, 0);
        BouncingBallsMain2.WallObj wall1_2 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall1_2","pink", -15f, -10f, 0);
        
        BouncingBallsMain2.WallObj wall2 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall2","orange", 0, 0, -5f);
        BouncingBallsMain2.WallObj wall2_1 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_1", "blue", 10f, 0, -5f);
        BouncingBallsMain2.WallObj wall2_2 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_2", "blue", -10f, 0, -5f);
        BouncingBallsMain2.WallObj wall2_3 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_3", "orange", 20f, 0, -5f);

        BouncingBallsMain2.WallObj wall2_4 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall2_4","blue", 0, 10f, -5f);
        BouncingBallsMain2.WallObj wall2_5 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_5", "orange", 10f, 10f, -5f);
        BouncingBallsMain2.WallObj wall2_6 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_6", "orange", -10f, 10f, -5f);
        BouncingBallsMain2.WallObj wall2_7 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_7", "blue", 20f, 10f, -5f);

        BouncingBallsMain2.WallObj wall2_8 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall2_8","orange", 0, -10f, -5f);
        BouncingBallsMain2.WallObj wall2_9 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_9", "blue", 10f, -10f, -5f);
        BouncingBallsMain2.WallObj wall2_10 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_10", "blue", -10f, -10f, -5f);
        BouncingBallsMain2.WallObj wall2_11 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall2_11", "orange", 20f, -10f, -5f);        
        
        BouncingBallsMain2.WallObj wall3 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall3","pink", 25f, 0, 0);
        BouncingBallsMain2.WallObj wall3_1 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall3_1","pink", 25f, 10f, 0);
        BouncingBallsMain2.WallObj wall3_2 = new BouncingBallsMain2.WallObj(0.1f, 5f, 5f,"wall3_2","pink", 25f, -10f, 0);        
        
        BouncingBallsMain2.WallObj wall4 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall4","orange", 0, 0, 5f);
        BouncingBallsMain2.WallObj wall4_1 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_1", "blue", -10f, 0, 5f);
        BouncingBallsMain2.WallObj wall4_2 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_2", "blue", 10f, 0, 5f);
        BouncingBallsMain2.WallObj wall4_3 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_3", "orange", 20f, 0, 5f);

        BouncingBallsMain2.WallObj wall4_4 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall4_4","blue", 0, 10f, 5f);
        BouncingBallsMain2.WallObj wall4_5 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_5", "orange", -10f, 10f, 5f);
        BouncingBallsMain2.WallObj wall4_6 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_6", "orange", 10f, 10f, 5f);
        BouncingBallsMain2.WallObj wall4_7 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_7", "blue", 20f, 10f, 5f);

        BouncingBallsMain2.WallObj wall4_8 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f,"wall4_8","orange", 0, -10f, 5f);
        BouncingBallsMain2.WallObj wall4_9 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_9", "blue", -10f, -10f, 5f);
        BouncingBallsMain2.WallObj wall4_10 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_10", "blue", 10f, -10f, 5f);
        BouncingBallsMain2.WallObj wall4_11 = new BouncingBallsMain2.WallObj(5f, 5f, 0.1f, "wall4_11", "orange", 20f, -10f, 5f);
        
        BouncingBallsMain2.WallObj roof = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f,"roof","blue",0, 5f, 0);
        //BouncingBallsMain2.WallObj roof_1 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_1", "orange", -10f, 5f, 0);
        BouncingBallsMain2.WallObj roof_1 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_1", "orange", 10f, 5f, 0);
        BouncingBallsMain2.WallObj roof_2 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_2", "blue", 20f, 5f, 0);

        BouncingBallsMain2.WallObj roof_3 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f,"roof_3","orange",0, 15f, 0);
        BouncingBallsMain2.WallObj roof_4 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_4", "blue", -10f, 15f, 0);
        BouncingBallsMain2.WallObj roof_5 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_5", "blue", 10f, 15f, 0);
        BouncingBallsMain2.WallObj roof_6 = new BouncingBallsMain2.WallObj(5f, 0.1f, 5f, "roof_6", "orange", 20f, 15f, 0);        
        
        // Generate the same gravity for all the balls
        Vector3f worldGrav = generateRandomGravity();
        
        // Set the gravity and random velocity to all the balls
        for (int i = 0; i < NUMBALLS; i++) {
            if (randGrav) {
                ball_physics[i].setGravity(generateRandomGravity());
            }
            else {
                ball_physics[i].setGravity(worldGrav);
            }

            estimatedTime = System.currentTimeMillis() - startTime;
            // Set the initial velocity to all the balls
            ball_physics[i].setLinearVelocity(new Vector3f(IVX , IVY , IVZ));
            if (estimatedTime > 500) {
                // Set the random velocity to all the balls
                ball_physics[i].setLinearVelocity(generateRandomVelocity());
            }
        }
        
        // Remove the default text display from the gui.
        guiNode.detachAllChildren();
        setDisplayStatView(false);
        setDisplayFps(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        
        // Add the text for tracking the balls' locations to the gui
        for (int i = 0; i < NUMBALLS; i++) {
            ballDisplays[i] = new BouncingBallsMain2.BallTextDisplay(i + 1, 450, 475 - i*25, 0);
        }
        
        gravText = new BitmapText(guiFont, false);
        gravText.setSize(guiFont.getCharSet().getRenderedSize());
        if (randGrav) {
                 gravText.setText("Separate Gravity");
        }
        else {
                 gravText.setText("Universal Gravity");
        }
             
             gravText.setLocalTranslation(50, 50, 0);
             guiNode.attachChild(gravText);
             
        // Customize the keys
        initKeys();
    }
    
    // Make it so that pressing P will exit the game
    // If P is not used to exit the game, then the
    //  position and velocity data on the playthrough
    //  will not be saved and the text file will be
    //  blank
    // Make it so that pressing G will switch gravity
    // between universal and individual
    public void initKeys() {
        inputManager.addMapping("Exit",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addListener(actionListener, new String[]{"Exit"});
        inputManager.addMapping("Gravity", new KeyTrigger(KeyInput.KEY_G));
        inputManager.addListener(actionListener, new String[]{"Gravity"});
    }
    
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
          if (name.equals("Exit") && !keyPressed) {
              output.close();              
              output2.close();
              app.stop();
          }
          if (name.equals("Gravity") && !keyPressed) {
              randGrav = !randGrav;
          }
        }
    };
    
    // An event handler to detect collisions
    public void collision(PhysicsCollisionEvent event) {
        CollisionResults results = new CollisionResults();
        Ray ray = new Ray(cam.getLocation(), cam.getDirection());
        rootNode.collideWith(ray, results);    // detect a collision
        if (results.size() > 0) {            
            for (int i = 0; i < results.size(); i++) {
                pt = results.getCollision(i).getContactPoint();
                hit = results.getCollision(i).getGeometry().getName();
                // ** Test code beginning
//                output2.println(hit + ": " + pt);
                output2.println(hit + " " + pt);
                // ** Test code end
                System.out.println("----- Collision # " + i + "-----");
                System.out.println("A ball hits " + hit + " at " + pt);
            }            
        }        
    }

   // The update loop for changing the text display in real time
    //  and for calling the method for recording position, 
    //  velocity, and gravity data on the current playthrough to a text file
    @Override
    public void simpleUpdate(float tpf) {
        estimatedTime = System.currentTimeMillis() - startTime;
        long estimatedGravTime = System.currentTimeMillis() - startGravTime;
        // Commented out below
        /* System.out.println(estimatedTime + ", " + startTime); */
        int elapsedTime = 0;
        
        // if one second has elapsed in game
        if(estimatedTime > 1000) {
            // update the gui and record position and velocity data
            //  to the text file
            updatePositionDisplay();   
            for (int i = 0; i < NUMBALLS; i++) {
                output.println("B" + i + ": " + getBallPosString(ball_physics[i]));
            }
            startTime = System.currentTimeMillis();
        }
        // otherwise, only update the gui
        else {
            updatePositionDisplay();
        }
        // if at least 5 seconds has elapsed from the last time, change
        // the gravity. If randGrav true, then each ball has its own
        // gravity. Otherwise, change the world gravity.
        if(estimatedGravTime > 5000) {
            Vector3f worldGrav = generateRandomGravity();
            for (int i = 0; i < NUMBALLS; i++) {
                if (randGrav){
                    ball_physics[i].setGravity(generateRandomGravity());
                }
                else {
                    ball_physics[i].setGravity(worldGrav);
                }
            }
            startGravTime = System.currentTimeMillis();
        }
    }
    // set the text on the gui display
    public void updatePositionDisplay() {        
        for (int i = 0; i < NUMBALLS; i++) {
            ballDisplays[i].setText(ball_physics[i]);
        }
        
        if (randGrav) {
                 gravText.setText("Separate Gravity");
        }
        else {
                 gravText.setText("Universal Gravity");
        }
    }
    
    // generates a random velocity for a ball
    public Vector3f generateRandomVelocity() {
        float velx = velGenerator.nextInt(10);
        int posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            velx *= -1;
        }
        float vely = velGenerator.nextInt(10);
        posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            vely *= -1;
        }
        float velz = velGenerator.nextInt(10);
        posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            velz *= -1;
        }
        return new Vector3f( velx , vely , velz );
    }
    // generates a random gravity for all of the balls
    //  or for each ball separately
    public Vector3f generateRandomGravity() {
        float gravX = gravGenerator.nextInt(3);
        int posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            gravX *= -1;
        }
        float gravY = gravGenerator.nextInt(3);
        posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            gravY *= -1;
        }
        float gravZ = gravGenerator.nextInt(3);
        posNeg = posNegGenerator.nextInt(2);
        if (posNeg == 0) {
            gravZ *= -1;
        }
        return new Vector3f(gravX, gravY, gravZ);
    }
    
    // generates a random position
    public int generateRandomPos() {
        int pos = positionGenerator.nextInt(6);
        return pos;
    }
    
    public String getBallPosString(RigidBodyControl ball_physics) {
        String xPos = String.format("%5.2f", ball_physics.getPhysicsLocation().getX());
        String yPos = String.format("%5.2f", ball_physics.getPhysicsLocation().getY());
        String zPos = String.format("%5.2f", ball_physics.getPhysicsLocation().getZ());
        // ** Test code beginning
//        return "(" + xPos + ", " + yPos + ", " + zPos + ")";
        return xPos + " " + yPos + " " + zPos;
        // ** Test code end
    }
    
    // the sphere sphere object
    public class SphereObj {
        Vector3f position;
        Sphere sphere; 
        Geometry geomSphere; 
        Material mat;
        // constructor method that generates the sphere
        SphereObj(String color, int minX) {
            // the balls' radius are 0.5
            sphere = new Sphere(32, 32, 0.5f); 
            geomSphere = new Geometry("Sphere", sphere); 
            mat = new Material(assetManager,
                   "Common/MatDefs/Misc/Unshaded.j3md");
            if (color.equalsIgnoreCase("yellow")) {
                mat.setColor("Color", ColorRGBA.Yellow);
            } else if (color.equalsIgnoreCase("red")) {
                mat.setColor("Color", ColorRGBA.Red);
                
            } else if (color.equalsIgnoreCase("green")) {
                mat.setColor("Color", ColorRGBA.Green);
            } else {
                mat.setColor("Color", new ColorRGBA(1, 0, 1, 0));
            }
            geomSphere.setMaterial(mat);
            rootNode.attachChild(geomSphere);
            
            int posX = minX + generateRandomPos();
            int posY = -3 + generateRandomPos();
            int posZ = -3 + generateRandomPos(); 
            
            geomSphere.move(posX, posY, posZ);
       
        }
        // method that adds the physics aspects to the sphere
        public void addControl(RigidBodyControl ball_phy) {
            geomSphere.addControl(ball_phy);
        }
    }
    // the wall class
    public class WallObj {
        Vector3f position;
        Box box; 
        Geometry geomWall; 
        Material mat;
        private RigidBodyControl phy;
        // constructor that generates a wall object
        // the parameters are the dimensions of the walls, their color,
        //  and the translations the wall undergoes
        WallObj(float x, float y, float z, String name, String color, float xTrans, float yTrans, float zTrans) {
            box = new Box(Vector3f.ZERO, x, y, z);
            box.scaleTextureCoordinates(new Vector2f(3, 6));
            geomWall = new Geometry(name, box);
            mat = new Material(assetManager,
                   "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
            //set color of wall with alpha channel so can make translucent
            if (color.equalsIgnoreCase("blue")) {
                mat.setColor("Color", new ColorRGBA(0, 0, 1, 0.5f));
            } else if (color.equalsIgnoreCase("pink")) {
                mat.setColor("Color", new ColorRGBA(1f, 0.68f, 0.68f, 0.5f));  
            } else if (color.equalsIgnoreCase("orange")) {
                mat.setColor("Color", new ColorRGBA(.98f, .51f, 0, 0.5f));
            }
            // make walls translucent
            mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
            geomWall.setMaterial(mat);
            geomWall.setQueueBucket(Bucket.Translucent);
            // move wall to position
            geomWall.setLocalTranslation(xTrans, yTrans, zTrans);
            rootNode.attachChild(geomWall);
            phy = new RigidBodyControl(0.0f);
            geomWall.addControl(phy);
            bulletAppState.getPhysicsSpace().add(phy);
            phy.setRestitution(0.5f);
            
        }
        // method that adds physics components to a wall
        public void addControl(RigidBodyControl wall_phy) {
            geomWall.addControl(wall_phy);
        }
    }
    // This class displays the text to the GUI
    public class BallTextDisplay {
        BitmapText ballText;
        BitmapText gravText;
        int ballNumber;
        // This displays the positions of each ball separately on the GUI
        BallTextDisplay(int whichBall, float xPos, float yPos, float zPos) {
             ballText = new BitmapText(guiFont, false);
             ballText.setSize(guiFont.getCharSet().getRenderedSize());
             ballText.setText("B" + whichBall + ": ");
             ballNumber = whichBall;
             ballText.setLocalTranslation(xPos, yPos, zPos);
             guiNode.attachChild(ballText);
        }
        // This displays the positions of each ball separately on the GUI
        public void setText(RigidBodyControl ball_phy) {
           String xPos = String.format("%5.2f", ball_phy.getPhysicsLocation().getX());
           String yPos = String.format("%5.2f", ball_phy.getPhysicsLocation().getY());
           String zPos = String.format("%5.2f", ball_phy.getPhysicsLocation().getZ());
           ballText.setText("B" + ballNumber + ": (" + xPos + ", " + yPos + ", " + zPos + ")");
        }
    }
}
fileBouncingBalls2TestData.pdf

Week 7 Social Anxiety

A social gaming. Like it or hate it, it is one of the major trends in gaming right now. One of the tenants of social gaming is the necessity to play with other people, either to cooperatively complete a goal, or simply to socialize. With social gaming companies like Zynga now worth billions of dollars, other traditional game companies are taking notice. Even with well established franchises, companies are incorporating more social aspects in their games, such as Facebook integration. Do you think that this trend is good or bad? Why?

From the view point of an user, I like the trend. You can share your achievements by competing and collaborating among users via the internet. Also you can play many of social games at any devices such as PCs, smart phones, and feature phones. Moreover, companies can easily receive feedbacks from users and keep improving their games in a short period of time.

From the view point of a social game provider, social games are more competitive and cost so much to develop and operate them compared to console games.

It is harder to make users lock in a specific platform because now users don't have to purchase specialized hardwares. Other than Facebook, in Japan, social game platformers such as GREE, DeNA, and Cyber Agent firmly established their positions, and many social game providers are rapidly growing and went public in recent years. Especially GREE and DeNA are the strongest for feature phones.

The business model was drastically changed. Prices of a game are cheaper than a console game. Players use the most of platforms for free, but pay for items or other options. In other words, companies need to finance initial development costs. In addition, they take care of costs for operating such as service improvement, monitoring, and infrastructure. That's why I think social game industry is a certainly growing but very tough field.

Week 8 Sequels

While networking and multiplayer aspects were not required for your games, they are still a major aspect of game design. Let's look to the future and imagine that there was a companion course which focused on networked multiplayer games: CMSC4XX (425 is already taken...) - Game Design and Development II.

What kind of game would you develop for this course? Would you extend your current design or go for something different? Would you even take the course?

Because I am interested in more infrastructure side such as networking, OS, and middleware, I would like to try it.

Since I learned 3D Java game programming using jMonkeyEngine through this class, I want to make an Android game. On the other hand, with the use of Java Script, you can create both iOS apps and Android apps easily, also a recent trend Node.js allows developers to do server side programming by JS. Also I can use WebGL, so that the language sounds like fun.

Week 8 Final Project

Students will use a popular, freely distributed game platform to design, implement and test a video game using its advanced 3D graphics and physics modeling capabilities.

Requirements:

Using the 3D graphics and associated Physics engine develop an arcade style game that allows a user to fire at various types of targets and be awarded points when the bullet or missile collides with the target. The following functionality is required:

  1. At least 4 types of targets should be displayed in the game. As targets are destroyed they should recreated at another location in the scene automatically.
  2. Each of the targets should be moving in the scene.
  3. At least one of the targets should have gravity/physics applied.
  4. Bullets or missiles should be unlimited.
  5. A Heads-up Display should be provided with a minimum of score totals for each target, total score, high score, and the number of bullets/missiles fired.
  6. High score should be stored in an ASCII file. Optionally, scores can be kept in a database with ability to have initials and scores for top 5 stored and displayed.
  7. Simple directions for running the game should be included on the screen
  8. A game timer should be embedded limiting a game session to 5 minutes or less.
  9. Coding conventions should be followed based on the programming language used.

Deliverables include:

import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Sphere;
import java.util.Random;

/*
 * This class creates shootable objects made of four spheres.
 * The colors and locations of each sphere are randomly generated.
 * @author yujishimojo
 */
public final class Target {

    private BulletAppState bulletAppState;    
    private Node rootNode;
    private Node shootables;
    private AssetManager assetManager;
    public Geometry outlineBall1;
    public Geometry outlineBall2;
    public Geometry outlineBall3;
    public Geometry outlineBall4;
    public RigidBodyControl ballCollision1;
    public RigidBodyControl ballCollision2;
    public RigidBodyControl ballCollision3;
    public RigidBodyControl ballCollision4;;
    
    public Target (AssetManager assetManager, Node rootNode, Node shootables, BulletAppState bulletAppState) {
        
        this.bulletAppState = bulletAppState;
        this.rootNode = rootNode;
        this.shootables = shootables;
        this.assetManager = assetManager;
        rootNode.attachChild(shootables);

        // Creates balls
        createBall1();
        createBall2();
        createBall3();
        createBall4();
    }

    public void createBall1() {
        Random random = new Random();
        Sphere createBall = new Sphere(32, 32, 0.8f);
        outlineBall1 = new Geometry("Ball 1", createBall);
        createBall.setTextureMode(Sphere.TextureMode.Projected);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.randomColor());
        outlineBall1.setMaterial(mat);                
        outlineBall1.setLocalTranslation((random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f));
        shootables.attachChild(outlineBall1);
        ballCollision1 = new RigidBodyControl(1f);
        outlineBall1.addControl(ballCollision1);
        bulletAppState.getPhysicsSpace().add(ballCollision1);
        ballCollision1.setMass(1);
        ballCollision1.setFriction(0);
        ballCollision1.setRestitution(1.0f);
    }

    public void createBall2() {
        Random random = new Random();
        Sphere createBall = new Sphere(32, 32, 0.6f);
        outlineBall2 = new Geometry("Ball 2", createBall);
        createBall.setTextureMode(Sphere.TextureMode.Projected);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.randomColor());
        outlineBall2.setMaterial(mat);
        outlineBall2.setLocalTranslation((random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f));
        shootables.attachChild(outlineBall2);
        ballCollision2 = new RigidBodyControl(1f);
        outlineBall2.addControl(ballCollision2);
        bulletAppState.getPhysicsSpace().add(ballCollision2);
        ballCollision2.setMass(1);
        ballCollision2.setFriction(0);
        ballCollision2.setRestitution(1.0f);
    }

    public void createBall3() {
        Random random = new Random();
        Sphere createBall = new Sphere(32, 32, 0.4f);
        outlineBall3 = new Geometry("Ball 3", createBall);
        createBall.setTextureMode(Sphere.TextureMode.Projected);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.randomColor());
        outlineBall3.setMaterial(mat);
        outlineBall3.setLocalTranslation((random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f));
        shootables.attachChild(outlineBall3);
        ballCollision3 = new RigidBodyControl(1f);
        outlineBall3.addControl(ballCollision3);
        bulletAppState.getPhysicsSpace().add(ballCollision3);
        ballCollision3.setMass(1);
        ballCollision3.setFriction(0);
        ballCollision3.setRestitution(1.0f);
    }

    public void createBall4() {
        Random random = new Random();
        Sphere createBall = new Sphere(32, 32, 0.2f);
        outlineBall4 = new Geometry("Ball 4", createBall);
        createBall.setTextureMode(Sphere.TextureMode.Projected);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.randomColor());
        outlineBall4.setMaterial(mat);
        outlineBall4.setLocalTranslation((random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f), (random.nextFloat() * 2.99f));
        shootables.attachChild(outlineBall4);
        ballCollision4 = new RigidBodyControl(1f);
        outlineBall4.addControl(ballCollision4);
        bulletAppState.getPhysicsSpace().add(ballCollision4);
        ballCollision4.setMass(1);
        ballCollision4.setFriction(0);
        ballCollision4.setRestitution(1.0f);
    }          
}
import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.BufferUtils;

/*
 * This class creates cubic scene objects made of six side of walls. 
 * @author yujishimojo
 */
public class Cube {
    
    private BulletAppState bulletAppState;    
    private Node rootNode;
    private AssetManager assetManager;

    public Cube (AssetManager assetManager, Node rootNode, BulletAppState bulletAppState) {
        
        this.bulletAppState = bulletAppState;
        this.rootNode = rootNode;
        this.assetManager = assetManager;
        
        // Create back side of cube
        createBackCube();
        // Create front side of cube
        createFrontCube();
        // Create right side of cube
        createRightSideCube();
        // Create left side of cube
        createLeftSideCube();
        // Create bottom side of cube
        createBottomSideCube();
        // Create top side of cube
        createTopSideCube();
    }

    private void createBackCube() {

        Mesh back = new Mesh();

        // Back Wall
        Vector3f[] backVertices = new Vector3f[4];
        backVertices[0] = new Vector3f(0, 0, 0);
        backVertices[1] = new Vector3f(9, 0, 0);
        backVertices[2] = new Vector3f(0, 9, 0);
        backVertices[3] = new Vector3f(9, 9, 0);

        // Back Wall
        Vector2f[] backCoord = new Vector2f[4];
        backCoord[0] = new Vector2f(0, 0);
        backCoord[1] = new Vector2f(1, 0);
        backCoord[2] = new Vector2f(0, 1);
        backCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        back.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(backVertices));
        back.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(backCoord));
        back.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        back.updateBound();

        // Create back of cube
        Geometry backGeom = new Geometry("OurMesh", back);
        Material backMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        backMat.setColor("Color", ColorRGBA.White);
        backGeom.setMaterial(backMat);
        backMat.getAdditionalRenderState().setWireframe(true);
        backMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        rootNode.attachChild(backGeom);
        RigidBodyControl backWallCollision = new RigidBodyControl(0f);
        backGeom.addControl(backWallCollision);
        bulletAppState.getPhysicsSpace().add(backWallCollision);
        backWallCollision.setRestitution(0.15f);
        backWallCollision.setFriction(0);
    }

    private void createFrontCube() {

        Mesh front = new Mesh();

        // Front Wall
        Vector3f[] frontVertices = new Vector3f[4];
        frontVertices[0] = new Vector3f(0, 0, 9);
        frontVertices[1] = new Vector3f(9, 0, 9);
        frontVertices[2] = new Vector3f(0, 9, 9);
        frontVertices[3] = new Vector3f(9, 9, 9);

        // Front Wall
        Vector2f[] frontCoord = new Vector2f[4];
        frontCoord[0] = new Vector2f(0, 0);
        frontCoord[1] = new Vector2f(1, 0);
        frontCoord[2] = new Vector2f(0, 1);
        frontCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        front.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(frontVertices));
        front.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(frontCoord));
        front.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        front.updateBound();

        // Create front of cube
        Geometry frontGeom = new Geometry("OurMesh", front);
        Material frontMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        frontGeom.setMaterial(frontMat);
        frontMat.setTransparent(true);
        frontMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.FrontAndBack);
        rootNode.attachChild(frontGeom);
        RigidBodyControl frontWallCollision = new RigidBodyControl(0f);
        frontGeom.addControl(frontWallCollision);
        bulletAppState.getPhysicsSpace().add(frontWallCollision);
        frontWallCollision.setRestitution(0.15f);
        frontWallCollision.setFriction(0);
    }

    private void createRightSideCube() {

        Mesh rightSide = new Mesh();

        Quaternion quatA = new Quaternion();
        quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

        // Right Wall
        Vector3f[] rightSideVertices = new Vector3f[4];
        rightSideVertices[0] = new Vector3f(3, 0, -9);
        rightSideVertices[1] = new Vector3f(12, 0, -9);
        rightSideVertices[2] = new Vector3f(3, 9, -9);
        rightSideVertices[3] = new Vector3f(12, 9, -9);
        Vector3f vectorA = quatA.mult(rightSideVertices[0]);
        Vector3f vectorB = quatA.mult(rightSideVertices[1]);
        Vector3f vectorC = quatA.mult(rightSideVertices[2]);
        Vector3f vectorD = quatA.mult(rightSideVertices[3]);
        Vector3f[] rightSideYes = new Vector3f[4];
        rightSideYes[0] = new Vector3f(vectorA);
        rightSideYes[1] = new Vector3f(vectorB);
        rightSideYes[2] = new Vector3f(vectorC);
        rightSideYes[3] = new Vector3f(vectorD);
        // Right Wall
        Vector2f[] rightSideCoord = new Vector2f[4];
        rightSideCoord[0] = new Vector2f(0, 0);
        rightSideCoord[1] = new Vector2f(1, 0);
        rightSideCoord[2] = new Vector2f(0, 1);
        rightSideCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        rightSide.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(rightSideYes));
        rightSide.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(rightSideCoord));
        rightSide.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        rightSide.updateBound();

        // Create Right of cube
        Geometry rightSideGeom = new Geometry("OurMesh", rightSide);
        rightSideGeom.setLocalTranslation(0, 0, -3);
        Material rightSideMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        rightSideMat.setColor("Color", ColorRGBA.White);
        rightSideGeom.setMaterial(rightSideMat);
        rightSideMat.getAdditionalRenderState().setWireframe(true);
        rightSideMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        RigidBodyControl rightWallCollision = new RigidBodyControl(0f);
        rightSideGeom.addControl(rightWallCollision);
        bulletAppState.getPhysicsSpace().add(rightWallCollision);
        rightWallCollision.setRestitution(0.15f);
        rightWallCollision.setFriction(0);
        rootNode.attachChild(rightSideGeom);
    }

    private void createLeftSideCube() {

        Mesh leftSide = new Mesh();

        Quaternion quatA = new Quaternion();
        quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

        // Left Wall
        Vector3f[] leftSideVertices = new Vector3f[4];
        leftSideVertices[0] = new Vector3f(6, 0, 0);
        leftSideVertices[1] = new Vector3f(-3, 0, 0);
        leftSideVertices[2] = new Vector3f(6, 9, 0);
        leftSideVertices[3] = new Vector3f(-3, 9, 0);
        Vector3f vectorA = quatA.mult(leftSideVertices[0]);
        Vector3f vectorB = quatA.mult(leftSideVertices[1]);
        Vector3f vectorC = quatA.mult(leftSideVertices[2]);
        Vector3f vectorD = quatA.mult(leftSideVertices[3]);
        Vector3f[] leftSideYes = new Vector3f[4];
        leftSideYes[0] = new Vector3f(vectorA);
        leftSideYes[1] = new Vector3f(vectorB);
        leftSideYes[2] = new Vector3f(vectorC);
        leftSideYes[3] = new Vector3f(vectorD);
        // Left Wall
        Vector2f[] leftSideCoord = new Vector2f[4];
        leftSideCoord[0] = new Vector2f(0, 0);
        leftSideCoord[1] = new Vector2f(1, 0);
        leftSideCoord[2] = new Vector2f(0, 1);
        leftSideCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        leftSide.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(leftSideYes));
        leftSide.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(leftSideCoord));
        leftSide.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        leftSide.updateBound();

        // Create Left of cube
        Geometry leftSideGeom = new Geometry("OurMesh", leftSide);
        Material leftSideMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        leftSideMat.setColor("Color", ColorRGBA.White);
        leftSideGeom.setMaterial(leftSideMat);
        leftSideGeom.setLocalTranslation(0, 0, 3);
        leftSideMat.getAdditionalRenderState().setWireframe(true);
        leftSideMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        rootNode.attachChild(leftSideGeom);
        RigidBodyControl leftWallCollision = new RigidBodyControl(0f);
        leftSideGeom.addControl(leftWallCollision);
        bulletAppState.getPhysicsSpace().add(leftWallCollision);
        leftWallCollision.setRestitution(0.15f);
        leftWallCollision.setFriction(0);
    }

    private void createBottomSideCube() {

        Mesh bottomSide = new Mesh();

        Quaternion quatA = new Quaternion();
        quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);

        // Bottom Wall
        Vector3f[] bottomSideVertices = new Vector3f[4];
        bottomSideVertices[0] = new Vector3f(0, 0, 9);
        bottomSideVertices[1] = new Vector3f(0, -9, 9);
        bottomSideVertices[2] = new Vector3f(9, 0, 9);
        bottomSideVertices[3] = new Vector3f(9, -9, 9);
        Vector3f vectorA = quatA.mult(bottomSideVertices[0]);
        Vector3f vectorB = quatA.mult(bottomSideVertices[1]);
        Vector3f vectorC = quatA.mult(bottomSideVertices[2]);
        Vector3f vectorD = quatA.mult(bottomSideVertices[3]);
        Vector3f[] bottomSideYes = new Vector3f[4];
        bottomSideYes[0] = new Vector3f(vectorA);
        bottomSideYes[1] = new Vector3f(vectorB);
        bottomSideYes[2] = new Vector3f(vectorC);
        bottomSideYes[3] = new Vector3f(vectorD);
        // Bottom Wall
        Vector2f[] bottomSideCoord = new Vector2f[4];
        bottomSideCoord[0] = new Vector2f(0, 0);
        bottomSideCoord[1] = new Vector2f(1, 0);
        bottomSideCoord[2] = new Vector2f(0, 1);
        bottomSideCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        bottomSide.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(bottomSideYes));
        bottomSide.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(bottomSideCoord));
        bottomSide.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        bottomSide.updateBound();

        // Create Bottom of cube
        Geometry bottomSideGeom = new Geometry("OurMesh", bottomSide);
        Material bottomSideMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        bottomSideMat.setColor("Color", ColorRGBA.White);
        bottomSideGeom.setMaterial(bottomSideMat);
        bottomSideMat.getAdditionalRenderState().setWireframe(true);
        bottomSideMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        rootNode.attachChild(bottomSideGeom);
        RigidBodyControl bottomWallCollision = new RigidBodyControl(0f);
        bottomSideGeom.addControl(bottomWallCollision);
        bulletAppState.getPhysicsSpace().add(bottomWallCollision);
        bottomWallCollision.setRestitution(0.15f);
        bottomWallCollision.setFriction(0);
    }

    private void createTopSideCube() {

        Mesh topSide = new Mesh();

        Quaternion quatA = new Quaternion();
        quatA.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);

        // Top Wall
        Vector3f[] topSideVertices = new Vector3f[4];
        topSideVertices[0] = new Vector3f(0, 0, 0);
        topSideVertices[1] = new Vector3f(0, -9, 0);
        topSideVertices[2] = new Vector3f(9, 0, 0);
        topSideVertices[3] = new Vector3f(9, -9, 0);
        Vector3f vectorA = quatA.mult(topSideVertices[0]);
        Vector3f vectorB = quatA.mult(topSideVertices[1]);
        Vector3f vectorC = quatA.mult(topSideVertices[2]);
        Vector3f vectorD = quatA.mult(topSideVertices[3]);
        Vector3f[] topSideYes = new Vector3f[4];
        topSideYes[0] = new Vector3f(vectorA);
        topSideYes[1] = new Vector3f(vectorB);
        topSideYes[2] = new Vector3f(vectorC);
        topSideYes[3] = new Vector3f(vectorD);
        // Top Wall
        Vector2f[] topSideCoord = new Vector2f[4];
        topSideCoord[0] = new Vector2f(0, 0);
        topSideCoord[1] = new Vector2f(1, 0);
        topSideCoord[2] = new Vector2f(0, 1);
        topSideCoord[3] = new Vector2f(1, 1);

        // Indexes. We define the order in which mesh should be constructed
        int[] indexes = {2, 0, 1, 1, 3, 2};

        // Setting buffers
        topSide.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(topSideYes));
        topSide.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(topSideCoord));
        topSide.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(indexes));
        topSide.updateBound();

        // Create Top of cube
        Geometry topSideGeom = new Geometry("OurMesh", topSide);
        Material topSideMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        topSideMat.setColor("Color", ColorRGBA.White);
        topSideGeom.setMaterial(topSideMat);
        topSideMat.getAdditionalRenderState().setWireframe(true);
        topSideMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        RigidBodyControl topWallCollision = new RigidBodyControl(0f);
        topSideGeom.addControl(topWallCollision);
        bulletAppState.getPhysicsSpace().add(topWallCollision);
        topWallCollision.setFriction(0);
        topWallCollision.setRestitution(0.15f);
        rootNode.attachChild(topSideGeom);
    }
}
import com.jme3.asset.AssetManager;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.debug.Arrow;
import com.jme3.scene.shape.*;
import com.jme3.texture.Texture;

/*
 * This class creates three types of weapons: a laser beam, a cannon ball, and an arrow.
 * @author yujishimojo
 */
public class Weapon {

    private BulletAppState bulletAppState;
    private Node rootNode;
    private AssetManager assetManager;
    public Geometry geoLaserBeam;
    public Geometry geoCannonBall;
    public Geometry geoArrow;
    public Material matLaserBeam;
    public Material matCannonBall;
    public Material matArrow;
    public RigidBodyControl phyLaserBeam;
    public RigidBodyControl phyCannonBall;
    public RigidBodyControl phyArrow;
    
    int VELOCITY = 100;
    
    public Weapon (AssetManager assetManager, Node rootNode, BulletAppState bulletAppState) {
        this.bulletAppState = bulletAppState;
        this.rootNode = rootNode;
        this.assetManager = assetManager;
    }

    public void makeLaserBeam (Vector3f location, Vector3f direction) {
        Box createLaserBeam = new Box(Vector3f.ZERO, 0.1f, 0.1f, 0.2f);
        geoLaserBeam = new Geometry ("Laser Beam", createLaserBeam);
        matLaserBeam = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        matLaserBeam.setColor("Color", new ColorRGBA(1.0f,0.0f,0.0f,0.0f));
        geoLaserBeam.setMaterial(matLaserBeam);
        rootNode.attachChild(geoLaserBeam);
        geoLaserBeam.setLocalTranslation(location);
        phyLaserBeam = new RigidBodyControl(1f);
        geoLaserBeam.addControl(phyLaserBeam);
        bulletAppState.getPhysicsSpace().add(phyLaserBeam);
        /** Accelerate the physcial ball to shoot it. */
        phyLaserBeam.setLinearVelocity(direction.mult(VELOCITY));
        phyLaserBeam.setGravity(new Vector3f(0, 0, 0));
    }
    
    public void removeLaserBeam () {
        rootNode.detachChild(geoLaserBeam);
    }    
    
    public void makeCannonBall (Vector3f location, Vector3f direction) {
        /** Create a ball geometry. */
        Sphere createCannonBall = new Sphere(32, 32, 0.3f);           
        geoCannonBall = new Geometry("Cannon Ball", createCannonBall);
        createCannonBall.setTextureMode(Sphere.TextureMode.Projected);
        matCannonBall = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        TextureKey key = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
        key.setGenerateMips(true);
        Texture tex = assetManager.loadTexture(key);
        matCannonBall.setTexture("ColorMap", tex);        
        geoCannonBall.setMaterial(matCannonBall);
        rootNode.attachChild(geoCannonBall);
        /** Position the ball  */
        geoCannonBall.setLocalTranslation(location);
        /** Make the ball physcial with a mass > 0.0f */
        phyCannonBall = new RigidBodyControl(1f);
        /** Add physical ball to physics space. */
        geoCannonBall.addControl(phyCannonBall);
        bulletAppState.getPhysicsSpace().add(phyCannonBall);
        /** Accelerate the physcial ball to shoot it. */
        phyCannonBall.setLinearVelocity(direction.mult(VELOCITY));
        phyCannonBall.setGravity(new Vector3f(0, 0, 0));
   }
    
    public void removeCannonBall () {
        rootNode.detachChild(geoCannonBall);
    }
    
    public void makeArrow (Vector3f location, Vector3f direction) {
        Arrow createArrow = new Arrow(direction.mult(1));
        createArrow.setLineWidth(2);        
        geoArrow = new Geometry("arrow", createArrow);
        matArrow = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        matArrow.setColor("Color", new ColorRGBA(0.9f,0.8f,0.0f,0.0f));
        geoArrow.setMaterial(matArrow);
        rootNode.attachChild(geoArrow);
        geoArrow.setLocalTranslation(location);
        phyArrow = new RigidBodyControl(1f);
        geoArrow.addControl(phyArrow);
        bulletAppState.getPhysicsSpace().add(phyArrow);
        phyArrow.setLinearVelocity(direction.mult(VELOCITY));
        phyArrow.setGravity(new Vector3f(0, 0, 0));
    }
       
    public void removeArrow () {
        rootNode.detachChild(geoArrow);
    } 
}
import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.BulletAppState;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import java.util.Random;
import java.util.Timer;
import javax.swing.JOptionPane;

/*
 * This is the main class of the project.
 * The functions are: text display on the screen, file export,
 * and event handlers for key presses and collision detections.
 * @author yujishimojo
 */
public class ShootingObjectsMain extends SimpleApplication {
    
    private java.io.PrintWriter output;
    private BulletAppState bulletAppState;
    private Cube createCube;
    private Target target;
    private Weapon weapon;
    private int count = 0;
    Node shootables;
    Timer timeClone;
    private int gameTimeCount = 0;
    private float shotsFired = 0;
    private float shotsHit = 0;
    private int destroyedTarget = 0;
    private float shotAccuracy = 100;
    private int points = 0;
    int weaponState = 0;
    BitmapText timePlayed;
    BitmapText bulletsFired;
    BitmapText bulletsHit;
    BitmapText accuracy;
    BitmapText targetsDestroyed;
    BitmapText pointSum;
    BitmapText selectedWeapon;
    private int ball1 = 0;
    private int ball2 = 0;
    private int ball3 = 0;
    private int ball4 = 0;
    private AudioNode laserBeamAudio;
    private AudioNode cannonBallAudio;
    private AudioNode arrowAudio;
    private AudioNode objectExplodeAudio;

    public static void main(String[] args) {
        ShootingObjectsMain shootingObjectsMain = new ShootingObjectsMain();
        // Starts the game
        shootingObjectsMain.start();
    }

    @Override
    public void simpleInitApp() {
        // Declares string fileName to be used in if statement
        String fileName;

        // Declares java.io.File file 
        java.io.File file;

        // Configure cam to look at scene
        cam.setLocation(new Vector3f(4.3f, 4.8f, 25f));
        cam.lookAt(new Vector3f(4.5f, 4.5f, 0), Vector3f.UNIT_Y);
        flyCam.setMoveSpeed(0);
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        bulletAppState.getPhysicsSpace().setAccuracy(0.005f);
        bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0f, 19f, 1f));

        // Set up GUI
        initCrosshair();
        // Set up shooter
        initKeys();
        // Set up audio
        initAudio();
        
        // Create shootables node 
        shootables = new Node("shootables");

        // Creates the first cube
        createCube = new Cube(assetManager, rootNode, bulletAppState);
        
        // Creates the first cube
        target = new Target(assetManager, rootNode, shootables, bulletAppState);
        
        // Instantiate the Weapon class
        weapon = new Weapon(assetManager, rootNode, bulletAppState);

        // User determines file name
        fileName = JOptionPane.showInputDialog(null, "What would you like the name of your file to be?", "Please name your file", JOptionPane.QUESTION_MESSAGE);

        // Creates new file using new name
        file = new java.io.File(fileName + "_ShootingObjectsTest.txt");
        
        // Instatiates geometries for weapons to avoid NullPointERexception
        weapon.makeLaserBeam(cam.getLocation(), cam.getDirection());
        weapon.makeCannonBall(cam.getLocation(), cam.getDirection());
        weapon.makeArrow(cam.getLocation(), cam.getDirection());
        
        try {
            // Create a Scanner for the file
            output = new java.io.PrintWriter(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        output.println("Bullets Fired: " + shotsFired);
        output.println("Bullets Hit: " + shotsHit);
        output.println("Accuracy: " + shotAccuracy + "%");
        output.println("Targets Destroyed: " + destroyedTarget);
        output.println("Points: " + points);
        output.flush();
        output.close();
        System.exit(0);
    }

    @Override
    public void simpleUpdate(float tpf) {
        // Update selected weapon
        updateWeaponDisplay();
        
        // Update vector position to text file
        if (getTimer().getTimeInSeconds() >= 1) {
            getTimer().reset();
            count++;
            gameTimeCount++;
            updateTime();
            
            // Clear weapons to display one by one
            weapon.removeLaserBeam();
            weapon.removeCannonBall();
            weapon.removeArrow();  
            
            // Gravity changes every 6 seconds.
            if (count > 5) {
                Random random = new Random();
                Vector3f setGravity = new Vector3f((random.nextFloat() * 60f - 30f), (random.nextFloat() * 60f - 30f), (random.nextFloat() * 60f - 30f));
                bulletAppState.getPhysicsSpace().setGravity(setGravity);
                System.out.println("Gravity Location" + setGravity);
                System.out.println("5 seconds");
                bulletAppState.getPhysicsSpace().applyGravity();
                count = 0;
            }

            // Stops game automatically
            if (gameTimeCount >= 120) {
                JOptionPane.showMessageDialog(null, "Two minutes is up! Program will shut down.");
                // Shows the final results
                JOptionPane.showMessageDialog(null,
                        "Bullets Fired: " + shotsFired + "\n"
                        + "Bullets Hit: " + shotsHit + "\n"
                        + "Accuracy: " + shotAccuracy + "%" + "\n"
                        + "Targets Destroyed: " + destroyedTarget + "\n"
                        + "Points: " + points,
                        "Results:", JOptionPane.INFORMATION_MESSAGE);
                stop();
            }
        }
    }
    
    // Creates key to shoot
    private void initKeys() {
        inputManager.addMapping("Shoot",
                new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar
                new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click
        inputManager.addListener(actionListener, "Shoot");
        
        inputManager.addMapping("Laser", new KeyTrigger(KeyInput.KEY_L));
        inputManager.addListener(actionListener, new String[]{"Laser"});

        inputManager.addMapping("Cannon", new KeyTrigger(KeyInput.KEY_C));
        inputManager.addListener(actionListener, new String[]{"Cannon"});

        inputManager.addMapping("Arrow", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addListener(actionListener, new String[]{"Arrow"});
    }
    
    // Create shooting action listener
    private ActionListener actionListener = new ActionListener() {
        private int ws; // A local variable to manage weapon state
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Shoot") && !keyPressed) {

                // Clear the weapon
                if (ws == 0) {
                    weapon.removeLaserBeam();
                } else if (ws == 1) {
                    weapon.removeCannonBall();    
                } else if (ws == 2) {
                    weapon.removeArrow();            
                }            

                // Makes the weapon
                if (ws == 0) {
                    weapon.makeLaserBeam(cam.getLocation(), cam.getDirection());
                } else if (ws == 1) {
                    weapon.makeCannonBall(cam.getLocation(), cam.getDirection());    
                } else if (ws == 2) {
                    weapon.makeArrow(cam.getLocation(), cam.getDirection());
                }            

                // This is for removing the weapon for certain
                long startTime = System.currentTimeMillis();

                // Plays shooting sound
                if (ws == 0) {
                    laserBeamAudio.playInstance();
                } else if (ws == 1) {
                    cannonBallAudio.playInstance();    
                } else if (ws == 2) {
                    arrowAudio.playInstance();
                }

                // Reset results list.
                CollisionResults results = new CollisionResults();

                // Aim the ray from cam loc to cam direction.
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());

                // Collect intersections between Ray and Shootables in results list.
                shootables.collideWith(ray, results);

                // If results is 0 then console prints you missed and fixes accuracy
                if (results.size() > 0) {
                    for (int i = 0; i < results.size(); i++) {
                        // Outputs results for all collisions
                        float dist = results.getCollision(i).getDistance();
                        Vector3f pt = results.getCollision(i).getContactPoint();
                        String hit = results.getCollision(i).getGeometry().getName();
                        // Removes the weapon within 0.01s
                        if (System.currentTimeMillis() - startTime > 1) {
                            if (ws == 0) {
                                weapon.removeLaserBeam();
                            } else if (ws == 1) {
                                weapon.removeCannonBall();    
                            } else if (ws == 2) {
                                weapon.removeArrow();
                            }                            
                            startTime = 0;
                        }
                        createNewCubes(hit);                                        
                        System.out.println("* Collision #" + i);
                        System.out.println("  You shot " + hit + " at " + pt + ", " + dist + " wu away.");
                        shotsHit++;
                        break;
                    }
                } else {
                    System.out.println("You missed!");  
                }

                // Update shots fired on GUI
                shotsFired++;
                updateShotsFired();
            }
            // Changes the value of the weapon state
            if (name.equals("Laser") && !keyPressed) {
                ws = 0;
                weaponState = 0;
            } else if (name.equals("Cannon") && !keyPressed) {
                ws = 1;
                weaponState = 1;
            } else if (name.equals("Arrow") && !keyPressed) {
                ws = 2;
                weaponState = 2;
            }
        }
    };

    // Create audio to attach to scene
    private void initAudio() {
        laserBeamAudio = new AudioNode(assetManager, "Sounds/laser.wav", false);
        laserBeamAudio.setLooping(false);
        laserBeamAudio.setVolume(2);
        rootNode.attachChild(laserBeamAudio);
        
        cannonBallAudio = new AudioNode(assetManager, "Sounds/stoning.wav", false);
        cannonBallAudio.setLooping(false);
        cannonBallAudio.setVolume(1);
        rootNode.attachChild(cannonBallAudio);
        
        arrowAudio = new AudioNode(assetManager, "Sounds/arrow.wav", false);
        arrowAudio.setLooping(false);
        arrowAudio.setVolume(2);
        rootNode.attachChild(arrowAudio);
        
        objectExplodeAudio = new AudioNode(assetManager, "Sounds/objectExplode.wav", false);
        objectExplodeAudio.setLooping(false);
        objectExplodeAudio.setVolume(4);
        rootNode.attachChild(objectExplodeAudio);
    }
    
    // Create shooting action attached to left mouse click
    private void initCrosshair() {
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");

        // Creates Crosshair
        BitmapText ch = new BitmapText(guiFont, false);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+"); // crosshairs
        ch.setLocalTranslation( // center
                settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
                settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
        guiNode.attachChild(ch);

        // Creates Time Played Text
        timePlayed = new BitmapText(guiFont, false);
        timePlayed.setSize(guiFont.getCharSet().getRenderedSize());
        timePlayed.setText("Time: " + gameTimeCount + " seconds");
        timePlayed.setLocalTranslation(0, 475, 0);
        guiNode.attachChild(timePlayed);

        // Creates Number of Bullets Fired Text
        bulletsFired = new BitmapText(guiFont, false);
        bulletsFired.setSize(guiFont.getCharSet().getRenderedSize());
        bulletsFired.setText("Bullets Fired: " + shotsFired);
        bulletsFired.setLocalTranslation(0, 450, 0);
        guiNode.attachChild(bulletsFired);

        // Creates Number of Bullets Hit Text
        bulletsHit = new BitmapText(guiFont, false);
        bulletsHit.setSize(guiFont.getCharSet().getRenderedSize());
        bulletsHit.setText("Bullets Hit: " + shotsHit);
        bulletsHit.setLocalTranslation(0, 425, 0);
        guiNode.attachChild(bulletsHit);

        // Creates Accuracy Text
        accuracy = new BitmapText(guiFont, false);
        accuracy.setSize(guiFont.getCharSet().getRenderedSize());
        accuracy.setText("Accuracy: " + shotAccuracy + "%");
        accuracy.setLocalTranslation(0, 400, 0);
        guiNode.attachChild(accuracy);

        // Creates Number of Targets Destroyed Text
        targetsDestroyed = new BitmapText(guiFont, false);
        targetsDestroyed.setSize(guiFont.getCharSet().getRenderedSize());
        targetsDestroyed.setText("Targets Destroyed: " + destroyedTarget);
        targetsDestroyed.setLocalTranslation(0, 375, 0);
        guiNode.attachChild(targetsDestroyed);

        // Creates Number of Targets Destroyed Text
        pointSum = new BitmapText(guiFont, false);
        pointSum.setSize(guiFont.getCharSet().getRenderedSize());
        pointSum.setText("Points: " + points);
        pointSum.setLocalTranslation(0, 350, 0);
        guiNode.attachChild(pointSum);
        
        // Creates
        selectedWeapon = new BitmapText(guiFont, false);
        selectedWeapon.setSize(guiFont.getCharSet().getRenderedSize());
        selectedWeapon.setText("Laser Beam"); // default weapon
        selectedWeapon.setLocalTranslation(540, 475, 0);
        guiNode.attachChild(selectedWeapon);        
    }

    private void updateTime() {
        timePlayed.setText("Time: " + gameTimeCount + " seconds");
    }

    private void updateShotsFired() {
        shotAccuracy = (shotsHit / shotsFired) * 100;
        bulletsFired.setText("Bullets Fired: " + shotsFired);
        bulletsHit.setText("Bullets Hit: " + shotsHit);
        accuracy.setText("Accuracy: " + shotAccuracy + "%");
        targetsDestroyed.setText("Targets Destroyed: " + destroyedTarget);
        pointSum.setText("Points: " + points);
    }
    
    // Set the text on the gui display
    public void updateWeaponDisplay() {
        if (weaponState == 0) {
            selectedWeapon.setText("Laser Beam");
        } else if (weaponState == 1) {
            selectedWeapon.setText("Cannon Ball");        
        } else {
            selectedWeapon.setText("Arrow");        
        }
    }

    private void createNewCubes(String hit) {

        if (hit.equals("Ball 1")) {
            ball1++;
            if (ball1 == 1) {
                shootables.detachChildNamed(hit);
                objectExplodeAudio.playInstance();
                target.createBall1();
                points = points + 2;
                destroyedTarget++;
                ball1 = 0;
            }
        } else if (hit.equals("Ball 2")) {
            ball2++;
            if (ball2 == 2) {
                shootables.detachChildNamed(hit);
                objectExplodeAudio.playInstance();
                target.createBall2();
                points = points + 6;
                destroyedTarget++;
                ball2 = 0;
            }
        } else if (hit.equals("Ball 3")) {
            ball3++;
            if (ball3 == 3) {
                shootables.detachChildNamed(hit);
                objectExplodeAudio.playInstance();
                target.createBall3();
                points = points + 10;
                destroyedTarget++;
                ball3 = 0;
            }
        } else if (hit.equals("Ball 4")) {
            ball4++;
            if (ball4 == 4) {
                shootables.detachChildNamed(hit);
                objectExplodeAudio.playInstance();
                target.createBall4();
                points = points + 16;
                destroyedTarget++;
                ball4 = 0;
            }
        }
    }    
}
fileCMSC325_FinalProject.pdf

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS