Before I begin, I know I should be using Swing rather than AWT, but this is what the book I'm using teaches with, so I'm just going with it for now.
Now, my question is why the AppletViewer runs this code just fine, but every browser I've tried (Chrome, Firefox, IE) throws the following error:
java.lang.NullPointerException
at ImageEntity.load(ImageEntity.java:61)
at GalacticWar.init(GalacticWar.java:55)
at com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source)
at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
GalacticWar.java
/*****************************************************
* Beginning Java Game Programming, 2nd Edition
* by Jonathan S. Harbour
* GALACTIC WAR, Chapter 11
*****************************************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
/*****************************************************
* Primary class for the game
*****************************************************/
public class GalacticWar extends Applet implements Runnable, KeyListener {
//the main thread becomes the game loop
Thread gameloop;
//use this as a double buffer
BufferedImage backbuffer;
//the main drawing object for the back buffer
Graphics2D g2d;
//toggle for drawing bounding boxes
boolean showBounds = false;
//create the asteroid array
int ASTEROIDS = 20;
Asteroid[] ast = new Asteroid[ASTEROIDS];
//create the bullet array
int BULLETS = 10;
Bullet[] bullet = new Bullet[BULLETS];
int currentBullet = 0;
//the player's ship
ImageEntity ship = new ImageEntity(this);
//create the identity transform
AffineTransform identity = new AffineTransform();
//create a random number generator
Random rand = new Random();
/*****************************************************
* applet init event
*****************************************************/
public void init() {
//create the back buffer for smooth graphics
backbuffer = new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);
g2d = backbuffer.createGraphics();
//set up the ship
ship.setX(320);
ship.setY(240);
ship.load("spaceship1.png");
ship.setGraphics(g2d);
//set up the bullets
for (int n = 0; n<BULLETS; n++) {
bullet[n] = new Bullet();
}
//set up the asteroids
for (int n = 0; n<ASTEROIDS; n++) {
ast[n] = new Asteroid();
ast[n].setRotationVelocity(rand.nextInt(3)+1);
ast[n].setX((double)rand.nextInt(600)+20);
ast[n].setY((double)rand.nextInt(440)+20);
ast[n].setMoveAngle(rand.nextInt(360));
double ang = ast[n].getMoveAngle() - 90;
ast[n].setVelX(calcAngleMoveX(ang));
ast[n].setVelY(calcAngleMoveY(ang));
}
//start the user input listener
addKeyListener(this);
}
/*****************************************************
* applet update event to redraw the screen
*****************************************************/
public void update(Graphics g) {
//start off transforms at identity
g2d.setTransform(identity);
//erase the background
g2d.setPaint(Color.BLACK);
g2d.fillRect(0, 0, getSize().width, getSize().height);
//print some status information
g2d.setColor(Color.WHITE);
g2d.drawString("Ship: " + Math.round(ship.getX()) + "," +
Math.round(ship.getY()) , 5, 10);
g2d.drawString("Move angle: " + Math.round(
ship.getMoveAngle())+90, 5, 25);
g2d.drawString("Face angle: " + Math.round(
ship.getFaceAngle()), 5, 40);
//draw the game graphics
drawShip();
drawBullets();
drawAsteroids();
//repaint the applet window
paint(g);
}
/*****************************************************
* drawShip called by applet update event
*****************************************************/
public void drawShip() {
// set the transform for the image
ship.transform();
ship.draw();
//draw bounding rectangle around ship
if (showBounds) {
g2d.setTransform(identity);
g2d.setColor(Color.BLUE);
g2d.draw(ship.getBounds());
}
}
/*****************************************************
* drawBullets called by applet update event
*****************************************************/
public void drawBullets() {
for (int n = 0; n < BULLETS; n++) {
if (bullet[n].isAlive()) {
//draw the bullet
g2d.setTransform(identity);
g2d.translate(bullet[n].getX(), bullet[n].getY());
g2d.setColor(Color.MAGENTA);
g2d.draw(bullet[n].getShape());
}
}
}
/*****************************************************
* drawAsteroids called by applet update event
*****************************************************/
public void drawAsteroids() {
for (int n = 0; n < ASTEROIDS; n++) {
if (ast[n].isAlive()) {
//draw the asteroid
g2d.setTransform(identity);
g2d.translate(ast[n].getX(), ast[n].getY());
g2d.rotate(Math.toRadians(ast[n].getMoveAngle()));
g2d.setColor(Color.DARK_GRAY);
g2d.fill(ast[n].getShape());
//draw bounding rectangle
if (showBounds) {
g2d.setTransform(identity);
g2d.setColor(Color.BLUE);
g2d.draw(ast[n].getBounds());
}
}
}
}
/*****************************************************
* applet window repaint event--draw the back buffer
*****************************************************/
public void paint(Graphics g) {
g.drawImage(backbuffer, 0, 0, this);
}
/*****************************************************
* thread start event - start the game loop running
*****************************************************/
public void start() {
gameloop = new Thread(this);
gameloop.start();
}
/*****************************************************
* thread run event (game loop)
*****************************************************/
public void run() {
//acquire the current thread
Thread t = Thread.currentThread();
//keep going as long as the thread is alive
while (t == gameloop) {
try {
Thread.sleep(20);
}
catch(InterruptedException e) {
e.printStackTrace();
}
//update the game loop
gameUpdate();
repaint();
}
}
/*****************************************************
* thread stop event
*****************************************************/
public void stop() {
gameloop = null;
}
/*****************************************************
* move and animate the objects in the game
*****************************************************/
private void gameUpdate() {
updateShip();
updateBullets();
updateAsteroids();
checkCollisions();
}
/*****************************************************
* Update the ship position based on velocity
*****************************************************/
public void updateShip() {
//update ship's X position, wrap around left/right
ship.incX(ship.getVelX());
if (ship.getX() < -10)
ship.setX(getSize().width + 10);
else if (ship.getX() > getSize().width + 10)
ship.setX(-10);
//update ship's Y position, wrap around top/bottom
ship.incY(ship.getVelY());
if (ship.getY() < -10)
ship.setY(getSize().height + 10);
else if (ship.getY() > getSize().height + 10)
ship.setY(-10);
}
/*****************************************************
* Update the bullets based on velocity
*****************************************************/
public void updateBullets() {
//move the bullets
for (int n = 0; n < BULLETS; n++) {
if (bullet[n].isAlive()) {
//update bullet's x position
bullet[n].incX(bullet[n].getVelX());
//bullet disappears at left/right edge
if (bullet[n].getX() < 0 ||
bullet[n].getX() > getSize().width)
{
bullet[n].setAlive(false);
}
//update bullet's y position
bullet[n].incY(bullet[n].getVelY());
//bullet disappears at top/bottom edge
if (bullet[n].getY() < 0 ||
bullet[n].getY() > getSize().height)
{
bullet[n].setAlive(false);
}
}
}
}
/*****************************************************
* Update the asteroids based on velocity
*****************************************************/
public void updateAsteroids() {
//move and rotate the asteroids
for (int n = 0; n < ASTEROIDS; n++) {
if (ast[n].isAlive()) {
//update the asteroid's X value
ast[n].incX(ast[n].getVelX());
if (ast[n].getX() < -20)
ast[n].setX(getSize().width + 20);
else if (ast[n].getX() > getSize().width + 20)
ast[n].setX(-20);
//update the asteroid's Y value
ast[n].incY(ast[n].getVelY());
if (ast[n].getY() < -20)
ast[n].setY(getSize().height + 20);
else if (ast[n].getY() > getSize().height + 20)
ast[n].setY(-20);
//update the asteroid's rotation
ast[n].incMoveAngle(ast[n].getRotationVelocity());
if (ast[n].getMoveAngle() < 0)
ast[n].setMoveAngle(360 - ast[n].getRotationVelocity());
else if (ast[n].getMoveAngle() > 360)
ast[n].setMoveAngle(ast[n].getRotationVelocity());
}
}
}
/*****************************************************
* Test asteroids for collisions with ship or bullets
*****************************************************/
public void checkCollisions() {
//check for ship and bullet collisions with asteroids
for (int m = 0; m<ASTEROIDS; m++) {
if (ast[m].isAlive()) {
//check for bullet collisions
for (int n = 0; n < BULLETS; n++) {
if (bullet[n].isAlive()) {
//perform the collision test
if (ast[m].getBounds().contains(
bullet[n].getX(), bullet[n].getY()))
{
bullet[n].setAlive(false);
ast[m].setAlive(false);
continue;
}
}
}
//check for ship collision
if (ast[m].getBounds().intersects(ship.getBounds())) {
ast[m].setAlive(false);
ship.setX(320);
ship.setY(240);
ship.setFaceAngle(0);
ship.setVelX(0);
ship.setVelY(0);
continue;
}
}
}
}
/*****************************************************
* key listener events
*****************************************************/
public void keyReleased(KeyEvent k) { }
public void keyTyped(KeyEvent k) { }
public void keyPressed(KeyEvent k) {
int keyCode = k.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_LEFT:
//left arrow rotates ship left 5 degrees
ship.incFaceAngle(-5);
if (ship.getFaceAngle() < 0) ship.setFaceAngle(360-5);
break;
case KeyEvent.VK_RIGHT:
//right arrow rotates ship right 5 degrees
ship.incFaceAngle(5);
if (ship.getFaceAngle() > 360) ship.setFaceAngle(5);
break;
case KeyEvent.VK_UP:
//up arrow adds thrust to ship (1/10 normal speed)
ship.setMoveAngle(ship.getFaceAngle() - 90);
ship.incVelX(calcAngleMoveX(ship.getMoveAngle()) * 0.1);
ship.incVelY(calcAngleMoveY(ship.getMoveAngle()) * 0.1);
//********* if (!thrust.getClip().isActive())
//**** thrust.play();
break;
//Ctrl, Enter, or Space can be used to fire weapon
case KeyEvent.VK_CONTROL:
case KeyEvent.VK_ENTER:
case KeyEvent.VK_SPACE:
//fire a bullet
currentBullet++;
if (currentBullet > BULLETS - 1) currentBullet = 0;
bullet[currentBullet].setAlive(true);
//point bullet in same direction ship is facing
bullet[currentBullet].setX(ship.getCenterX());
bullet[currentBullet].setY(ship.getCenterY());
bullet[currentBullet].setMoveAngle(ship.getFaceAngle() - 90);
//fire bullet at angle of the ship
double angle = bullet[currentBullet].getMoveAngle();
double svx = ship.getVelX();
double svy = ship.getVelY();
bullet[currentBullet].setVelX(svx + calcAngleMoveX(angle) * 2);
bullet[currentBullet].setVelY(svy + calcAngleMoveY(angle) * 2);
break;
case KeyEvent.VK_B:
//toggle bounding rectangles
showBounds = !showBounds;
break;
}
}
/*****************************************************
* calculate X movement value based on direction angle
*****************************************************/
public double calcAngleMoveX(double angle) {
double movex = Math.cos(angle * Math.PI / 180);
return movex;
}
/*****************************************************
* calculate Y movement value based on direction angle
*****************************************************/
public double calcAngleMoveY(double angle) {
double movey = Math.sin(angle * Math.PI / 180);
return movey;
}
}
ImageEntity.java
/*********************************************************
* Base game image class for bitmapped game entities
**********************************************************/
import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.*;
import java.applet.*;
import java.net.*;
public class ImageEntity extends BaseGameEntity {
//variables
private Image image;
private Applet applet;
private AffineTransform at;
private Graphics2D g2d;
//default constructor
ImageEntity(Applet a) {
applet = a;
setImage(null);
setAlive(true);
}
//sets and returns the entity's image object
public Image getImage() { return image; }
public void setImage(Image image) { this.image = image; }
//returns the width and height of the entity
public int width() {
return getImage().getWidth(applet);
}
public int height() {
return getImage().getHeight(applet);
}
//returns the center of the entity in pixels
public double getCenterX() {
return getX() + width() / 2;
}
public double getCenterY() {
return getY() + height() / 2;
}
//set reference to the drawing object
public void setGraphics(Graphics2D g) {
g2d = g;
}
private URL getURL(String filename) {
URL url = null;
try {
url = this.getClass().getResource(filename);
}
catch (Exception e) { }
return url;
}
//load an image file
public void load(String filename) {
setImage(applet.getImage(getURL(filename)));
while(getImage().getWidth(applet) <= 0);
double x = applet.getSize().width/2 - width()/2;
double y = applet.getSize().height/2 - height()/2;
at = AffineTransform.getTranslateInstance(x, y);
}
//move and rotate the entity
public void transform() {
at.setToIdentity();
at.translate((int)getX() + width()/2, (int)getY() + height()/2);
at.rotate(Math.toRadians(getFaceAngle()));
at.translate(-width()/2, -height()/2);
}
//draw the entity
public void draw() {
g2d.drawImage(getImage(), at, applet);
}
//bounding rectangle
public Rectangle getBounds() {
return new Rectangle((int)getX(),(int)getY(),width(),height());
}
}
I understand that it seems as if the code can't find spaceship1.png, but I assure you it's there. Why would the code compile and work completely fine in AppletViewer, but then throw this exception only in the browsers?