- 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);
}
}
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());
}
System.out.println(speed);
if (speed <= 10.0f)
notifyController("stopped");
@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:
- Create a scoreboard by extending TextModel.
- The scoreboard needs some attributes:
private int score = 0;
private String message;
@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);
}
@Override
protected void onOutOfBounds(OutOfBoundsEvent[] events) {
for (OutOfBoundsEvent e : events) {
ScreenBoundary sb = e.getBoundary();
// more here
if (sb.getEdge() == Direction.South)
sboard.increment();
}
}
@Override
protected void updateGameState() {
if (sboard.getScore() >= 10) {
sboard.modifyMessage("Game Over!");
gameOver = true;
}
}
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.
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”.
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”.
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.