Download presentation
Presentation is loading. Please wait.
1
Chapter 7 – Collision Detection: Asteroids
2
The Asteroids Game
3
We handle a “space” input and call the fire() method.
How Are Bullets Fired? We handle a “space” input and call the fire() method.
4
How Are Asteroids Created?
We call the addAsteroids() method in the Space constructor
5
What does an Explosion do?
Placing an Explosion object creates the Explosion Visual and makes an Explosion Sound.
6
What does a Proton Wave do?
Placing a ProtonWave object has no effect except a ProtonWave visual.
7
What does the Counter do?
Apparently nothing No effect except a ProtonWave visual.
8
What is currently NOT coded?
When experimenting with the current scenario, you will notice that some fundamental functionality is missing. The rocket does not move. It cannot be turned, nor can it be moved forward. Nothing happens when an asteroid collides with the rocket. It flies straight through it, instead of damaging the rocket. As a result of this, you cannot lose. The game never ends, and a final score is never displayed. The ScoreBoard, Explosion, and ProtonWave classes, which we can see in the class diagram, do not seem to feature in the scenario.
9
What should be coded? Controls for the Rocket
Collision: Asteroid vs. Rocket Explosion Logic ScoreBoard/Counter Logic ProtonWave Logic
10
Turning the Rocket We want to make the rocket turn left or right using the left and right arrow keys.
11
The method checkKeys handles keyboard input
Handling Key Presses /* * Check whether there are any key pressed and react to them. */ private void checkKeys() { if (Greenfoot.isKeyDown("space")) fire(); } The method checkKeys handles keyboard input
12
Actor Class Methods
13
Turning the Rocket if (Greenfoot.isKeyDown("left"))
setRotation(getRotation() - 5); if (Greenfoot.isKeyDown("right")) setRotation(getRotation() + 5); Left: Negative Degrees Right: Positive Degrees
14
If left arrow key is down rotate left 5 degrees
Turning the Rocket /* * Check whether there are any key pressed and react to them. */ private void checkKeys() { if (Greenfoot.isKeyDown ("space")) fire(); } if (Greenfoot.isKeyDown ("left")) setRotation (getRotation() - 5); If left arrow key is down rotate left 5 degrees
15
Turning the Rocket
16
If right arrow key is down rotate right 5 degrees
Turning the Rocket /* * Check whether there are any key pressed and react to them. */ private void checkKeys() { if (Greenfoot.isKeyDown("space")) fire(); } if (Greenfoot.isKeyDown ("left")) setRotation (getRotation() - 5); if (Greenfoot.isKeyDown ("right")) setRotation (getRotation() + 5); If right arrow key is down rotate right 5 degrees
17
Turning the Rocket
18
Flying Forward Our Rocket class is a subclass of the SmoothMover class. This means that it holds a movement vector that determines its movement and that it has a move () method that makes it move according to this vector
19
Flying Forward The rocket does not move because we did not specify a movement vector yet.
20
Add an initial movement to the rocket constructor.
Flying Forward /* * Initialize this rocket. */ public Rocket() { reloadDelayCount = 5; addForce ( new Vector (13, 0.3)); //initially slow drifting } Add an initial movement to the rocket constructor.
21
Flying Forward /* * Do what a rocket's gotta do. (Which is: mostly
* flying about, and turning, * accelerating and shooting when the right keys are pressed.) */ public void act() { move (); checkKeys(); reloadDelayCount++; } Add the move () method
22
The rocket drifts slowly toward the right of the World
Flying Forward The rocket drifts slowly toward the right of the World
23
Ignite the Engines Ignite Algorithm
1) If “up” arrow key is pressed then 1.1) change image to show engine fire 1.2) add movement 2) If “up” arrow key is released then 2.1) change back to normal rocket image
24
Define a stub method for ignite
Ignite the Engines Define a stub method for ignite /* * Go with thrust on */ private void ignite (boolean boosterOn) { }
25
Ignite the Engines A boolean parameter /* * Go with thrust on */
private void ignite (boolean boosterOn) { if (boosterOn) setImage (rocketWithThrust); addForce (new Vector (getRotation(), 0.3)); } else setImage (rocket);
26
Ignite the Engines /* * Check whether there are any key pressed and react to them. */ private void checkKeys() { if (Greenfoot.isKeyDown("space")) fire(); ignite (Greenfoot.isKeyDown ("up")); if (Greenfoot.isKeyDown("left")) setRotation(getRotation() - 5); if (Greenfoot.isKeyDown("right")) setRotation(getRotation() + 5 } Add a call to ignite
27
Flying Forward
28
Colliding with Asteroids
Colliding Algorithm 1) If we have collided with an asteroid then 1.1) remove the rocket from the world 1.2) place an explosion into the world 1.3) show final score (game over)
29
Colliding with Asteroids
Define a stub method for checkCollision /* * Check for a collision with an Asteroid */ private void checkCollision() { }
30
Colliding with Asteroids
/* * Do what a rocket's gotta do. (Which is: mostly flying about, and turning, * accelerating and shooting when the right keys are pressed.) */ public void act() { move (); checkKeys(); checkCollision(); reloadDelayCount++; } Make a call to checkCollision from the Rocket Act method
31
Intersecting Objects Bounding Box Visible Image Intersection
32
Intersecting Objects Methods
List getIntersectingObjects (Class cls) Actor getOneIntersectingObject (Class cls) Intersection Bounding Boxes Visible Image
33
getOneIntersectingObject()
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); } Even though we can specify what class we are looking for, the method always returns an Actor object
34
getOneIntersectingObject()
/* * Check for a collision with an Asteroid */ private void checkCollision() { Asteroid a = (Asteroid) getOneIntersectingObject (Asteroid.class); } However, we can re-interpret the returned Actor to a more specific class via a process called “Casting”. More on that later.
35
getOneIntersectingObject()
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) } We have a collision if: a is not “null”, meaning if the getOneIntersectingObject has returned something
36
Colliding with Asteroids
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) World space = getWorld(); space.removeObject (this); space.addObject (new Explosion(), getX(), getY()); } Adding the Explosion and removing the Rocket has to be done via World-methods.
37
Colliding with Asteroids
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) World space = getWorld(); space.addObject (new Explosion(), getX(), getY()); space.removeObject (this); } The sequence of commands is very important when removing objects!
38
Colliding with Asteroids
39
Game Over After a collision, we want to show a ScoreBoard object in the middle of the Level
40
Game Over Method in the Space class
/* * This method is called when the game is over to display the final score. */ public void gameOver() { // TODO: show the score board here. Currently missing. }
41
ScoreBoard /* * Create a score board with dummy result for testing. */
public ScoreBoard() { this(100); } * Create a score board for the final result. public ScoreBoard(int score) makeImage("Game Over", "Score: ", score); The ScoreBoard class has two constructors, a Default Constructor and a second Constructor with parameters
42
Game Over /* * This method is called when the game is over to display the final score. */ public void gameOver() { addObject(new ScoreBoard(999), getWidth()/2, getHeight()/2); } Making sure that the Game Over screen appears right in the middle of the screen.
43
Game Over
44
Colliding with Asteroids II
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) World space = getWorld(); space.addObject (new Explosion(), getX(), getY()); space.removeObject (this); space.gameOver(); } Why does this code produce an error?
45
Colliding with Asteroids II
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) World space = getWorld(); space.addObject (new Explosion(), getX(), getY()); space.removeObject (this); space.gameOver(); } The gameOver() method is a method of the Space class. Our Compiler cannot find it in the World class. Thus, we cannot call it from objects of type World!
46
Colliding with Asteroids II
/* * Check for a collision with an Asteroid */ private void checkCollision() { Actor a = getOneIntersectingObject (Asteroid.class); if (a != null) Space space = (Space) getWorld(); space.addObject (new Explosion(), getX(), getY()); space.removeObject (this); space.gameOver(); } We can use Casting to specify that the object returned by the getWorld() method is not only a World object, but actually an object of the more specific Subclass Space. This does NOT change the actual type of the object, it only changes the information available to our program.
47
Painting Stars The Asteroid Scenario does not use an image file for the background. Instead, the background image is generated directly in the Constructor.
48
The Background is Created by These Three Statements.
Painting Stars The Background is Created by These Three Statements.
49
Code to Create the Background is Commented Out
Painting Stars Code to Create the Background is Commented Out
50
No Background
51
The GreenfootImage Class
Draw Line Draw Oval Draw Rectangle Fill Oval
52
Point Coordinates in Greenfoot
Each point of a World object can be identified using a Cartesian coordinate system The origin of the coordinate system (i.e. the point (0,0) ) is in the top-left corner
53
Drawing A Line drawLine(10, 20, 150, 45); or
54
Drawing A Rectangle drawRect (50, 20, 100, 40);
55
Drawing An Oval drawOval (175, 20, 50, 80);
56
Filling an Oval fillOval (175, 20, 50, 80);
57
Method to create stars /*
* Method to create stars. The integer number is how many. */ private void createStars(int number) { GreenfootImage background = getBackground(); for (int i = 0; i < number; i++) { } We want to draw a set amount of stars. This means that our new methods requires a parameter.
58
Method to create stars /*
* Method to create stars. The integer number is how many. */ private void createStars(int number) { GreenfootImage background = getBackground(); for (int i = 0; i < number; i++) { int x = Greenfoot.getRandomNumber( getWidth() ); int y = Greenfoot.getRandomNumber( getHeight() ); background.setColor (new Color(255, 255, 255)); background.fillOval(x, y, 2, 2); } Note the sequencing: We first specify the color, then what we want to draw in said color. Also note how we apply the operations to a specific image, using dot notation.
59
Calling the createStars methods in the Space constructor
Painting Stars Calling the createStars methods in the Space constructor
60
Painting Stars
61
Painting Stars With Random Brightness
/* * Method to create stars. The integer number is how many. */ private void createStars(int number) { GreenfootImage background = getBackground(); for (int i = 0; i < number; i++) int x = Greenfoot.getRandomNumber( getWidth() ); int y = Greenfoot.getRandomNumber( getHeight() ); int color = Greenfoot.getRandomNumber (256); background.setColor(new Color(color, color, color)); background.fillOval(x, y, 2, 2); } Generate a random number for color in the range 0 to 255 Will be more or less bright, but always on the white-black spectrum
62
Painting Stars With Random Brightness
63
Adding Fire Power: The Proton Wave
The idea is this: Our proton wave, once released, radiates outward from our rocket, damaging or destroying every asteroid in its path. Since it works in all directions simultaneously, it is a much more powerful weapon than our bullets.
64
The Proton Wave Does not Move Does not Disappear Does not cause Damage
65
The Proton Wave Already implemented code: Constructor
public ProtonWave() { initializeImages(); } public static void initializeImages() if(images == null) GreenfootImage baseImage = new GreenfootImage("wave.png"); images = new GreenfootImage[NUMBER_IMAGES]; int i = 0; while (i < NUMBER_IMAGES) int size = (i+1) * ( baseImage.getWidth() / NUMBER_IMAGES ); images[i] = new GreenfootImage(baseImage); images[i].scale(size, size); i++; public void act() Already implemented code: Constructor initializeImages () act ()
66
initializeImages() creates an Array of Growing Images
GreenfootImage [ ] images
67
Setting up The Proton Wave
/* * Index of the currently used image. */ private int imageCount = 0; * Create a new proton wave. public ProtonWave() { initializeImages(); setImage(images [0]); Greenfoot.playSound ("proton.wav"); }
68
The Proton Wave
69
The Proton Wave /* * Act for the proton wave is: grow and check whether we hit anything. */ public void act() { grow(); } * Grow the wave. If we get to full size remove it. private void grow ()
70
The Proton Wave Grow Algorithm
1) If our index has exceed the number of images then 1.1) Remove the wave from the world 2) Otherwise 2.1) set the next image in the array 2.2) increment the index
71
The Proton Wave /* * Grow the wave. If we get to full size remove it.
*/ private void grow () { if (imageCount >= NUMBER_IMAGES) getWorld().removeObject (this); else setImage(images[imageCount++]); }
72
The Proton Wave Create a new ProtonWave by hand
Click “> Act” to watch the wave grow sequentially
73
Create ProtonWave from Rocket
/* * Release a proton wave (if it is loaded). */ private void startProtonWave() { ProtonWave wave = new ProtonWave(); getWorld().addObject (wave, getX(), getY()); }
74
Create ProtonWave from Rocket
/* * Check whether there are any key pressed and react to them. */ private void checkKeys() { if (Greenfoot.isKeyDown("space")) fire(); if (Greenfoot.isKeyDown("z")) startProtonWave(); ignite (Greenfoot.isKeyDown ("up")); if (Greenfoot.isKeyDown("left")) setRotation(getRotation() - 5); if (Greenfoot.isKeyDown("right")) setRotation(getRotation() + 5); }
75
Test It
76
Test It Proton Wave Can Be Released Too Fast by Holding Down the z Key
77
A Delay Count of 200 Seems Reasonable
Managing Delays private static final int gunReloadTime = 5; // Minimum delay in firing gun. private static final int protonReloadTime = 200; // Minimum delay in proton wave bursts. private int reloadDelayCount; // How long ago we fired gun the last time. private int protonDelayCount; // How long ago we fired proton wave the last time. private GreenfootImage rocket = new GreenfootImage("rocket.png"); private GreenfootImage rocketWithThrust = new GreenfootImage("rocketWithThrust.png"); A Delay Count of 200 Seems Reasonable
78
Managing Delays /* * Do what a rocket's gotta do. (Which is: mostly flying about, and turning, * accelerating and shooting when the right keys are pressed.) */ public void act() { move (); checkKeys(); checkCollision(); reloadDelayCount++; protonDelayCount++; }
79
Managing Delays /* * Release a proton wave (if it is loaded). */
private void startProtonWave() { if (protonDelayCount >= protonReloadTime) ProtonWave wave = new ProtonWave(); getWorld().addObject (wave, getX(), getY()); protonDelayCount = 0; } The method only produces a new Proton Wave if sufficient time as passed since the last one
80
Test It
81
Interacting with Objects in Range
List getObjectsInRange (int radius, Class cls)
82
Check for ProtonWave Collisions
/* * Act for the proton wave is: grow and check whether we hit anything. */ public void act() { checkCollision(); grow(); } * Explode all intersecting asteroids. private void checkCollision()
83
ProtonWave Collisions
import greenfoot.*; // (World, Actor, GreenfootImage, and Greenfoot) import java.util.List; … /* * Explode all intersecting asteroids. */ private void checkCollision() { int range = getImage().getWidth() / 2; List<Asteroid> asteroids = getObjectsInRange (range, Asteroid.class); for (Asteroid a : asteroids) { }
84
Parameter to determine the amount of damage
Asteroid Hit Method Parameter to determine the amount of damage /* * Hit this asteroid dealing the given amount of damage. */ public void hit(int damage) { stability = stability - damage; if(stability <= 0) breakUp (); } Every Asteroid has “hit points” in the form of an integer variable called stability. An Asteroid breaks up if the variable reaches 0 or less.
85
ProtonWave Collissions
/* The damage this wave will deal */ private static final int DAMAGE = 30; … /* * Explode all intersecting asteroids. */ private void checkCollision() { int range = getImage().getWidth() / 2; List<Asteroid> asteroids = getObjectsInRange(range, Asteroid.class); for (Asteroid a : asteroids) { a.hit (DAMAGE); }
86
Extra: Hit Invincibility
The ProtonWave currently completely destroys all Asteroids it comes in contact with. Meaning it destroys both the Asteroids it hits and the Asteroids that are then spawned. Depending on how we want our game to function, this might not be desirable. How can we make sure that the ProtonWave does not destroy the new Asteroids?
87
Summary of Programming Techniques
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.