A red blob moves randomly across the canvas. The arrow keys help move it in the desired direction. The world ends when the blob travels outside of the bounds. The clock stops when the blob falls into the black hole in the middle of the canvas. The player can change the color of the blob to green by hitting the 'G' key, to yellow by hitting the 'Y' key, and back to red by hitting the 'R' key.
To see the html code for this applet, select View Source in your browser. The Java code below is the complete code for this applet.
The code can also run as Java application. The programmer has to
remove the code for the class BlobWorldApplet, change the
import to use the idraw package and either
comment out the main method - or run the program as a test
suite.
package blob;
import java.util.Random;
import tester.*;
import adraw.*;
import geometry.*;
import colors.*;
/**
* Applet wrapper for the BlobWorld
*
* @author Viera K. Proulx
* @since May 5, 2008
*/
public class BlobWorldApplet extends WorldApplet{
/** Produce a new BlobWorld */
public World getNewWorld(){
return new BlobWorld(
new Blob(new Posn(50, 60), 20, new Red()));
}
/** Set the size of this world */
public void setWorldSize(){
this.WIDTH = 200;
this.HEIGHT = 300;
}
}
/** Class that represents a colored disk that moves around the Canvas */
class Blob{
Posn center;
int radius;
IColor col;
/** The constructor */
Blob(Posn center, int radius, IColor col) {
this.center = center;
this.radius = radius;
this.col = col;
}
/** draw this blob in the given World */
void draw(Canvas c) {
c.drawDisk(this.center, this.radius, col);
}
/** move this blob 20 pixels in the direction given by the ke
or change its color to Green, Red or Yellow */
public void moveBlob(String ke){
if (ke.equals("right")){
this.center = new Posn(this.center.x + 5, this.center.y);
}
else if (ke.equals("left")){
this.center = new Posn(this.center.x - 5, this.center.y);
}
else if (ke.equals("up")){
this.center = new Posn(this.center.x, this.center.y - 5);
}
else if (ke.equals("down")){
this.center = new Posn(this.center.x, this.center.y + 5);
}
// change the color to Y, G, R
else if (ke.equals("Y")){
this.col = new Yellow();
}
else if (ke.equals("G")){
this.col = new Green();
}
else if (ke.equals("R")){
this.col = new Red();
}
}
/** produce a new blob moved by a random distance < n pixels */
void randomMove(int n){
this.center = new Posn(this.center.x + this.randomInt(n),
this.center.y + this.randomInt(n));
}
/** helper method to generate a random number in the range -n to n */
int randomInt(int n){
return -n + (new Random().nextInt(2 * n + 1));
}
/** is the blob outside the bounds given by the width and height */
boolean outsideBounds(int width, int height) {
return this.center.x < 0
|| this.center.x > width
|| this.center.y < 0
|| this.center.y > height;
}
/** is the blob near the center of area given by the width and height */
boolean nearCenter(int width, int height) {
return this.center.x > width / 2 - 10
&& this.center.x < width / 2 + 10
&& this.center.y > height / 2 - 10
&& this.center.y < height / 2 + 10;
}
}
/** Represent the world of a Blob */
class BlobWorld extends World {
int width = 200;
int height = 300;
Blob blob;
/** The constructor */
public BlobWorld(Blob blob) {
super();
this.blob = blob;
}
/** Move the Blob when the player presses a key */
public void onKeyEvent(String ke) {
this.blob.moveBlob(ke);
}
/** On tick check whether the Blob is out of bounds,
* or fell into the black hole in the middle.
* If all is well, move the Blob in a random direction.
*/
public void onTick() {
// if the blob is outside the canvas, stop
if (this.blob.outsideBounds(this.width, this.height)){
this.endOfWorld("Blob is outside the bounds");
}
// time ends is the blob falls into the black hole in the middle
if (this.blob.nearCenter(this.width, this.height)){
this.endOfTime("Black hole ate the blob");
}
// else move the blob randomly at most 5 pixels in any direction
else
this.blob.randomMove(5);
}
/** draw this world with a blue background */
public void draw() {
this.theCanvas.drawRect(new Posn(0, 0),
this.width, this.height, new Blue());
this.blob.draw(this.theCanvas);
this.theCanvas.drawDisk(new Posn(100, 150), 10, new Black());
}
}
class BlobExamples implements IExamples{
// examples of data for the Blob class:
Blob b1 = new Blob(new Posn(100, 100), 50, new Red());
Blob b1left = new Blob(new Posn(95, 100), 50, new Red());
Blob b1right = new Blob(new Posn(105, 100), 50, new Red());
Blob b1up = new Blob(new Posn(100, 95), 50, new Red());
Blob b1down = new Blob(new Posn(100, 105), 50, new Red());
Blob b1G = new Blob(new Posn(100, 100), 50, new Green());
Blob b1Y = new Blob(new Posn(100, 100), 50, new Yellow());
/** reset the Blob */
void reset(){
b1 = new Blob(new Posn(100, 100), 50, new Red());
}
/** test the method moveBlob in the Blob class */
void testMoveBlob(Tester t){
b1.moveBlob("left");
t.checkExpect(b1, b1left, "test moveBolb - left " + "\n");
reset();
b1.moveBlob("right");
t.checkExpect(b1, b1right, "test movelob - right " + "\n");
reset();
b1.moveBlob("up");
t.checkExpect(b1, b1up, "test moveBlob - up " + "\n");
reset();
b1.moveBlob("down");
t.checkExpect(b1, b1down, "test moveBlob - down " + "\n");
reset();
b1.moveBlob("G");
t.checkExpect(b1, b1G, "test moveBlob - G " + "\n");
reset();
b1.moveBlob("Y");
t.checkExpect(b1, b1Y, "test moveBlob - Y " + "\n");
reset();
b1G.moveBlob("R");
t.checkExpect(b1G, b1, "test moveBlob - R " + "\n");
}
/** test the method outsideBounds in the Blob class */
void testOutsideBounds(Tester t){
reset();
t.checkExpect(b1.outsideBounds(60, 200), true,
"test outsideBounds on the right");
t.checkExpect(b1.outsideBounds(100, 90), true,
"test outsideBounds below");
t.checkExpect(
new Blob(new Posn(-5, 100), 50, new Red()).outsideBounds(100, 110),
true,
"test outsideBounds above");
t.checkExpect(
new Blob(new Posn(80, -5), 50, new Blue()).outsideBounds(100, 90),
true,
"test outsideBounds on the left");
t.checkExpect(b1.outsideBounds(200, 400), false,
"test outsideBounds - within bounds");
}
/** test the method nearCenter in the Blob class */
void testNearCenter(Tester t){
reset();
t.checkExpect(b1.nearCenter(200, 200), true,
"test nearCenter - true");
t.checkExpect(b1.nearCenter(200, 100), false,
"test nearCenter - false");
}
/** the method randomInt in the Blob class */
void testRandomInt(Tester t){
t.checkOneOf(b1.randomInt(3),
new Integer[]{-3, -2, -1, 0, 1, 2, 3},
"test randomInt");
}
/** the method randomMove in the Blob class */
void testRandomMove(Tester t){
b1.randomMove(1);
t.checkOneOf(b1,
new Blob[]{new Blob(new Posn(100, 100), 50, new Red()),
new Blob(new Posn(101, 100), 50, new Red()),
new Blob(new Posn( 99, 100), 50, new Red()),
new Blob(new Posn(100, 101), 50, new Red()),
new Blob(new Posn(100, 99), 50, new Red())},
"test randomMove");
// runWorld();
}
/** Combine all tests */
public void tests(Tester t){
testMoveBlob(t);
testOutsideBounds(t);
testNearCenter(t);
testRandomInt(t);
testRandomMove(t);
testOutsideBounds(t);
testOutsideBounds(t);
}
// start the world
void runWorld(){
// construct an instance of a TimerWorld
BlobWorld w = new BlobWorld(new Blob(new Posn(100, 200), 20, new Red()));
// and run the TimerWorld
w.bigBang(200, 300, 0.3);
}
/** Run the world as an application:
* first delete the BlobWorldApplet class *//*
public static void main(String[] argv){
// construct an instance of a TimerWorld
BlobWorld w = new BlobWorld(new Blob(new Posn(100, 200), 20, new Red()));
// and run the TimerWorld
w.bigBang(200, 300, 0.3);
}
*/
}