Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm having difficulties understanding how to use threads and I'm not sure if my basic structure is right.

This is my Board Class:

package mortifera;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JPanel;

public class Board extends JPanel implements Runnable, MouseListener {
    private int posX, posY;
    private Thread thread;
    private Hero hero;
    private Map map;

    public Board(Hero hero, Map map) {
        this.hero = hero;
        this.map = map;

        addMouseListener(this);
        setBackground(Color.BLACK);
        setDoubleBuffered(true);
    }

    public void addNotify(){
        super.addNotify();
        thread = new Thread(this);
        thread.start();
    }

    public void paint(Graphics g){
        super.paint(g);

        Graphics2D g2d = (Graphics2D)g;

        // DRAW MAP. index -> index of map[] array
        int index = 0;
        while(index<(map.getMapWidthInTiles()*map.getMapHeightInTiles())){
            for(int i=0; i<map.getMapWidthInTiles(); i++){
                for(int j=0; j<map.getMapHeightInTiles(); j++){
                    g2d.drawImage(map.getTileImage(index), posX, posY, this);
                    posX += map.getTileWidth();
                    index++;
                } 
                posX = 0;
                posY += map.getTileHeight();
            }
            posY = 0;
        }

        // DRAW HERO
        g2d.drawImage(hero.getImage(), hero.getX(), hero.getY(), this);

        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }

    public void run() {
        while(true){
            repaint();
        }    
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if(e.getButton() == 1){
            hero.moveTo(e.getX(), e.getY());
        }
    }

Followed by my Map Class:

package mortifera;

import java.awt.Image;

import javax.swing.ImageIcon;

public class Map {
    private int mapWidth, mapHeight, tileWidth, tileHeight;
    private int[] map = 
        { 0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          1,1,1,1,1,1,1,1,1,1,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0,
          0,0,0,0,0,0,0,0,0,0 
        };
    private Image[] tileImage;

    public Map(int mapWidth, int mapHeight){
        this.mapWidth = mapWidth;
        this.mapHeight = mapHeight;
        this.tileImage = new Image[2];
        this.tileImage[1] = new ImageIcon(this.getClass().getResource("tile-grass.png")).getImage();
        this.tileImage[0] = new ImageIcon(this.getClass().getResource("tile-mountain.png")).getImage();
        this.tileWidth = this.tileImage[0].getWidth(null);
        this.tileHeight = this.tileImage[0].getHeight(null);
    }

    public int getMapWidthInTiles(){
        return this.mapWidth;
    }

    public int getMapHeightInTiles(){
        return this.mapHeight;
    }

    public int getTileWidth(){
        return this.tileWidth;
    }

    public int getTileHeight(){
        return this.tileHeight;
    }

    public Image getTileImage(int index){
        return this.tileImage[map[index]];
    }
}

my Hero Class:

package mortifera;

import java.awt.Image;

import javax.swing.ImageIcon;

public class Hero{
    private int[] position;
    private Image image;

    public Hero(){
        position = new int[2];
        position[0] = 0; // X
        position[1] = 0; // Y
        image = new ImageIcon(getClass().getResource("held.gif")).getImage();
    }

    public void setPosition(int x, int y){
        this.position[0] = x;
        this.position[1] = y;
    }

    public int[] getPosition(){
        return this.position;
    }

    public int getX(){
        return this.position[0];
    }

    public int getY(){
        return this.position[1];
    }

    public Image getImage(){
        return this.image;
    }

    public void moveTo(int x, int y){
        while(this.position[0]!=x && this.position[1]!=y){
            if(this.position[0]<x){
                this.position[0]++;
            }
            if(this.position[1]<y){
                this.position[1]++;
            }
        }
    }
}

and my Main Class:

package mortifera;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Hero hero = new Hero();
        Map map = new Map(10, 10);
        Board board = new Board(hero, map);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(board);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

}

At the moment a a little map is drawn and my hero...

  1. After clicking some time on my screen the game crashes..
  2. At the moment the Hero is "teleported" to the point I clicked. I want it to "go" there and know how to do it with a Swing Timer, but not how it works with Threads.
  3. Apart from those 2 problems, im very thankful for any hints or critics to my whole concept. Is this, what I'm trying to do, done in this way?
share|improve this question
add comment

1 Answer

This bit:

public void moveTo(int x, int y){
    while(this.position[0]!=x && this.position[1]!=y){
        if(this.position[0]<x){
            this.position[0]++;
        }
        if(this.position[1]<y){
            this.position[1]++;
        }
    }
}

Is the crux of your problem. You have to think about game programming in a fundamentally different way than other things. Yes, your character is moving one square at a time (and only in one direction, which is a separate bug), but you're not doing it over time.

There are many ways of solving this, but thinking about it in a threaded sense is the wrong way to do it.

In a very basic sense, you need to simulate all of your entities for a frame, draw that frame, then continue to update. That frame is usually somewhere in the range of 1/60th to 1/30th of a second. So if you want your guy to move at X pixels a second, for one "tick" or "frame", you move him that frame's portion. Usually game frameworks have some kind of "game loop" setup where the actual time it took to draw the frame is passed down as a "delta time" value that you use instead of hard coding a frame time.

So in a rough sense, you would have to have an update() method on your guy that represents a single frame's worth of movement, and you do that movement and only that movement. The "while" loop is contained elsewhere (as a trivial case, your "repaint" loop is what you could use).

Just look for documentation on "game loops" and that should point you in a better direction.

share|improve this answer
2  
Thanks for your answer. I just googled Java 2d Game Loop and found this tutorial: cokeandcode.com/info/tut2d.html i think thats helping me. apreciate your help. –  aeres Dec 15 '11 at 17:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.