Thread not behaving correctly

Posted by ivor on Stack Overflow See other posts from Stack Overflow or by ivor
Published on 2010-04-03T20:16:36Z Indexed on 2010/04/03 20:23 UTC
Read the original article Hit count: 370

Filed under:
|

Hello, I wonder if anyone can help me to understand where I could be going wrong with this code; Basically I'm working on a turorial and calling the class below from another class - and it is getting the following error;

Exception in thread "Thread-1" java.lang.NullPointerException at org.newdawn.spaceinvaders.TCPChat.run(TCPChat.java:322) at java.lang.Thread.run(Unknown Source)

I realise the error is beibg flagged in another class- but I have tested the other class with a small class which sets up a separate thread - and it works fine, but as soon as I try and implement a new thread in this class - it causes all sorts of problems. Am I setting up the thread correctly in this class?

Basically I can set up a thread in this class, with a test loop and it's fine, but when I bring in the functionality of the rest of the game it sometimes hangs, or does not display at all.

Any suggestions on where I could be going wrong would be greatly appreciated.

Thanks for looking.

package org.newdawn.spaceinvaders;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.Scanner;

import java.awt.*;//maybe not needed
import javax.swing.*;//maybenot needed

import java.util.Random;
//import java.io.*;

/**
 * The main hook of our game. This class with both act as a manager
 * for the display and central mediator for the game logic. 
 * 
 * Display management will consist of a loop that cycles round all
 * entities in the game asking them to move and then drawing them
 * in the appropriate place. With the help of an inner class it
 * will also allow the player to control the main ship.
 * 
 * As a mediator it will be informed when entities within our game
 * detect events (e.g. alient killed, played died) and will take
 * appropriate game actions.
 * 
 * @author Kevin Glass
 */
public class Game extends Canvas implements Runnable{

    /** The stragey that allows us to use accelerate page flipping */
    private BufferStrategy strategy;
    /** True if the game is currently "running", i.e. the game loop is looping */
    private boolean gameRunning = true;
    /** The list of all the entities that exist in our game */
    private ArrayList entities = new ArrayList();
    /** The list of entities that need to be removed from the game this loop */
    private ArrayList removeList = new ArrayList();
    /** The entity representing the player */
    private Entity ship;
    /** The speed at which the player's ship should move (pixels/sec) */
    private double moveSpeed = 300;
    /** The time at which last fired a shot */
    private long lastFire = 0;
    /** The interval between our players shot (ms) */
    private long firingInterval = 500;
    /** The number of aliens left on the screen */
    private int alienCount;
    /** The number of levels progressed */
    private double levelCount;
    /** high score for the user */
    private int highScore;
    /** high score for the user */
    private String player = "bob";
    //private GetUserInput getPlayer;


    /** The list of entities that need to be removed from the game this loop */

    /** The message to display which waiting for a key press */
    private String message = "";
    /** True if we're holding up game play until a key has been pressed */
    private boolean waitingForKeyPress = true;
    /** True if the left cursor key is currently pressed */
    private boolean leftPressed = false;
    /** True if the right cursor key is currently pressed */
    private boolean rightPressed = false;
    /** True if we are firing */
    private boolean firePressed = false;
    /** True if game logic needs to be applied this loop, normally as a result of a game event */
    private boolean logicRequiredThisLoop = false;

    //private Thread cThread = new Thread(this);
    //public Thread t = new Thread(this);
    //private Thread g = new Thread(this);



 void setHighscore(int setHS) {
        highScore = setHS;
    }

    public int getHighscore() {
        return highScore;
    }

    public void setPlayer(String setPlayer) {
        player = setPlayer;
    }

    public String getPlayer() {
        return player;
    }


    public void run() {
        //setup(); 
        System.out.println("hello im running bob");

        /*int count = 1;
        do {
             System.out.println("Count is: " + count);
             count++;
             try{Thread.sleep(1);}
             catch(InterruptedException e){}
        } while (count <= 2000000);*/
        //Game g =new Game();
        //Game g = this;
            // Start the main game loop, note: this method will not
            // return until the game has finished running. Hence we are
            // using the actual main thread to run the game.
        //setup();  
        //this.gameLoop();
        //try{thread.sleep(1);}
        //catch{InterruptedException e}
     }

    /**
     * Construct our game and set it running.
     */


