Lesson 3: Gravity & Collisions

Learning Objectives:
  • Explain how the game engine simulates gravity.
  • Use the Physics methods: setCoefficientOfRestitution, setRotation, and rebound.
  • Make sprites rebound off each other and screen edges.
  • Handle scoring in the updateGameState callback.
  • Make sprites bounce off barriers using the onBlocked callback.

How can we make sprites behave like objects do in the physical world?

The game engine's Physics class lets us expose sprites to gravity, make them spin, and make them bounce off the walls and each other with varying degrees of elasticity. To accomplish these effects, the game engine uses velocity, acceleration, mass, restitution, and the law of conservation of momentum. Get familiar with these concepts in the simulations below.

Simulation 1 - Velocity and Acceleration

Which is velocity and which is acceleration? The green or the blue?

Simulation by PhET Interactive Simulations, University of Colorado Boulder, licensed under CC-BY-4.0 (https://phet.colorado.edu).

In our games, we can use a downward (or Y) acceleration to simulate gravity.

What happens when two sprites collide?

The game engine's Physics.rebound method calculates the new velocities based on the masses, velocities, and coefficients of restitution (bounciness) of each. Momentum is conserved during the collision. Experiment with these concepts in the next simulation.

Simulation 2 - Mass, Elasticity and Momentum

Simulation by PhET Interactive Simulations, University of Colorado Boulder, licensed under CC-BY-4.0 (https://phet.colorado.edu).

Exercises

Exercise 3A_SoccerBall


Make a soccer ball appear on the screen and respond to the left, right, up and down arrow keys (and WASD keys) to move it around.

  • Change the ball's X or Y velocity depending on the key pressed.
  • This situation is different from single key presses like pressing Escape to exit the game. For single strokes, we use a KeyListener.
  • This situation involves processing multiple key presses during a game. For example, the user could press the left and up arrow simultaneously to move the ball. This requires the game engine's MultiKeyListener which keeps track of all the strokes. We use the onKeysPolled method for this:
  •   @Override
      protected void onKeysPolled(int[] keyCodes) {
                
        for (int code : keyCodes) {
          switch(code) {
            case KeyEvent.VK_W:
            case KeyEvent.VK_UP:
              // change the ball's X velocity here
              break;
                      
            case ?
              // add other cases here
                      
            default: // this is needed to make the ball stop
                     // when no keys are pressed
              ball.setXVelocity(0);
              ball.setYVelocity(0);
             }
          }
        }

Read about setXVelocity, setYVelocity, KeyEvent, and MultiKeyListener.

Exercise 3B_GravityBall


Make a soccer ball that is acted upon by gravity (a downward acceleration). Your soccer ball should also bounce off the walls and floor as a ball would.

  • Set the coefficient of restitution for your ball in setAppearance().
  • Set the ball's X and Y velocities and Y acceleration in the controller when you add the ball entity.
  • Use setRotationAngle to add spin to the ball in your sprite model's updateParameters method.
  • Use the Physics.rebound method in the onOutOfBounds method to make your ball rebound when it collides with a wall:
  •  @Override
      protected void onOutOfBounds(OutOfBoundsEvent[] events) {
    		for (OutOfBoundsEvent e : events) {
    			ScreenBoundary sb = e.getBoundary();
    			EntityModel em = e.getEntity();
    			Physics.rebound(em, sb);
    		}
      }
  • Experiment until you get the behavior you want.

Read about setCoefficientOfRestitution, setRotationAngle, ScreenBoundary, and Physics.

What is happening when the ball reaches the bottom of the screen? Read about it in the Book. We'll handle this situation in the next exercise.

Exercise 3C_ReboundingBalls


Make a single soccer ball appear each time the mouse is clicked, make the balls behave as in exercise 3B, and make them rebound from each other using Physics when they collide. Make the game controller write a message to the console each time the ball hits the South wall.

  • Add a mouse listener.
  • Add the code to generate a new ball:
  • @Override
    public void mouseReleased(MouseEvent e) {
      addBall(e.getX(), e.getY());
    }
  • In your updateParameters method, handle the "stopped" balls, those that reach the bottom of the screen with their velocity approaching 0 and still having acceleration downward. Use notifyController to send a message about the situation.
  • System.out.println(speed);
    if (speed <= 10.0f)
      notifyController("stopped");
    
  • In your controller, check for the message, print a message to the console, and dispose of the ball.
  • @Override
    protected void onMessagesPolled(MessageEvent[] events) {
    	for (MessageEvent me : events) {
    		String msg = me.getDescription();
    		EntityModel em = me.getSender();
    		if (msg.equalsIgnoreCase("stopped")) {
    			System.out.println("The ball has stopped");
    			em.dispose();
    		}
    	}
    }
    

If you want, you can show the Collision Bounds width and height (hit box width and height) for each ball using showCollisionBounds. Later, it may be useful to adjust this.

Read about MouseListener, Physics, .dispose, EntityModel, notifyController, and onMessagesPolled.

Exercise 3D_Scoreboard


Add a scoreboard to your game, initialized to “0”. Each time a ball hits the south wall, increment the score. When the score reaches 10, change the score display to “GAME OVER”.

  • Here's a class diagram containing the classes you'll need for the exercise:
  • Class diagram
  • Create a scoreboard by extending TextModel.
  • The scoreboard needs some attributes:
  • private int score = 0;
    private String message;
    
  • Set the scoreboard's appearance (be creative with this if you want):
  • @Override
    protected void setAppearance() {
      Font font = new Font("Courier New", Font.BOLD|Font.PLAIN, 40);
      message = String.format("Score: %03d", score);
      setView(message, font, Color.YELLOW);
    } 
    
  • Increment the score in onOutOfBounds:
  • @Override
    	protected void onOutOfBounds(OutOfBoundsEvent[] events) {
    		for (OutOfBoundsEvent e : events) {
    			ScreenBoundary sb = e.getBoundary();
    			// more here
    			if (sb.getEdge() == Direction.South)
    				sboard.increment(); 
    		}
    	}
    
  • You can use the TextModel's modifyMessage method to change the message contained in the scoreboard text entity.
  • Code updateGameState() to check for the end of the game:
  • @Override
    protected void updateGameState() {
    	if (sboard.getScore() >= 10) {
    		sboard.modifyMessage("Game Over!");
    		gameOver = true;
    	}
    }
    
  • Use setGhost(true) for the scoreboard since we don't want it involved in collision processing.

Read about TextModel, ScreenBoundary, and updateGameState.

Exercise 3E_Barrier


Put a sloping barrier in the window and call the .rebound() method in onBlocked() when a soccer ball hits the barrier.

Soccer balls boucing off barrier slope

If you would like, go back and use a BarrierModel to fix the "stopped" balls in 3C.

Read about BarrierModel.

Exercise 3F_FlippedAirplane


Make an airplane that moves left and right to arrow keys, flipping itself to face the direction it’s going. The spacebar should make it go up.

Read about setFlipped.

Challenges

Challenge 3G_JumpingSprite


Create a game where a green man (greenman-4.png) can move left and right with the arrow keys. Make the man able to jump using the spacebar giving him the acceleration of gravity. Create a bee that appears at the right edge of the screen, moves to the left, and then wraps around to appear at the right again. Use a SceneryModel (ufoscene-1.png) to create a static background for the game. Each time the bee crosses the screen and the man successfully avoids getting stung by jumping over it, a point is scored. Make a scoreboard that shows the total points. When three bee stings have been avoided, display “Game Over”.

Static: Green man jumping over a bee
Animated: Green man jumping over a bee

Tip #1. With most games, you'll have to tweak the velocities, acceleration, and sprite hit boxes. Use showCollisionBounds and setCollisionBounds to experiment.

Tip #2. For this challenge, you may run into a situation where a BarrierModel will come in handy to solve your problem.

Challenge 3H_BeachPailGame


Make a pail move left and right across the bottom of the screen using keystrokes. The game should begin by automatically releasing a single beach ball from the top of the screen. Move the pail left and right to collect balls. When the ball comes in contact with the pail, the ball should disappear, the score should be incremented, and another ball should be released. When 10 balls have been “collected,” display “Game Over”.

Static: Beach pail collecting flying balls
Animated: Beach pail collecting flying balls

Tip: If you have objects created during the game loop, don’t do it in enlistEntities. enlistEntities is done once at the beginning for objects that are present at the beginning of the game.

For all exercises and challenges, try to incorporate a few features of your own. Get creative and make it unique!

Challenge 3I_ClassDiagram


Draw a class diagram for one of your games (JumpingSprite or BeachPail). Include classes for GameController, SpriteModel, TextModel, your controller, and scoreboard. Depending on the game, include your classes for the jumping man and bee, or the beach pail and ball. Use pencil and paper or a software tool like UMLet.

Draw it online

More

Top