在开始之前,我知道我应该使用 Swing 而不是 AWT,但这是我正在使用的书所教的内容,所以我现在就继续使用它。
现在,我的问题是为什么 AppletViewer 可以很好地运行此代码,但我尝试过的每个浏览器(Chrome、Firefox、IE)都会引发以下错误:
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)
银河战争.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());
}
}
我知道代码似乎找不到 spaceship1.png,但我向您保证它就在那里。为什么代码可以在 AppletViewer 中编译并完全正常工作,但只在浏览器中抛出此异常?