    public Game () {

        //Thread t = new Thread(this);//set up new thread for invaders game
         //t.run();//run the run method of the game
        //Game g =new Game();
        //setup();
        //Thread t = new Thread(this);
        //thread.start();
        //SwingUtilities.invokeLater(this);
        Thread er = new Thread(this);
        er.start();




    }

    public void setup(){

        //initialise highscore      
        setHighscore(0);

        // create a frame to contain our game
        JFrame container = new JFrame("Space Invaders 101");

        // get hold the content of the frame and set up the resolution of the game
        JPanel panel = (JPanel) container.getContentPane();
        panel.setPreferredSize(new Dimension(800,600));
        //panel.setLayout(null);

        // setup our canvas size and put it into the content of the frame
        setBounds(0,0,800,600);
        panel.add(this);

        // Tell AWT not to bother repainting our canvas since we're
        // going to do that our self in accelerated mode
        setIgnoreRepaint(true);

        // finally make the window visible 
        container.pack();
        container.setResizable(false);
        container.setVisible(true);


        // add a listener to respond to the user closing the window. If they
        // do we'd like to exit the game
        container.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                //cThread.interrupt();
                System.exit(0);

            }
        });

        // add a key input system (defined below) to our canvas
        // so we can respond to key pressed
        addKeyListener(new KeyInputHandler());

        // request the focus so key events come to us
        requestFocus();

        // create the buffering strategy which will allow AWT
        // to manage our accelerated graphics
        createBufferStrategy(2);
        strategy = getBufferStrategy();

        // initialise the entities in our game so there's something
        // to see at startup
        initEntities();


    }

    /**
     * Start a fresh game, this should clear out any old data and
     * create a new set.
     */
    private void startGame() {
        // clear out any existing entities and intialise a new set

        entities.clear();
        initEntities();

        //initialise highscore

        setHighscore(0);

        // blank out any keyboard settings we might currently have
        leftPressed = false;
        rightPressed = false;
        firePressed = false;
    }

    /**
     * Initialise the starting state of the entities (ship and aliens). Each
     * entitiy will be added to the overall list of entities in the game.
     */
    //private void initEntities() {
    public void initEntities() {
        Random randomAlien = new Random();
        // create the player ship and place it roughly in the center of the screen
        //ship = new ShipEntity(this,"sprites/ship.gif",370,550);//orignal
        ship = new ShipEntity(this,"sprites/ship.gif",700,300);//changed postioning to right hand side
        entities.add(ship);

        // create a block of aliens (5 rows, by 12 aliens, spaced evenly)
        alienCount = 0;
        levelCount = 1.02;

        for (int row=0;row<7;row++) {//altered number of rows
            for (int x=0;x<5;x++) {
                 int r = randomAlien.nextInt(100);//loop added to produce random aliens
                 if (r < 50){
                    //Entity alien = new AlienEntity(this,"sprites/alien.gif",/*100+*/(x*50),(50)+row*30);
                        Entity alien = new AlienEntity(this,"sprites/alien.gif",100+(x*90),(12)+row*85);
                        entities.add(alien);
                        alienCount++;
                        }
                }
        }

    }


    //private void initEntities() {
    public void initAlienEntities() {
        Random randomAlien = new Random();
        // create the player ship and place it roughly in the center of the screen
        //ship = new ShipEntity(this,"sprites/ship.gif",370,550);//orignal
        //ship = new ShipEntity(this,"sprites/ship.gif",700,300);//changed postioning to right hand side
        //entities.add(ship);

        // create a block of aliens (5 rows, by 12 aliens, spaced evenly)
        alienCount = 0;
        levelCount = levelCount + 0.10;//this increases the speed on every level



        for (int row=0;row<7;row++) {//altered number of rows
            for (int x=0;x<5;x++) {
                 int r = randomAlien.nextInt(100);//loop added to produce random aliens
                 if (r < 50){//randome check to show alien
                    //Entity alien = new AlienEntity(this,"sprites/alien.gif",/*100+*/(x*50),(50)+row*30);
                        Entity alien = new AlienEntity(this,"sprites/alien.gif",-250+(x*90),(12)+row*85);
                        entities.add(alien);
                        alienCount++;                       
                        }
                }
        }

        advanceAlienSpeed(levelCount);

    }


    /**
     * Notification from a game entity that the logic of the game
     * should be run at the next opportunity (normally as a result of some
     * game event)
     */
    public void updateLogic() {

        logicRequiredThisLoop = true;
    }

    /**
     * Remove an entity from the game. The entity removed will
     * no longer move or be drawn.
     * 
     * @param entity The entity that should be removed
     */
    public void removeEntity(Entity entity) {
        removeList.add(entity);
    }

    /**
     * Notification that the player has died. 
     */
    public void notifyDeath() {
        message = "Oh no! They got you, try again?";
        waitingForKeyPress = true;
    }

    /**
     * Notification that the player has won since all the aliens
     * are dead.
     */
    public void notifyWin() {
        message = "Well done! You Win!";
        waitingForKeyPress = true;
    }

    /**
     * Notification that an alien has been killed
     */
    public void notifyAlienKilled() {
        // reduce the alient count, if there are none left, the player has won!
        alienCount--;

        if (alienCount == 0) {
            //notifyWin();win not relevant here...
            this.initAlienEntities();//call fresh batch of aliens
        }

        // if there are still some aliens left then they all need to get faster, so
        // speed up all the existing aliens

        advanceAlienSpeed(1.30);

    }

    public void advanceAlienSpeed(double speed) {

        // if there are still some aliens left then they all need to get faster, so
        // speed up all the existing aliens
        for (int i=0;i<entities.size();i++) {
            Entity entity = (Entity) entities.get(i);

            if (entity instanceof AlienEntity) {
                // speed up by 2%
                entity.setHorizontalMovement(entity.getHorizontalMovement() * speed);
                //entity.setVerticalMovement(entity.getVerticalMovement() * 1.02);
            }
        }
    }

    /**
     * Attempt to fire a shot from the player. Its called "try"
     * since we must first check that the player can fire at this 
     * point, i.e. has he/she waited long enough between shots
     */
    public void tryToFire() {
        // check that we have waiting long enough to fire
        if (System.currentTimeMillis() - lastFire < firingInterval) {
            return;
        }

        // if we waited long enough, create the shot entity, and record the time.
        lastFire = System.currentTimeMillis();
        ShotEntity shot = new ShotEntity(this,"sprites/shot.gif",ship.getX()+10,ship.getY()-30);
        entities.add(shot);
    }

    /**
     * The main game loop. This loop is running during all game
     * play as is responsible for the following activities:
     * <p>
     * - Working out the speed of the game loop to update moves
     * - Moving the game entities
     * - Drawing the screen contents (entities, text)
     * - Updating game events
     * - Checking Input
     * <p>
     */
    public void gameLoop() {
        long lastLoopTime = System.currentTimeMillis();

        // keep looping round til the game ends
        while (gameRunning) {
            // work out how long its been since the last update, this
            // will be used to calculate how far the entities should
            // move this loop
            long delta = System.currentTimeMillis() - lastLoopTime;
            lastLoopTime = System.currentTimeMillis();

            // Get hold of a graphics context for the accelerated 
            // surface and blank it out
            Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
            g.setColor(Color.black);
            g.fillRect(0,0,800,600);

            // cycle round asking each entity to move itself
            if (!waitingForKeyPress) {

                for (int i=0;i<entities.size();i++) {
                    Entity entity = (Entity) entities.get(i);

                    entity.move(delta);
                }
            }

            // cycle round drawing all the entities we have in the game 

            for (int i=0;i<entities.size();i++) {
                Entity entity = (Entity) entities.get(i);

                entity.draw(g);
            }

            // brute force collisions, compare every entity against
            // every other entity. If any of them collide notify 
            // both entities that the collision has occured
            for (int p=0;p<entities.size();p++) {
                for (int s=p+1;s<entities.size();s++) {
                    Entity me = (Entity) entities.get(p);
                    Entity him = (Entity) entities.get(s);

                    if (me.collidesWith(him)) {
                        me.collidedWith(him);
                        him.collidedWith(me);
                    }
                }
            }

            // remove any entity that has been marked for clear up
            entities.removeAll(removeList);
            removeList.clear();

            // if a game event has indicated that game logic should
            // be resolved, cycle round every entity requesting that
            // their personal logic should be considered.
            if (logicRequiredThisLoop) {
                //g.drawString("Press any key",(800-g.getFontMetrics().stringWidth("Press any key"))/2,300);
                for (int i=0;i<entities.size();i++) {
                    Entity entity = (Entity) entities.get(i);
                    entity.doLogic();
                }

                logicRequiredThisLoop = false;

            }

            // if we're waiting for an "any key" press then draw the 
            // current message

            //show highscore at top of screen

            //show name at top of screen
            g.setColor(Color.white);
            g.drawString("Player : "+getPlayer()+" : Score : "+getHighscore(),20,20);

            if (waitingForKeyPress) {
                g.setColor(Color.white);
                g.drawString(message,(800-g.getFontMetrics().stringWidth(message))/2,250);
                g.drawString("Press any key",(800-g.getFontMetrics().stringWidth("Press any key"))/2,300);
            }

            // finally, we've completed drawing so clear up the graphics
            // and flip the buffer over
            g.dispose();
            strategy.show();

            // resolve the movement of the ship. First assume the ship 
            // isn't moving. If either cursor key is pressed then
            // update the movement appropraitely
            ship.setVerticalMovement(0);//set to vertical movement

            if ((leftPressed) && (!rightPressed)) {
                ship.setVerticalMovement(-moveSpeed);//**took out setHorizaontalMOvement
            } else if ((rightPressed) && (!leftPressed)) {
                ship.setVerticalMovement(moveSpeed);//**took out setHorizaontalMOvement
            }

            // if we're pressing fire, attempt to fire
            if (firePressed) {
                tryToFire();
            }

            // finally pause for a bit. Note: this should run us at about
            // 100 fps but on windows this might vary each loop due to
            // a bad implementation of timer
            try { Thread.sleep(10); } catch (Exception e) {}
        }
    }


    /**
     * A class to handle keyboard input from the user. The class
     * handles both dynamic input during game play, i.e. left/right 
     * and shoot, and more static type input (i.e. press any key to
     * continue)
     * 
     * This has been implemented as an inner class more through 
     * habbit then anything else. Its perfectly normal to implement
     * this as seperate class if slight less convienient.
     * 
     * @author Kevin Glass
     */
    private class KeyInputHandler extends KeyAdapter {
        /** The number of key presses we've had while waiting for an "any key" press */
        private int pressCount = 1;

        /**
         * Notification from AWT that a key has been pressed. Note that
         * a key being pressed is equal to being pushed down but *NOT*
         * released. Thats where keyTyped() comes in.
         *
         * @param e The details of the key that was pressed 
         */
        public void keyPressed(KeyEvent e) {
            // if we're waiting for an "any key" typed then we don't 
            // want to do anything with just a "press"
            if (waitingForKeyPress) {
                return;
            }


        //  if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                ////leftPressed = true;
            ///}
        ////    if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                //rightPressed = true;

            if (e.getKeyCode() == KeyEvent.VK_UP) {
                leftPressed = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                rightPressed = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                firePressed = true;
            }
        } 

        /**
         * Notification from AWT that a key has been released.
         *
         * @param e The details of the key that was released 
         */
        public void keyReleased(KeyEvent e) {
            // if we're waiting for an "any key" typed then we don't 
            // want to do anything with just a "released"
            if (waitingForKeyPress) {
            return;
            }

            if (e.getKeyCode() == KeyEvent.VK_UP) {//changed from VK_LEFT
                leftPressed = false;
            }
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {//changed from VK_RIGHT
                rightPressed = false;
            }

            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                firePressed = false;
            }
        }

        /**
         * Notification from AWT that a key has been typed. Note that
         * typing a key means to both press and then release it.
         *
         * @param e The details of the key that was typed. 
         */
        public void keyTyped(KeyEvent e) {
            // if we're waiting for a "any key" type then
            // check if we've recieved any recently. We may
            // have had a keyType() event from the user releasing
            // the shoot or move keys, hence the use of the "pressCount"
            // counter.
            if (waitingForKeyPress) {
                if (pressCount == 1) {
                    // since we've now recieved our key typed
                    // event we can mark it as such and start 
                    // our new game
                    waitingForKeyPress = false;
                    startGame();
                    pressCount = 0;
                } else {
                    pressCount++;
                }
            }

            // if we hit escape, then quit the game
            if (e.getKeyChar() == 27) {
                //cThread.interrupt();


                System.exit(0);
            }
        }
    }

    /**
     * The entry point into the game. We'll simply create an
     * instance of class which will start the display and game
     * loop.
     * 
     * @param argv The arguments that are passed into our game
     */
    //public static void main(String argv[]) {

        //Game g =new Game();

        // Start the main game loop, note: this method will not
        // return until the game has finished running. Hence we are
        // using the actual main thread to run the game.
        //g.gameLoop();
    //}












}

© Stack Overflow or respective owner

Related posts about java

Related posts about oop