1

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?

Rick_Sch
  • 456
  • 3
  • 10
  • 19
  • @AndrewThompson Read my first sentence :) I posted a question about applets a few days ago and got quite an education from you already about Swing vs. AWT, which I thoroughly appreciated, but until I finish with this book, I won't be using it. Thank you again though. – Rick_Sch Jun 20 '13 at 04:03
  • 1
    *"..AWT, but this is what the book I'm using teaches with, so I'm just going with it for now."* That book is good as a paperweight, or maybe for a fire. Stop using it sooner rather than later. – Andrew Thompson Jun 20 '13 at 04:05
  • @John3136 That can't be it. Doing that just generates **many** errors. The error at hand has to do with trying to load the spaceship1.png image. – Rick_Sch Jun 20 '13 at 04:06
  • 1
    *..Read my first sentence :)"* Yes, my silly. :P – Andrew Thompson Jun 20 '13 at 04:06
  • "I know I should be using Swing..." No. Please don't use Swing. Please? –  Jun 20 '13 at 04:07
  • Try changing `ship.load("spaceship1.png");` to `ship.load("/spaceship1.png");` – Marlon Bernardes Jun 20 '13 at 04:07
  • 1
    BTW: See this answer on [Swing extras over AWT](http://stackoverflow.com/a/6255978/418556) for many good reasons to *abandon* using AWT components. – Andrew Thompson Jun 20 '13 at 04:08
  • @MarlonBernardes No luck. Thanks though! – Rick_Sch Jun 20 '13 at 04:14
  • @ConnerDouglass Sarcasm? Or no? – Rick_Sch Jun 20 '13 at 04:14
  • @Rick_Sch I'm being completely serious. Swing is a dead windowing framework. I mean, maybe not dead, but how many applications do you use that were built on Swing? Java is cool for lots of things, but it hasn't taken the desktop world by storm as Swing was an attempt at doing. –  Jun 20 '13 at 04:22
  • @ConnerDouglass I'm making an applet though. Any better suggestions? – Rick_Sch Jun 20 '13 at 04:27
  • @Rick_Sch For applets, I think Swing is just fine. But Swing as a whole has some design flaws. I'd stick with what you're using as it'll teach you a lot (When I started Java, I used applets for a few years) –  Jun 20 '13 at 04:31

1 Answers1

2

Turns out the error is caused by Java 7_25 which I downloaded earlier today. The new version apparently has trouble loading applets, or at least applets loaded from local files. I've submitted a bug report to Oracle and have reverted back to 7_21.

That was a lot of trouble for no reason...

Rick_Sch
  • 456
  • 3
  • 10
  • 19