CalaverasCrossingPainter.java and CalaverasCrossingWindow are incomplete. Compiled versions are available in the archive.
CalaverasCrossingApplet.java
/*
<APPLET CODE="CalaverasCrossingApplet.class" WIDTH=450 HEIGHT=600></APPLET>
*/
import javax.swing.*;
import java.awt.*;
/**
* An applet that displays a game of Calaveras Crossing.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
* @high 3460 as of 10/8/2008
*/
public class CalaverasCrossingApplet extends JApplet
{
public void init()
{
CalaverasCrossingGame game = new CalaverasCrossingGame();
Level level = new Level();
// ADD LANES HERE
game.startLevel(level);
CalaverasCrossingPanel panel = new CalaverasCrossingPanel(game);
CalaverasCrossingControl control = new CalaverasCrossingControl(game, panel);
panel.addKeyListener(control);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel, BorderLayout.CENTER);
}
}
CalaverasCrossingControl.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* The controller for Calaveras Crossing. The controller handles the time and
* the player's input.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class CalaverasCrossingControl extends KeyAdapter
{
/**
* The game model this controller is connected to.
*/
private CalaverasCrossingGame game;
/**
* The game view this controller is connected to.
*/
private CalaverasCrossingPanel view;
/**
* Whether we have given the panel the focus.
*/
private boolean gotFocus;
/**
* Creates a CalaverasCrossing controller connected to the given game model and
* view.
*
* @param g a CalaverasCrossing game
* @param p a panel displaynig a CalaverasCrossing game
*/
public CalaverasCrossingControl(CalaverasCrossingGame g, CalaverasCrossingPanel p)
{
game = g;
view = p;
gotFocus = false;
Timer t = new Timer(1000 / 20,
new ActionListener() {
public void actionPerformed(ActionEvent e)
{
timerTick();
}
});
t.start();
}
/**
* Handles timer events.
*/
public synchronized void timerTick()
{
game.update();
view.repaint();
if (!gotFocus)
{
view.requestFocus();
gotFocus = true;
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_UP)
game.getPlayerFrog().startJump(Frog.UP);
else if (e.getKeyCode() == KeyEvent.VK_DOWN)
game.getPlayerFrog().startJump(Frog.DOWN);
else if (e.getKeyCode() == KeyEvent.VK_LEFT)
game.getPlayerFrog().startJump(Frog.LEFT);
else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
game.getPlayerFrog().startJump(Frog.RIGHT);
}
}
CalaverasCrossingGame.java
import java.util.*;
import java.awt.*;
/**
* A Calaveras Crossing game. A game consists of a level (which contains lanes
* that in turn contain obstacles and animals) together with the player's
* frog.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class CalaverasCrossingGame
{
/**
* Constants for scores
*/
public static final int FORWARD_JUMP_SCORE = 10;
public static final int FROG_HOME_SCORE = 50;
public static final int REMAINING_TIME_SCORE = 10;
public static final int ESCORT_SCORE = 200;
public static final int FLY_EATEN_SCORE = 200;
public static final int LEVEL_COMPLETE_SCORE = 1000;
/**
* The amount of time the player has to being a frog home.
*/
public static final int FROG_TIME = 45;
/**
* The time to wait before starting a new frog.
*/
public static final double NEW_FROG_WAIT = 3.0;
/**
* The default number of lives at the start of the game.
*/
public static final int DEFAULT_LIVES = 3;
/**
* This game's current level.
*/
private Level level;
/**
* The player's score.
*/
private int score;
/**
* The time this game was last updated, in milliseconds. -1 indicates
* no update has taken place.
*/
private long lastUpdate;
/**
* The number of frogs left in this game.
*/
private int frogsLeft;
/**
* The number of frogs that have reached home during the current level.
*/
private int frogsHome;
/**
* The player's frog.
*/
private Frog playerFrog;
public CalaverasCrossingGame()
{
level = null;
lastUpdate = -1;
playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
frogsLeft = DEFAULT_LIVES - 1;
frogsHome = 0;
score = 0;
}
/**
* Starts the given level in this game.
*
* @param l a level
*/
public void startLevel(Level l)
{
if (l == null)
throw new IllegalArgumentException("null level");
level = l;
}
/**
* Returns the player's frog from this game.
*/
public Frog getPlayerFrog()
{
return playerFrog;
}
/**
* Returns an iterator over the lanes in this game's current level.
*
* @return an iterator over the lanes in this game's current level
*/
public Iterator laneIterator()
{
return level.laneIterator();
}
/**
* Returns the given lane from this game's current level.
*
* @param index a lane index
*/
public Lane getLane(int index)
{
return level.getLane(index);
}
/**
* Updates this game.
*/
public synchronized void update()
{
long t = System.currentTimeMillis();
if (lastUpdate != -1 && level != null)
{
// compute time since last update and notify everything in
// this game
double interval = (t - lastUpdate) / 1000.0;
level.update(interval);
playerFrog.update(interval, this);
if (!playerFrog.isVisible()
&& frogsHome < 5
&& playerFrog.getStateTime() >= NEW_FROG_WAIT)
{
playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
}
else if (playerFrog.isDead()
&& playerFrog.getStateTime() > NEW_FROG_WAIT
&& frogsLeft > 0)
{
playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
frogsLeft--;
}
}
lastUpdate = t;
}
/**
* Adds the given amount to the player's score for this game.
*
* @param s the amount to add
*/
public void addScore(int s)
{
score += s;
}
/**
* Updates the game statistics to reflect a forward jump.
*/
public void forwardJump()
{
addScore(FORWARD_JUMP_SCORE);
}
/**
* Updates game statistics to reflect the fact that a frog was brought
* home.
*/
public void frogHome()
{
frogsHome++;
addScore(FROG_HOME_SCORE);
addScore((FROG_TIME - (int)(playerFrog.getLifeTime())) * REMAINING_TIME_SCORE);
if (frogsHome == 5)
{
addScore(LEVEL_COMPLETE_SCORE);
}
}
/**
* Returns the number of lives left in this game.
*
* @return the number of lives left in this game
*/
public int countLives()
{
return frogsLeft;
}
/**
* Returns the score for the game.
*
* @return the score for the game
*/
public int getScore()
{
return score;
}
}
CalaverasCrossingPainter.java
import java.util.*;
import java.awt.*;
/**
* A painter for Calaveras Crossing games.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class CalaverasCrossingPainter
{
/**
* The game this painter paints.
*/
private CalaverasCrossingGame game;
/**
* Creates a painter to paint the given game.
*
* @param g a CalaverasCrossing game
*/
public CalaverasCrossingPainter(CalaverasCrossingGame g)
{
game = g;
}
/**
* Paints this painter's game on the given graphics context.
*
* @param g the graphics context to paint in
* @param w the width of the area to paint in
* @param h the height of the area to paint in
*/
public void paint(Graphics g, int w, int h)
{
// compute the height in pixels of each lane
int laneHeight = h / Level.NUM_LANES;
// paint all the lanes
Iterator i = game.laneIterator();
int laneIndex = 0;
while (i.hasNext())
{
Lane l = (Lane)(i.next());
Graphics laneClip = g.create(0,
laneIndex * laneHeight,
w,
laneHeight);
paintLane(laneClip, w, laneHeight, l);
laneIndex++;
}
// draw score, time, and remaining frogs
g.setColor(Color.WHITE);
g.drawString("SCORE: " + game.getScore() + " TIME: " + (int)(game.getPlayerFrog().getRemainingTime()) + " LIVES: " + game.countLives(), 0, 13 * laneHeight - 2);
// paint the player's frog
Frog frog = game.getPlayerFrog();
// does the clipping region not get rotated along with the
// coordinate system or is something else wrong here?
Graphics frogClip;
if (frog.getDirection() == Frog.UP || frog.getDirection() == Frog.DOWN)
{
frogClip = g.create((int)(w * frog.getX() / Lane.SCREEN_WIDTH),
(int)(frog.getY() * laneHeight),
(int)(w * (frog.getX() + frog.getWidth()) / Lane.SCREEN_WIDTH),
(int)(frog.getHeight() * laneHeight));
}
else
{
frogClip = g.create((int)(w * frog.getX() / Lane.SCREEN_WIDTH),
(int)(frog.getY() * laneHeight),
(int)(frog.getHeight() * laneHeight),
(int)(w * (frog.getX() + frog.getWidth()) / Lane.SCREEN_WIDTH));
}
Graphics2D g2 = (Graphics2D)frogClip;
if (frog.getDirection() == Frog.LEFT)
{
g2.rotate(-Math.PI / 2);
g2.translate(-(int)(w * frog.getWidth() / Lane.SCREEN_WIDTH) + 1, 0);
}
else if (frog.getDirection() == Frog.DOWN)
{
g2.rotate(Math.PI);
g2.translate(-(int)(w * frog.getWidth()/ Lane.SCREEN_WIDTH) + 1, -(int)(frog.getHeight() * laneHeight));
}
else if (frog.getDirection() == Frog.RIGHT)
{
g2.rotate(Math.PI / 2);
g2.translate(0, -(int)(frog.getHeight() * laneHeight));
}
paintFrog(g2, (int)(w * frog.getWidth() / Lane.SCREEN_WIDTH), (int)(frog.getHeight() * laneHeight), frog);
}
/**
* Paints the given lane on the given graphics context.
*
* @param g the graphics context to paint in
* @param w the width of the area to paint in
* @param h the height of the area to paint in
* @param l the lane to paint
*/
private void paintLane(Graphics g, int w, int h, Lane l)
{
// paint the background
switch (l.getType())
{
case Lane.ROAD:
g.setColor(Color.GRAY);
break;
case Lane.GRASS:
g.setColor(Color.GREEN);
break;
case Lane.RIVER:
g.setColor(Color.BLUE);
break;
}
g.fillRect(0, 0, w, h);
// if you're paying attention to my comments and want to paint some
// lane markers, this is the place to do it -- the upper left corner
// of the lane we're currently working on is (0, 0) and the lower
// right corner is (w - 1, h - 1); some thin white rectangles along
// the top edge might do the trick
// paint the obstacles in the lane
Iterator i = l.obstacleIterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
double pos = ((Double)(p.getSecond())).doubleValue();
int obsX = (int)(w * pos / Lane.SCREEN_WIDTH);
int obsW = (int)(w * o.getWidth() / Lane.SCREEN_WIDTH);
Graphics2D obstacleClip = (Graphics2D)(g.create(obsX, 0, obsW, h));
if (l.getVelocity() < 0)
{
/*
obstacleClip.rotate(Math.PI);
obstacleClip.translate(-(int)(w * o.getWidth() / Lane.SCREEN_WIDTH), -h);
*/
obstacleClip.scale(-1.0, 1.0);
obstacleClip.translate(-(int)(w * o.getWidth() / Lane.SCREEN_WIDTH), 0);
}
paintObstacle(obstacleClip, obsW, h, o);
}
}
/**
* Paints the given obstacle.
*
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param o the obstacle to paint
*/
public void paintObstacle(Graphics g, int w, int h, Obstacle o)
{
if (o instanceof Truck)
paintTruck(g, w, h, (Truck)o);
else if (o instanceof Tractor)
paintTractor(g, w, h, (Tractor)o);
else if (o instanceof Car)
paintCar(g, w, h, (Car)o);
else if (o instanceof Racecar)
paintRacecar(g, w, h, (Racecar)o);
else if (o instanceof Log)
paintLog(g, w, h, (Log)o);
else if (o instanceof Turtles)
paintTurtles(g, w, h, (Turtles)o);
else if (o instanceof Home)
paintHome(g, w, h, (Home)o);
else
{
g.setColor(Color.WHITE);
g.fillRect(0, 0, w, h);
}
}
/**
* Paints the given truck.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param t the truck to paint
*/
public void paintTruck(Graphics g, int w, int h, Truck t)
{
paintVehicle(g, w, h, t);
}
/**
* Paints the given truck.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param t the truck to paint
*/
public void paintTractor(Graphics g, int w, int h, Tractor t)
{
paintVehicle(g, w, h, t);
}
/**
* Paints the given car.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param c the car to paint
*/
public void paintCar(Graphics g, int w, int h, Car c)
{
paintVehicle(g, w, h, c);
}
/**
* Paints the given truck.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param c the car to paint
*/
public void paintRacecar(Graphics g, int w, int h, Racecar c)
{
paintVehicle(g, w, h, c);
}
/**
* Paints the given vehicle.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param v the vehicle to paint
*/
public void paintVehicle(Graphics g, int w, int h, Vehicle v)
{
g.setColor(Color.BLUE.darker());
g.fillRect(1, 1, w - 2, h - 2);
}
/**
* Paints the given log.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param l the log to paint
*/
public void paintLog(Graphics g, int w, int h, Log l)
{
g.setColor(Color.BROWN);
g.fillRect(0, 0, w, h);
}
/**
* Paints the given group of turtles.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param t the turtles to paint
*/
public void paintTurtles(Graphics g, int w, int h, Turtles t)
{
int turtleWidth = w / t.getCount();
for (int i = 0; i < t.getCount(); i++)
{
Graphics turtleClip = g.create(turtleWidth * i,
0,
turtleWidth,
h);
paintTurtle(turtleClip, turtleWidth, h, t);
}
}
/**
* Paints a single turtle within a group
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param t the group of turtles the one to paint is in
*/
public void paintTurtle(Graphics g, int w, int h, Turtles t)
{
g.setColor(Color.RED);
g.fillOval(0, 0, w, h);
}
/**
* Paints a frog home.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param home the home to paint
*/
public void paintHome(Graphics g, int w, int h, Home home)
{
g.setColor(Color.BLUE);
g.fillRect(0, 0, w, h);
}
/**
* Paints a frog.
* @param g the graphics context to paint in
* @param w the width to paint in
* @param h the height to paint in
* @param frog the frog to paint
*/
public void paintFrog(Graphics g, int w, int h, Frog frog)
{
g.setColor(frog.getColor());
g.fillOval(0, 0, w, h);
}
}
CalaverasCrossingPanel.java
import java.awt.*;
import javax.swing.*;
/**
* A panel showing the main part of the screen for Calaveras Crossing.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class CalaverasCrossingPanel extends JPanel
{
/**
* The game this panel displays.
*/
private CalaverasCrossingGame game;
/**
* The painter for the game displayed in this panel.
*/
private CalaverasCrossingPainter painter;
/**
* Creates a new panel displaying the given game.
*
* @param g a CalaverasCrossing game
*/
public CalaverasCrossingPanel(CalaverasCrossingGame g)
{
game = g;
painter = new CalaverasCrossingPainter(g);
}
/**
* Paints this game.
*
* @param g the graphics context to paint in
*/
public void paint(Graphics g)
{
// determine the area to paint in based on whether the aspect
// ratio of this panel is greater than or less than the aspect
// ratio of the game
double aspect = (double)Lane.SCREEN_WIDTH / Level.NUM_LANES;
int w, h;
if ((double)getWidth() / getHeight() > aspect)
{
h = getHeight();
w = (int)(h * aspect);
}
else
{
w = getWidth();
h = (int)(w / aspect);
}
Graphics clipRegion = g.create((getWidth() - w) / 2,
(getHeight() - h) / 2,
w,
h);
painter.paint(g, w, h);
}
}
CalaverasCrossingWindow.java
/**
* A window that displays a game of Calaveras Crossing.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
* @high 2910 as of 10/8/2008
*/
import javax.swing.*;
import java.awt.*;
public class CalaverasCrossingWindow extends JFrame
{
public CalaverasCrossingWindow()
{
super("Calaveras Crossing");
CalaverasCrossingGame game = new CalaverasCrossingGame();
Level level = new Level();
// ADD LANES HERE
game.startLevel(level);
CalaverasCrossingPanel panel = new CalaverasCrossingPanel(game);
CalaverasCrossingControl control = new CalaverasCrossingControl(game, panel);
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != null)
{
System.out.println(KeyboardFocusManager.getCurrentKeyboardFocusManager());
KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner().addKeyListener(control);
}
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel, BorderLayout.CENTER);
setSize(400, 300);
setVisible(true);
}
public static void main(String[] args)
{
JFrame win = new CalaverasCrossingWindow();
win.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Car.java
/**
* A Calaveras Crossing car.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Car extends Vehicle
{
/**
* The width of a car, in frog widths.
*/
private static final double CAR_WIDTH = 1.25;
/**
* Creates a new car.
*/
public Car()
{
super(CAR_WIDTH);
}
}
Floater.java
/**
* A Calaveras Crossing floating obstacle.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class Floater extends Obstacle
{
/**
* Creates a new floating obstacle of the given width.
*
* @param w a positive <CODE>double</CODE>
*/
public Floater(double w)
{
super(w);
}
/**
* Determines if this floating obstacle is above water.
*
* @return true if and only if this floating obstacle is above water
*/
public boolean isAboveWater()
{
return true;
}
}
Frog.java
import java.awt.*;
/**
* A frog. This can be the player's frog or a friendly frog the player
* can take home.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Frog
{
/**
* Direction constants.
*/
public static final int UP = 0;
public static final int DOWN = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;
/**
* Deltas for directions.
*/
private static final int[] dx = {0, 0, -1, 1};
private static final int[] dy = {-1, 1, 0, 0};
/**
* The direction this frog is facing.
*/
private int facingDir;
/**
* The vertical position of this frog, in whole lanes. This will
* be the lane this frog was last in.
*/
private int y;
/**
* The horizontal position of this frog, in frog widths.
*/
private double x;
/**
* The color of this frog.
*/
private Color color;
/**
* The maximum lifespan of this frog. This frog will die if
* it is not home before this time expires.
*/
private double maxTime;
/**
* The total lifespan of this frog.
*/
private double lifeTime;
/**
* State constants.
*/
public static final int DEAD = 0;
public static final int SITTING = 1;
public static final int JUMPING = 2;
public static final int HOME = 3;
/**
* The state of this frog. The state can be dead, jumping, or sitting.
*/
private int state;
/**
* The amount of time this frog has spent in its current state.
*/
private double stateTime;
/**
* The time it takes this frog to complete a jump, in seconds.
*/
private double jumpTime;
/**
* The default jumping speed of a frog in seconds.
*/
public static final double DEFAULT_JUMP_TIME = 0.2;
/**
* The horizontal distance covered in a single jump, measured in frog
* widths.
*/
public static final double JUMP_DISTANCE = 1.0;
/**
* The width of a frog, in frog widths. Provided for consistency with
* older implementation.
*/
public static final double FROG_WIDTH = 1.0;
/**
* Creates a new frog of the given color at the given location.
*/
public Frog(Color c, double startX, int startY, int t)
{
color = c;
x = startX;
y = startY;
facingDir = UP;
setState(SITTING);
jumpTime = DEFAULT_JUMP_TIME;
maxTime = t;
lifeTime = 0.0;
}
/**
* Returns the color of this frog.
*
* @return the color of this frog
*/
public Color getColor()
{
return color;
}
/**
* Updates this frog.
*
* @param t the time since the last update, in seconds
* @param game the game this frog is part of
*/
public void update(double t, CalaverasCrossingGame game)
{
// update timers
if (state != HOME)
{
lifeTime += t;
}
stateTime += t;
if (state == JUMPING && stateTime >= jumpTime)
{
// end of jump
if (facingDir == UP)
game.forwardJump();
setState(SITTING);
x += dx[facingDir] * JUMP_DISTANCE;
y += dy[facingDir];
}
Lane l = game.getLane(y);
// check for floating on logs
if (state == SITTING)
{
if (y == 0)
{
// check for home
Home h = l.findHome(x, x + getWidth());
if (h != null && !h.isOccupied())
{
h.setOccupied();
setState(HOME);
game.frogHome();
}
else
{
setState(DEAD);
}
}
else
{
// float or drown if in river
if (l.getType() == Lane.RIVER)
{
if (l.hasFloaterAt(x + getWidth() / 3.0)
&& l.hasFloaterAt(x + getWidth() * 2 / 3.0))
x -= l.getVelocity() * t;
else
{
setState(DEAD);
}
}
// check for collisions
if (l.hasCollision(x, x + getWidth()))
{
setState(DEAD);
}
}
}
else if (state == JUMPING)
{
if (facingDir == UP || facingDir == DOWN)
{
Lane jumpLane = game.getLane(y + dy[facingDir]);
if (stateTime < jumpTime * 0.25)
{
if (l.hasCollision(x, x + getWidth()))
{
setState(DEAD);
}
}
else if (stateTime > jumpTime * 0.75)
{
if (jumpLane.hasCollision(x, x + getWidth()))
{
setState(DEAD);
}
}
else
{
if (jumpLane.hasCollision(x, x + getWidth())
|| l.hasCollision(x, x + getWidth()))
{
setState(DEAD);
}
}
}
else
{
// horizontal jump
if (l.hasCollision(getX(), getX() + getWidth()))
{
setState(DEAD);
}
}
}
if ((getX() < 0.0 || getX() + getWidth() > Lane.SCREEN_WIDTH) && state != DEAD)
{
setState(DEAD);
}
if (lifeTime > maxTime && state != HOME && state != DEAD)
{
setState(DEAD);
}
}
/**
* Returns the current x position of this frog.
*
* @return the x position of this frog
*/
public double getX()
{
if (state != JUMPING || facingDir == UP || facingDir == DOWN)
{
return x;
}
else if (facingDir == LEFT)
{
if (stateTime < jumpTime * 0.75)
return x - JUMP_DISTANCE * (stateTime / (jumpTime * 0.75));
else
return x - JUMP_DISTANCE;
}
else /* if (facingDir == RIGHT) */
{
if (stateTime < jumpTime * 0.25)
return x;
else
return x + JUMP_DISTANCE * (stateTime - 0.25 * jumpTime) / (jumpTime * 0.75);
}
}
/**
* Returns the current y position of this frog.
*
* @return the y position of this frog
*/
public double getY()
{
if (state != JUMPING || facingDir == LEFT || facingDir == RIGHT)
{
return y;
}
else if (facingDir == UP)
{
if (stateTime < jumpTime * 0.75)
{
return y - (stateTime / (jumpTime * 0.75));
}
else
return y - 1.0;
}
else /* if (facingDir == DOWN) */
{
if (stateTime < jumpTime * 0.25)
{
return y;
}
else
{
return y + (stateTime - 0.25 * jumpTime) / (jumpTime * 0.75);
}
}
}
/**
* Returns the direction this frog is facing.
*
* @return the direction this frog is facing
*/
public int getDirection()
{
return facingDir;
}
/**
* Returns the current painting width of this frog in units of
* screen widths. "Width" here means the size across the frog
* (that is, perpendicular to the direction it is facing).
*/
public double getWidth()
{
return FROG_WIDTH;
/*
if (state != JUMPING || facingDir == UP || facingDir == DOWN)
{
return FROG_WIDTH;
}
else
{
if (stateTime < jumpTime * 0.25)
{
// beginning of jump
return FROG_WIDTH * (1.0 + 1.0 / 3.0 * stateTime / (jumpTime * 0.25));
}
else if (stateTime > jumpTime * 0.75)
{
// end of jump
return FROG_WIDTH * (1.0 + 1.0 / 3.0 * (jumpTime - stateTime) / (jumpTime * 0.25));
}
else
{
return FROG_WIDTH * 4.0 / 3.0;
}
}
*/
}
/**
* Returns the current painting height of this frog in units of
* lane height. "Height" here means along the frog (that is, in the
* direction it is facing).
*
* @return the painting height of this frog
*/
public double getHeight()
{
if (state != JUMPING /*|| facingDir == LEFT || facingDir == RIGHT*/)
{
return 1.0;
}
else
{
if (stateTime < jumpTime * 0.25)
{
// beginning of jump
return (1.0 + 1.0 / 3.0 * stateTime / (jumpTime * 0.25));
}
else if (stateTime > jumpTime * 0.75)
{
// end of jump
return (1.0 + 1.0 / 3.0 * (jumpTime - stateTime) / (jumpTime * 0.25));
}
else
{
return 4.0 / 3.0;
}
}
}
/**
* Determines if this frog is alive.
*
* @return true if and only if this frog is alive
*/
public boolean isDead()
{
return (state == DEAD);
}
/**
* Determines if this frog is visible. A frog is visible if it is not home.
*
* @return true if and only if this frog is visible
*/
public boolean isVisible()
{
return (state != HOME);
}
/**
* Determines if this frog is moving.
*
* @return true if and only if this frog is in the middle of a jump
*/
public boolean isMoving()
{
return (state == JUMPING);
}
/**
* Starts this frog a-jumpin' in the given direction.
*
* @param dir one of the direction constants
*/
public void startJump(int dir)
{
if (state == SITTING && (y < 12 || dir != DOWN))
{
facingDir = dir;
setState(JUMPING);
}
}
/**
* Sets the state of this frog.
*
* @param s one of the state contants
*/
public void setState(int s)
{
state = s;
stateTime = 0.0;
}
/**
* Returns how long this frog has been in its current state.
*
* @return how long this frog has been in its current state
*/
public double getStateTime()
{
return stateTime;
}
/**
* Returns how long this frog has been alive.
*
* @return how long this frog has been alive
*/
public double getLifeTime()
{
return lifeTime;
}
/**
* Returns how much time this frog has left to live
*
* @return how much time this frog has left to live
*/
public double getRemainingTime()
{
return Math.max(0.0, maxTime - lifeTime);
}
}
Home.java
/**
* A home for a frog.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Home extends Obstacle
{
/**
* The width of a home, measured in frog widths.
*/
public static final double HOME_WIDTH = 1.5;
/**
* A flag that indicates whether this home is occupied by a frog.
*/
private boolean occupied;
/**
* Creates a new unoccupied home.
*/
public Home()
{
super(HOME_WIDTH);
occupied = false;
}
/**
* Determines if this home is occupoied.
*
* @return true if and only if this home is occupied
*/
public boolean isOccupied()
{
return occupied;
}
/**
* Sets this home to occupied.
*/
public void setOccupied()
{
occupied = true;
}
}
Lane.java
import java.util.*;
/**
* A horizontal lane of traffic. "Traffic" in this context can mean vehicles,
* logs, or other obstacles. Lanes can be grass, roadway, or river.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Lane
{
/**
* Constants for lane types.
*/
public static final int ROAD = 0;
public static final int GRASS = 1;
public static final int RIVER = 2;
/**
* The default visible width of a lane, in frog widths.
*/
public static final int SCREEN_WIDTH = 15;
/**
* The maximum velocity of a lane, in frog widths per second.
*/
private static final double VELOCITY_MAX = 7.5;
/**
* The width of this lane, as a proportion of the screen width.
*/
private double width;
/**
* The type of this lane.
*/
private int type;
/**
* The position within this lane of the left edge of the screen.
*/
private double position;
/**
* The velocity of this lane, in screen widths per second. Positive
* velocities indicate right-to-left motion; negative velocities indicate
* left-to-right motion.
*/
private double velocity;
/**
* The obstacles in this lane.
*/
private List obstacles;
/**
* Creates an empty grass lane one screen wide. The lane will
* be stationary and will start at the left edge of the screen.
*/
public Lane()
{
this(GRASS, SCREEN_WIDTH);
}
/**
* Creates an empty grass lane of the given width. The lane will
* be stationary and will start at the left edge of the screen.
*
* @param w a <CODE>double</CODE> at least 1.0
*/
public Lane(double w)
{
this(ROAD, w);
}
/**
* Creates an empty lane of the given type. The lane will be stationary
* and will start at the left edge of the screen.
*
* @param t one of the type constants
* @param w a <CODE>double</CODE> at least 1.0
*/
public Lane(int t, double w)
{
if (w < SCREEN_WIDTH)
throw new IllegalArgumentException("Width must be at least "
+ SCREEN_WIDTH + ": "
+ w);
if (t < ROAD || t > RIVER)
throw new IllegalArgumentException("Invalid lane type: " + t);
width = w;
type = t;
velocity = 0.0;
position = 0.0;
obstacles = new ArrayList();
}
/**
* Returns the type of this lane.
*
* @return the type of this lane
*/
public int getType()
{
return type;
}
/**
* Returns the velocity of this lane.
*
* return the velocity of this lane
*/
public double getVelocity()
{
return velocity;
}
/**
* Sets the velocity of this lane. The velocity is givenin screen widths
* per second, with positive values for leftward movement and negative
* values for rightward movement.
*
* @param v the new speed of this lane
* @throws IllegalArgumentException if the magnitude of v is greater than
* the maximum allowable
*/
public void setVelocity(double v)
{
if (Math.abs(v) > getMaximumVelocity())
{
throw new IllegalArgumentException("invalid velocity: " + v);
}
velocity = v;
}
/**
* Returns the maximum velocity for any lane.
*
* @return the maximum velocity
*/
public static double getMaximumVelocity()
{
return VELOCITY_MAX;
}
/**
* Creates a river lane with evenly spaced logs.
* The number of logs is determined by the argument. The spaces
* between the logs will be the same size as the logs. The width
* of the lane will be exactly one screen.
*
* @param n a positive integer
* @return a lane with n logs
*/
public static Lane makeLogLane(int n)
{
if (n <= 0)
throw new IllegalArgumentException("n must be positive: " + n);
Lane l = new Lane(RIVER, SCREEN_WIDTH);
double logWidth = (double)SCREEN_WIDTH / (2 * n);
for (int i = 0; i < n; i++)
l.addObstacle(new Log(logWidth), logWidth * i * 2);
return l;
}
/**
* Adds the given obstacle to this lane at the given position.
*
* @param o an obstacle compatible with this lane
* @param p a position within this lane
*
* @throws IllegalArgumentException if the obstacle is not appropriate
* for this lane or will not fit at the given position
*/
public void addObstacle(Obstacle o, double p)
{
if (type == GRASS && !(o instanceof Home))
throw new IllegalArgumentException("Only homes allowed on grass");
else if (type == ROAD && !(o instanceof Vehicle))
throw new IllegalArgumentException("Only vehicles allowed on road");
else if (type == RIVER && !(o instanceof Floater))
throw new IllegalArgumentException("Only floating obstacles allowed in river");
if (p < 0.0 || p + o.getWidth() > width)
throw new IllegalArgumentException("Obstacle does not fit in lane:"
+ "(" + p + ", " + (p + o.getWidth()) + ") "
+ width);
obstacles.add(new Pair(o, new Double(p)));
}
/**
* Updates this lane and everything in it.
*
* @param t the time since the last update, in seconds
*/
public void update(double t)
{
// update position
position += t * velocity;
if (position >= width)
position -= (int)(position / width) * width;
else if (position < 0.0)
position += ((int)(-position / width) + 1) * width;
// update obstacles in this lane
Iterator i = obstacles.iterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
o.update(t);
}
// update animals in this lane
// check for appearance of new animals
}
/**
* Finds the home overlapping the given position in this lane.
*
* @param x1 the left edge of the area to check for overlap with a home
* @param x2 the right edge of the area to check for overlap with a home
* @return the home overlapping that area, or <CODE>null</CODE>
*/
public Home findHome(double x1, double x2)
{
// we take advantage of the fact that the home lane doesn't move
// so we don't have to worry about wraparound
Iterator i = obstacles.iterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
if (o instanceof Home)
{
double homePos = ((Double)(p.getSecond())).doubleValue();
if (x1 >= homePos && x2 <= homePos + o.getWidth())
return (Home)o;
}
}
return null;
}
/**
* Determines if this lane has a log at the given position.
*
* @param x the x position, relative to the edge of the screen
* @return true if and only if this lane has a log at that position
*/
public boolean hasFloaterAt(double x)
{
if (type != RIVER)
return false;
x += position;
if (x > width)
x -= width;
Iterator i = obstacles.iterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
double obstaclePos = ((Double)(p.getSecond())).doubleValue();
if (x >= obstaclePos
&& x <= obstaclePos + o.getWidth()
&& o instanceof Floater
&& ((Floater)o).isAboveWater())
return true;
}
return false;
}
/**
* Determines if there is a collision in this lane between the
* object between the given points and a lethal obstacle.
* Positions are given relative to the edge of the screen.
*
* @param x1 the left edge of the area to check for collisions in
* @param x2 the right edge of the area to check for collisions in
*/
public boolean hasCollision(double x1, double x2)
{
return hasCollisionLaneCoordinates(x1 + position, x2 + position);
}
/**
* Determines if there is a collision in this lane between the
* object between the given points and a lethal obstacle.
* Positions are given relative to the edge of this lane
*
* @param x1 the left edge of the area to check for collisions in
* @param x2 the right edge of the area to check for collisions in
*/
private boolean hasCollisionLaneCoordinates(double x1, double x2)
{
if (x1 > width)
{
x1 -= width;
x2 -= width;
}
if (x2 > width)
{
return (hasCollisionLaneCoordinates(x1, width)
|| hasCollisionLaneCoordinates(0.0, x2 - width));
}
else
{
Iterator i = obstacles.iterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
double obsLeft = ((Double)(p.getSecond())).doubleValue();
double obsRight = obsLeft + o.getWidth();
if (o.isLethal()
&& ((x1 < obsLeft && x2 > obsRight)
|| (x1 > obsLeft && x1 < obsRight)
|| (x2 > obsLeft && x2 < obsRight)))
{
return true;
}
}
return false;
}
}
/**
* Returns an iterator over all the visible obstacles in this lane.
* Obstacles will be visible if any portion of them is currently
* positioned between 0.0 and the width of the screen.
* Obstacles may be iterated over
* twice if they are visible at both edges of the screen.
* The iterator will return (obstacle, position) pairs, where the
* position is relative to the edge of the screen.
*
* @return an iterator over this lane's obstacles
*/
public Iterator obstacleIterator()
{
// create a list of visible obstacles
List visible = new LinkedList();
// get position within this lane of the left and right edges
// of the screen -- we must do the wraparound carefully:
// screenLeft + visibleWidth - width may come out >
// screenLeft, in which case we think there's only a tiny
// sliver visible and nothing gets painted
double screenLeft = position;
double screenRight = screenLeft + SCREEN_WIDTH;
if (screenRight > width)
screenRight = screenLeft + (SCREEN_WIDTH - width);
Iterator i = obstacles.iterator();
while (i.hasNext())
{
Pair p = (Pair)(i.next());
Obstacle o = (Obstacle)(p.getFirst());
double obsLeft = ((Double)(p.getSecond())).doubleValue();
double obsRight = obsLeft + o.getWidth();
if (screenLeft < screenRight)
{
// no wraparound -- obstacle is visible exactly once
// if either end is on screen
if ((obsLeft > screenLeft && obsLeft < screenRight)
|| (obsRight > screenLeft && obsRight < screenRight))
visible.add(new Pair(o, new Double(obsLeft - screenLeft)));
}
else
{
// wrapround -- obstacle is entirely visible
// if its left is > screen left, visible on the
// left edge if its right is > screen left
// and (possibly also) on the right edge if
// its left edge < screen right
if (obsLeft > screenLeft)
visible.add(new Pair(o, new Double(obsLeft - screenLeft)));
else
{
if (obsRight > screenLeft)
visible.add(new Pair(o, new Double(obsLeft - screenLeft)));
if (obsLeft < screenRight)
visible.add(new Pair(o, new Double(obsLeft + width - screenLeft)));
}
}
}
// return an iterator over the list
return visible.iterator();
}
}
Level.java
import java.util.*;
/**
* A Calaveras Crossing level. Each Calaveras Crossing level has 13
* lanes, including the starting lane and the home lane.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Level
{
/**
* The number of lanes per level, including the starting lane and the
* home lane.
*/
public static final int NUM_LANES = 13;
/**
* The number of homes in a level.
*/
public static final int NUM_HOMES = 5;
/**
* The lanes in this level.
*/
private Lane[] lanes;
/**
* Create a new level with 12 empty grass lanes and the home lane.
*/
public Level()
{
lanes = new Lane[NUM_LANES];
// create empty lanes of grass
for (int l = 1; l < NUM_LANES; l++)
{
lanes[l] = new Lane();
}
// create home lane
Lane homeLane = new Lane();
// compute home spacing so that homes are evenly spaced at
// positions that are integer multiples of frog widths;
// this assumes that the screen is at least 5 frogs wide.
int spacing = 0;
while (NUM_HOMES * (spacing + 1) - 1 <= Lane.SCREEN_WIDTH)
{
spacing++;
}
// compute position of 1st home that centers things
double firstHome = (Lane.SCREEN_WIDTH / 2 - (Home.HOME_WIDTH - 1.0) / 2) - (NUM_HOMES / 2 * spacing);
for (int h = 0; h < NUM_HOMES; h++)
{
homeLane.addObstacle(new Home(), firstHome + h * spacing);
}
lanes[0] = homeLane;
}
/**
* Adds the given lane to this level at the given position. Lanes
* are numbered from top to bottom starting with 0 for the niche lane.
*
* @param l a lane
* @param p lane position
*/
public void addLane(Lane l, int p)
{
if (l == null)
throw new IllegalArgumentException("null lane");
if (p < 0 || p >= NUM_LANES)
throw new IllegalArgumentException("Invalid lane index: " + p);
if (p == NUM_LANES - 1)
throw new IllegalArgumentException("Can't replace home lane: " + p);
lanes[p] = l;
}
/**
* Returns the number of lanes in this level. In the current
* implementation all levels have 13 lanes.
*
* @return the number of lanes in this level
*/
public int countLanes()
{
return NUM_LANES;
}
/**
* Returns the lane at the given position in this level.
*
* @param p a lane index
*/
public Lane getLane(int p)
{
if (p < 0 || p >= NUM_LANES)
throw new IllegalArgumentException("Invalid lane index: " + p);
return lanes[p];
}
/**
* Updates this level and everything in it.
*
* @param t the time since the last update
*/
public void update(double t)
{
for (int l = 0; l < NUM_LANES; l++)
lanes[l].update(t);
}
/**
* Returns an iterator over this level's lanes.
*
* @return an iterator over this level's lanes
*/
public Iterator laneIterator()
{
return new LaneIterator();
}
/**
* An iterator over this level's lanes.
*/
private class LaneIterator implements Iterator
{
/**
* The index of the lane this iterator is currently positioned before.
*/
private int index;
/**
* Creates an iterator positioned before this level's first lane.
*/
public LaneIterator()
{
index = 0;
}
/**
* Determines if this iterator has a next lane to iterate over.
*/
public boolean hasNext()
{
return (index < NUM_LANES);
}
/**
* Returns the next lane this iterator iterates over and positions
* this iterator just after that lane.
*/
public Object next()
{
if (!hasNext())
throw new IllegalStateException("no next lane: " + index);
index++;
return lanes[index - 1];
}
/**
* Unsupported.
*
* @throws UnsupportedOperationException
*/
public void remove()
{
throw new UnsupportedOperationException();
}
}
}
Log.java
/**
* A Calaveras Crossing log.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class Log extends Floater
{
/**
* Creates a new obstacle of the given width.
*
* @param w a positive <CODE>double</CODE>
*/
public Log(double w)
{
super(w);
}
}
Obstacle.java
/**
* A Calaveras Crossing obstacle. Obstacles include vehicles, logs,
* and turtles. Otters, snakes, and other frogs are not obstacles.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class Obstacle
{
/**
* The width of this obstacle, measured in frog widths.
*/
private double width;
/**
* Creates a new obstacle of the given width.
*
* @param w a positive <CODE>double</CODE>
*/
public Obstacle(double w)
{
if (w <= 0.0)
throw new IllegalArgumentException("Width must be positive:" + w);
width = w;
}
/**
* Returns the width of this obstacle.
*
* @return the width of this obstacle
*/
public double getWidth()
{
return width;
}
/**
* Updates this obstacle. The default implementation does nothing.
*
* @param t the time sine the last update, in seconds
*/
public void update(double t)
{
}
/**
* Determines if this obstacle is lethal to the touch.
*/
public boolean isLethal()
{
return false;
}
}
Pair.java
/**
* An ordered pair of objects.
*
* @author Jim Glenn
* @version 0.1 8/8/2003
*/
public class Pair
{
/**
* The two objects in this pair.
*/
Object x, y;
/**
* Constructs the given ordered pair.
*
* @param first the first component of the new pair
* @param second the second component of the new pair
*/
public Pair(Object first, Object second)
{
x = first;
y = second;
}
/**
* Returns the first component of this pair.
*
* @return the first component of this pair
*/
public Object getFirst()
{
return x;
}
/**
* Returns the second component of this pair.
*
* @return the second component of this pair
*/
public Object getSecond()
{
return y;
}
/**
* Sets the first component of this pair to the given value.
*
* @param obj the new first component
*/
public void setFirst(Object obj)
{
x = obj;
}
/**
* Sets the second component of this pair to the given value.
*
* @param obj the new second component
*/
public void setSecond(Object obj)
{
y = obj;
}
/**
* Returns a printable representation of this pair.
*
* @return a printable representation of this pair
*/
public String toString()
{
return "(" + x + ", " + y + ")";
}
}
Racecar.java
/**
* A Calaveras Crossing racecar.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Racecar extends Vehicle
{
/**
* The width of a racecar, in frog widths.
*/
private static final double RACECAR_WIDTH = 1.25;
/**
* Creates a new racecar.
*/
public Racecar()
{
super(RACECAR_WIDTH);
}
}
Tractor.java
/**
* A Calaveras Crossing tractor.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Tractor extends Vehicle
{
/**
* The width of a tractor, in frog widths.
*/
private static final double TRACTOR_WIDTH = 1.25;
/**
* Creates a new tractor.
*/
public Tractor()
{
super(TRACTOR_WIDTH);
}
}
Truck.java
/**
* A Calaveras Crossing truck.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Truck extends Vehicle
{
/**
* The width of a truck, in frog widths.
*/
private static final double TRUCK_WIDTH = 2.5;
/**
* Creates a new truck.
*/
public Truck()
{
super(TRUCK_WIDTH);
}
}
Turtles.java
/**
* A group of Calaveras Crossing turtles.
*
* @author Jim Glenn
* @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
* @version 0.1 10/7/2008
*/
public class Turtles extends Floater
{
/**
* The width of a single turtle, in frog widths.
*/
private static final double TURTLE_WIDTH = 1.0;
/**
* The number of turtles in this group.
*/
private int num;
/**
* A flag that is true if and only if this group of turtles dives.
*/
private boolean diving;
/**
* The length of time these turtles spend above water and then
* underwater if they are diving.
*/
private double diveTime;
/**
* The time within the current dive cycle. Times in the first half are
* above water and times in the second half are below.
*/
private double cycleTime;
/**
* Creates a new group with the given number of non-diving turtles in it.
*
* @param n a positive integer
*/
public Turtles(int n)
{
super(TURTLE_WIDTH * n);
diving = false;
diveTime = 1.0;
cycleTime = 0.0;
num = n;
}
/**
* Returns the number of turtles in this group.
*
* @return the number of turtles in this group
*/
public int getCount()
{
return num;
}
/**
* Sets the diving status of this group of turtles.
*
* @param flag true to set these turtles to diving
*/
public void setDiving(boolean flag)
{
diving = flag;
}
/**
* Determines whether these turtles dive. This method
* determines if these turtles have a dive cycle, not whether they
* are currently in the dive phase of their cycle. To determine if
* these turtles are currently underwater use <CODE>isAboveWater</CODE>
* or <TT>getDepth</TT>.
*
* @return true if and only if these turtles dive
*/
public boolean canDive()
{
return diving;
}
/**
* Sets the dive time for these turtles. The dive time is
* 1.0 by default. There is no effect on non-diving turtles.
*
* @param t a positive number
*/
public void setDiveTime(double t)
{
if (t <= 0.0)
throw new IllegalArgumentException("Dive time must be positive: "
+ t);
diveTime = t;
}
/**
* Updates this obstacle. The default implementation does nothing.
*
* @param t the time sine the last update, in seconds
*/
public void update(double t)
{
// update cycle time
cycleTime += t;
// and move to beginning of next cycle if necessary (this formula
// takes into account cases where an update is not performed
// for an entire cycle
if (cycleTime > 2 * diveTime)
cycleTime -= (int)(cycleTime / (2 * diveTime)) * (2 * diveTime);
}
/**
* Determines if these turtles are above water.
*
* @return true if and only if these turtles are currently above water
*/
public boolean isAboveWater()
{
return (!diving || cycleTime <= diveTime);
}
/**
* Returns the current depth of these turtles. The value returned will
* be between -1.0 and 1.0 for diving turtles and 1.0 for non-diving turtles.
*
* @return a number between 1.0 and 1.0
*/
public double getDepth()
{
if (diving)
{
return Math.sin(Math.PI * cycleTime / diveTime);
}
else
{
return 1.0;
}
}
}
Vehicle.java
/**
* A CalaverasCrossing vehicle.
*
* @author Jim Glenn
* @version 0.1 10/7/2008
*/
public class Vehicle extends Obstacle
{
/**
* Creates a new vehicle of the given width.
*
* @param w a positive <CODE>double</CODE>
*/
public Vehicle(double w)
{
super(w);
}
/**
* Determines if this vehicle is lethal to the touch.
*/
public boolean isLethal()
{
return true;
}
}
This code can also be downloaded from the files
CalaverasCrossingApplet.java,
CalaverasCrossingControl.java,
CalaverasCrossingGame.java,
CalaverasCrossingPainter.java,
CalaverasCrossingPanel.java,
CalaverasCrossingWindow.java,
Car.java,
Floater.java,
Frog.java,
Home.java,
Lane.java,
Level.java,
Log.java,
Obstacle.java,
Pair.java,
Racecar.java,
Tractor.java,
Truck.java,
Turtles.java,
and Vehicle.java.