无法在main中启动Thread,但文件编译成功

时间:2014-05-06 16:24:08

标签: java multithreading applet runnable

我正试图通过“开始Java SE 6游戏编程”这本书。我有一些以前的Java经验,但我从未遇到过Runnable接口。本书的第三章展示了一个简单的小行星游戏,几乎所有需要的代码。作者没有提供main()方法,我自己尝试的所有内容最终都成功编译但无所事事或有错误。

Asteroids.java文件的代码有近400行,可能只有init(),start()和run()方法是最重要的,但我会粘贴所有这些。

package asteroids;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;


public class Asteroids 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 new bullet array
    int BULLETS = 10;
    Bullet[] bullet = new Bullet[BULLETS];
    int currentBullet = 0;

    //the player's ship
    Ship ship = new Ship();

    //create the identity transform(0,0)
    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();

        //det up the ship
        ship.setX(320);
        ship.setY(240);

        //set up the bullets
        for(int n = 0 ; n < BULLETS ; n++)
        {
            bullet[n] = new Bullet();
        }

        //create the asteroid
        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 transform 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 g raphics
        drawShip();
        drawBullets();
        drawAsteroids();

        //repaint the applet window
        paint(g);
    }

    //drawShip called by applet update event
    public void drawShip(){
        g2d.setTransform(identity);
        g2d.translate(ship.getX(), ship.getY());
        g2d.rotate(Math.toRadians(ship.getFaceAngle()));
        g2d.setColor(Color.ORANGE);
        g2d.fill(ship.getShape());
    }

    //drawBullets called by applet update event
    public void drawBullets(){
        //iterate through the array of bullets
        for(int n = 0 ; n < BULLETS ; n++)
        {
            //is this bullet currently in use?
            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(){
        //iterate through the asteroids array
        for(int n = 0 ; n < ASTEROIDS ; n++)
        {
            //is this asterois currently in use?
            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());
            }            
        }
    }

    //applet window repaint event - - draw the back buffer
    public void paint(Graphics g){
        //draw the back buffer onto the applet window
        g.drawImage(backbuffer, 0, 0, this);
    }


    //thread start event - start the game loop running
    public void start(){
        //create the gameloop thread for real-time updates
        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{
                //update game loop
                gameUpdate();

                //target framerate is 50 fps
                Thread.sleep(20);
            }
            catch(InterruptedException e){
                e.printStackTrace();
            }
            repaint();
            }
        }
    //thread stop event
    public void stop(){
        //kill the gameloop thread
        gameloop = null;
    }

    //move and animate 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
        ship.incX(ship.getVelX());

        //wrap around left/right
        if(ship.getX() < -10)
            ship.setX(getSize().width+10);
        else if(ship.getX() > getSize().width + 10)
            ship.setX(-10);

        //update ship's Y position
        ship.incY(ship.getVelY());

        //wrap around top/bottom
        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 each of the bullets
        for(int n = 0 ; n < BULLETS ; n++)
        {
            //is the bullet alive?
            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 asteroids based on velocity
    public void updateAsteroids(){
        //move and rotate the asteroids
        for(int n = 0 ; n < ASTEROIDS ; n++)
        {
            //is this asteroid being used?
            if(ast[n].isAlive()){
                //update this asteroid's X value
                ast[n].incX(ast[n].getVelX());

                //warp the asteroid at screen edges
                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());

                //warp the asteroid at screen edges
                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());

                //keep the angle within 0-359 degrees
                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(){

        //iterate through the asteroids array
        for(int m = 0 ; m < ASTEROIDS ; m++)
        {
            //is this asteroid being used
            if(ast[m].isAlive())
            {
                //check for collisions with bullet
                for(int n = 0 ; n < BULLETS; n++)
                {
                    //is this bullet being used?
                    if(bullet[n].isAlive())
                    {
                        //perform collision test
                        if(ast[m].getBounds().contains(
                            bullet[n].getX(), bullet[n].getY()))
                                {
                                    bullet[n].setAlive(false);
                                    ast[m].setAlive(false);
                                    continue;
                                }
                    }
                }
            }

            //check for collision with ship
            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);

                //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.getX());
                bullet[currentBullet].setY(ship.getY());
                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;
        }
    }

        //calculate X movement value based on direction angle
        public double calcAngleMoveX(double angle){
            return (double)(Math.cos(angle * Math.PI / 180));
        }

        //calculate Y movement value based on direction able
        public double calcAngleMoveY(double angle){
            return (double)(Math.sin(angle * Math.PI / 180));
        }

}

我知道在最后一个括号之前应该有一个main()方法。以下是我尝试过的几个例子。

public static void main(String[] args) {

            Asteroids a = new Asteroids();
            a.init();
            a.run();
           }

建立成功,没有任何反应。我猜这应该是一个命令,而不是两个单独的命令?我也不确定是应该在Asteroids对象上调用.run()或.init()方法,还是在线程的实例上调用?

public static void main(String[] args) {

            Thread t = new Thread(new Asteroids());
            t.run();
           }

再次,建立成功,没有任何反应。另一个猜测是,因为我已经有一个start()方法,它创建了一个新的Thread,我应该在一个新的Asteroids()对象上调用它,但后来我得到一个NullPointerException。

我尝试了几种类似的方法,但我认为这篇文章足够长,没有展示它们。主要问题是:

  • 有了这些方法,我应该怎么称呼它们? Thread对象还是Asteroids对象?
  • 不应该是名为run()的唯一方法(因为我发现的关于Threads和Runnable接口的代码示例只使用run()方法)。
  • 如果没有,因为我在Asteroids类中有几个方法,它们应该在游戏实际运行之前按特定顺序调用吗?例如。 .start(),. init(),. run()?

我只是觉得我的知识和作者的期望之间存在巨大差距,而且,即使查看代码,我也可以看出大多数东西代表什么,它&#39我自己很难继续前进。任何提示,特定的Oracle文档,我可以通过它来掌握这个?我正在使用NetBeans进行编译。

1 个答案:

答案 0 :(得分:0)

Ok从我从你的代码中读到的内容,这是发生了什么:

   Asteroids a = new Asteroids(); // Instantiate an object for the game
   a.init(); // Init the applet for the game, add key listeners.
   a.start(); // Start the thread(its handled internally) with the game loop, which handles UI updates and game mechanics

你的第一次尝试失败,因为start()设置了一个成员属性,gameloop作为一个新线程。因此,当您手动调用runloop时,未设置gameloop,因此currentThread(t)不等于gameloop(null)。

第二次尝试因同样的原因失败,也因为applet未初始化。