Bouncing Hedgehog
Spike the hedgehog loves to roll up into a spiky ball and bounce on his trampoline, but he is a bit clumsy. Can you move the trampoline so that he never falls to the ground?
In this chapter you build a whole game on your own, using everything from the
chapters before: sprites of your own classes, positions, keys, run(), if and
touching. At the end you swap in your own pictures.
A few steps are marked Your turn. Try them yourself before you open the solution.
Step 1: The stage
Create a class BouncyHedgehogStage:
import org.openpatch.scratch.*;
public class BouncyHedgehogStage extends Stage {
public BouncyHedgehogStage() {
this.addBackdrop("background");
}
public static void main(String[] args) {
Window myWindow = new Window(480, 360);
myWindow.setStage(new BouncyHedgehogStage());
}
}
Run it. You see the backdrop, and nothing else yet.
Step 2: The trampoline
The trampoline is a sprite, so it gets a class of its own:
import org.openpatch.scratch.*;
public class TrampolineSprite extends Sprite {
public TrampolineSprite() {
this.addCostume("spring");
this.setSize(70);
}
}
Line by line:
-
public class TrampolineSprite extends Spritesays that a trampoline is a kind of sprite. It can do everything a sprite can do. -
public TrampolineSprite() { ... }is the constructor. It runs once, when a trampoline is made, and sets it up: a costume and a size.
A class is only a plan, so nothing has changed on the stage. Make a trampoline
with new and add it to the stage:
import org.openpatch.scratch.*;
public class BouncyHedgehogStage extends Stage {
public BouncyHedgehogStage() {
this.addBackdrop("background");
this.add(new TrampolineSprite());
}
public static void main(String[] args) {
Window myWindow = new Window(480, 360);
myWindow.setStage(new BouncyHedgehogStage());
}
}
Run it again. The trampoline is in the middle of the stage.
Step 3: Your turn: the hedgehog
Add Spike the same way: a class HedgehogSprite with the costume spikeBall1
and a size of 40, and a line in the stage that adds him.
Solution
import org.openpatch.scratch.*;
public class HedgehogSprite extends Sprite {
public HedgehogSprite() {
this.addCostume("spikeBall1");
this.setSize(40);
}
}
And in BouncyHedgehogStage, below the trampoline:
this.add(new HedgehogSprite());
Step 4: Starting positions
Both sprites are in the middle, on top of each other. The trampoline belongs at the bottom. Add a line to its constructor:
this.setPosition(0, -120);
x: 0 is the middle from left to right, and y: -120 is 120 steps down from the middle.
Your turn: put Spike at the top left, at x: -180, y: 140.
Solution
In the constructor of HedgehogSprite:
this.setPosition(-180, 140);
Step 5: Move the trampoline
The arrow keys should move the trampoline. whenKeyPressed is called by the
library every time a key is pressed, and key says which one it was:
import org.openpatch.scratch.*;
public class TrampolineSprite extends Sprite {
public TrampolineSprite() {
this.addCostume("spring");
this.setSize(70);
this.setPosition(0, -120);
}
public void whenKeyPressed(KeyCode key) {
if (key == KeyCode.LEFT) {
this.changeX(-10);
} else if (key == KeyCode.RIGHT) {
this.changeX(10);
}
}
}
This is Scratch's when [left arrow] key pressed, but one method handles every
key, and the if decides what to do. Run it, click the stage so it gets the
keys, and move the trampoline.
Step 6: Make Spike bounce
Spike should keep moving, bounce off the edges, and fly back up when he lands on the trampoline. If he gets past it, he hits the ground:
import org.openpatch.scratch.*;
public class HedgehogSprite extends Sprite {
public HedgehogSprite() {
this.addCostume("spikeBall1");
this.setSize(40);
this.setPosition(-180, 140);
this.setDirection(160);
}
public void run() {
if (this.getY() > -100) {
this.move(2);
this.ifOnEdgeBounce();
if (this.isTouchingSprite(TrampolineSprite.class)) {
this.setDirection(Random.randomInt(-45, 45));
}
} else {
this.say("Ouch!");
}
}
}
Before you run it, read the code and predict what will happen. Then run it and check.
-
setDirection(160)points Spike down and a little to the right. 0 is up, 90 is right, 180 is down. -
run()is called in every frame. As long as Spike is above y: -100 he keeps moving. Below that he is lower than the top of the trampoline, so he has missed it: he stops and says "Ouch!". -
isTouchingSprite(TrampolineSprite.class)asks: am I touching any trampoline? If so, Spike gets a random direction between -45 and 45, which is always upwards.
The finished game
Here it is running. Click the stage and use the arrow keys.
Step 7: Your own pictures
So far every picture was built in. You can use your own just as well: a drawing of yours, a photo, or a picture from the internet that you are allowed to use.
This needs Studio or VS Code, because the browser editor cannot load files from your computer. Download the project with a hedgehog, a trampoline and a playground as picture files:
Project: Bouncy HedgehogThe pictures are in the project folder, next to the Java files. Give each one a name of your choice, followed by its file name:
this.addCostume("hedgehog", "hedgehog.png");
this.addCostume("trampoline", "trampoline.png");
this.addBackdrop("playground", "playground.jpg");
The name is what you use later with switchCostume. File names must match
exactly, including capital letters and the ending. You may need a different
setSize, because these pictures are smaller than the built-in ones.
Costumes, Backdrops and Sounds explains more, also
about sounds.
The finished game with these pictures:
Project: Bouncy Hedgehog 100%Things to try
Make Spike faster
Hint
How far Spike moves in each frame is the number in move.
Solution
In run(), change this.move(2); to this.move(4);. The game gets harder, so
the trampoline may need to be faster as well: change the 10 in
whenKeyPressed.
Space puts the trampoline back in the middle
Hint
Add a third case to the if in whenKeyPressed. KeyCode.SPACE is the space
bar, and setX sets the position from left to right.
Solution
public void whenKeyPressed(KeyCode key) {
if (key == KeyCode.LEFT) {
this.changeX(-10);
} else if (key == KeyCode.RIGHT) {
this.changeX(10);
} else if (key == KeyCode.SPACE) {
this.setX(0);
}
}
Count the bounces
Show how often Spike has landed on the trampoline.
Hint
You need a field bounces in HedgehogSprite, and showVariable
shows it on the stage. Careful: Spike touches the trampoline for several frames
in a row, so count only in the frame where the touching starts. A second
field can remember whether he was touching it in the frame before.
Solution
import org.openpatch.scratch.*;
public class HedgehogSprite extends Sprite {
private int bounces = 0;
private boolean wasTouching = false;
public HedgehogSprite() {
this.addCostume("spikeBall1");
this.setSize(40);
this.setPosition(-180, 140);
this.setDirection(160);
this.showVariable("Bounces", () -> this.bounces);
}
public void run() {
if (this.getY() > -100) {
this.move(2);
this.ifOnEdgeBounce();
boolean touching = this.isTouchingSprite(TrampolineSprite.class);
if (touching && !this.wasTouching) {
this.bounces = this.bounces + 1;
this.setDirection(Random.randomInt(-45, 45));
}
this.wasTouching = touching;
} else {
this.say("Ouch!");
}
}
}
When you are confident, try changeColorEffect to change Spike's colour every time he bounces.