[Solved]Having problem with drawing

So I have made my own game, its a 2d tile game much like pokemon for gameboy.

My problem is that, when I move my player around in my world, the picture is much like jelly or pudding if you will :stuck_out_tongue:
It’s like the picture isn’t updated fast enough, or that the tiles that are drawn after the player (in my loop) isn’t updated before the player moves to another tile. this is my code for my drawing board:



package zompocalypseEngine;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;

import zompocalypse.Player;



public class GamePanel extends JPanel{

	private BufferedImage backBuffer;
	private int windowHeight;
	private int windowWidth;
	private ZompocalypseGame game;

	public GamePanel(int windowWidth, int windowHeight, ZompocalypseGame sGame){
		setIgnoreRepaint(true);
		this.windowWidth = windowWidth;
		this.windowHeight = windowHeight;
		setVisible(true);
		this.game = sGame;
		
		this.backBuffer = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_RGB);
		
		this.backBuffer = new BufferedImage(this.windowWidth, this.windowHeight, BufferedImage.TYPE_INT_RGB);
	}

	public void draw(){
		Graphics2D g = (Graphics2D) getGraphics();
		
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, windowWidth, windowHeight);
		
		g.drawImage(this.backBuffer, 0, 0, this);
		g.dispose();
	}

	public void render() {
		Graphics bbg = this.backBuffer.getGraphics();
		BufferedImage image = null;
		
		Player player = this.game.getTileMap().getPlayer();

		for(int y = 0; y < 24; y++){
			for(int x = 0; x < 42; x++){
				Position position = new Position(x + player.getPosition().getX()-21,y + player.getPosition().getY()-12);
				int yOffset = 0;
				//Draw tiles
				Tile tile = this.game.getTileMap().getTileAt(position);
				if(tile != null){
					image = tile.getImage();
				}else{
					tile = new Tile(position, "WATER");
					image = tile.getImage();
				}

				//Draw items
				Item item = this.game.getTileMap().getItemAt(position);
				if(item != null){
					image = item.getImage();
				}

				//Draw buildings
				Building building = this.game.getTileMap().getBuildingAt(position);
				if(building != null){
					image = building.getImage();
				}

				//Draw units
				Unit unit = this.game.getTileMap().getUnitAt(position);
				if(unit != null){
					image = unit.getImage();
					yOffset = -40; //Unit height
				}
				bbg.drawImage(image, x*20, y*20+yOffset, this);
			}
		}
	}
}



Just tested my game again, and it is every tile, where the player isn’t standing, that are jelly-ish. :S

Here is a screenshot of my problem:

http://sudopwn.net/Files/gameProblem.png

The world is a square as for now :S

Where do you draw the images after you get them from Tile, Item, or Building?

Also why are you setting backBuffer twice?

The backbuffer thing is a mistake after I made a minor edit in my code :stuck_out_tongue:

I draw the images onto a buffered image, and then onto the JPanel, that what you mean?


	public void render() {
		Graphics bbg = this.backBuffer.getGraphics();
		BufferedImage image = null;
		
		Player player = this.game.getTileMap().getPlayer();

		for(int y = 0; y < 24; y++){
			for(int x = 0; x < 42; x++){
				Position position = new Position(x + player.getPosition().getX()-21,y + player.getPosition().getY()-12);
				int yOffset = 0;
				//Draw tiles
				Tile tile = this.game.getTileMap().getTileAt(position);
				if(tile != null){
					image = tile.getImage();
				}else{
					tile = new Tile(position, "WATER");
					image = tile.getImage();
				}

				//You should be drawing the Tile's image here

				//Draw items
				Item item = this.game.getTileMap().getItemAt(position);
				if(item != null){
					image = item.getImage();     // <-- The Tile's image is lost after this assignment
				}

				//You should be drawing the Item's image here

				//Draw buildings
				Building building = this.game.getTileMap().getBuildingAt(position);
				if(building != null){
					image = building.getImage();     // <-- The Item's image is lost after this assigmnent
				}

				//You should be drawing the Building's image here

				//Draw units
				Unit unit = this.game.getTileMap().getUnitAt(position);
				if(unit != null){
					image = unit.getImage();       // <-- The Building's image is lost after this assignment
					yOffset = -40; //Unit height
				}
				bbg.drawImage(image, x*20, y*20+yOffset, this);
			}
		}
	}

Yes I know the tiles images is lost, that’s the point, don’t wanna draw a tile if it ain’t visible :slight_smile:

If so, then the code you are showing us is insufficient to answer your question :wink:

Hmm… maybe this will help then, but it alot of code :stuck_out_tongue:



public class GUI extends JFrame implements ZompocalypseGUI{

	private GamePanel gamePanel;
	private boolean running;
	private int fps;
	private int windowWidth;
	private int windowHeight;
	private Insets insets;
	private Game game;
	private String gameMode;
	private KeyController keyController;
	private MouseController mouseController;
	private JButton singlePlayerBtn;
	private JFrame titleMenu;
	private int windowLocationX;
	private int windowLocationY;

	public GUI(int windowWidth, int windowHeight, int fps, Game game) {
		this.gameMode = "waiting";
		
		this.running = true;
		this.fps = fps;
		this.windowWidth = windowWidth;
		this.windowHeight = windowHeight;
		this.game = game;

		this.keyController = new KeyController();
		this.addKeyListener(keyController);

		this.mouseController = new MouseController();
		this.addMouseListener(mouseController);

		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension screenSize = toolkit.getScreenSize();

		this.windowLocationX = (int) screenSize.getWidth();
		this.windowLocationY = (int) screenSize.getHeight();

		this.setTitle("Zompocalypse");
		this.setSize(this.windowWidth, this.windowHeight);
		this.setResizable(false);
		this.setLocation((windowLocationX - windowWidth) / 2,( windowLocationY - windowHeight) / 2);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);

		this.setVisible(true);
		this.setIgnoreRepaint(true);

		this.insets = this.getInsets();
		setSize(insets.left + this.windowWidth + insets.right, insets.top + this.windowHeight + insets.bottom);

		

		this.gamePanel = new GamePanel(windowWidth, windowHeight, this.game);
		this.add(this.gamePanel);

		openTitleMenu();
	}

	private void openTitleMenu() {
		this.titleMenu = new JFrame("Zompocalypse - StartMenu!");
		titleMenu.setSize(300, 400);
		titleMenu.setResizable(false);
		titleMenu.setLocation((windowLocationX - 300) / 2, (windowLocationY - 400) / 2);
		titleMenu.setDefaultCloseOperation(EXIT_ON_CLOSE);
		titleMenu.setLayout(null);

		this.singlePlayerBtn = new JButton("SinglePlayer");
		singlePlayerBtn.setSize(250, 30);
		singlePlayerBtn.setLocation(25, 25);
		singlePlayerBtn.addActionListener(this);
		titleMenu.add(singlePlayerBtn);

		titleMenu.setVisible(true);
	}

	@Override
	public void run() {
		while (running) {
			long time = System.currentTimeMillis();
			update();
			render();
			draw();

			time = (1000 / fps) - (System.currentTimeMillis() - time);
			if (time > 0) {
				try {
					Thread.sleep(time);
				} catch (Exception e) {
					System.out.println(e);
				}
			}
		}
		setVisible(false);
	}

	public void update(){
		game.updatePlayer();
		game.updateMobs();
	}
	
	public void render(){
		gamePanel.render();
	}
	
	public void draw() {
		gamePanel.draw();
	}

	public String getGameMode() {
		return gameMode;
	}

	public void setGameMode(String gameMode){
		this.gameMode = gameMode;
	}

	public void actionPerformed(ActionEvent e) {
		if(e.getSource().equals(this.singlePlayerBtn)){
			setGameMode("newGame");
			this.titleMenu.setVisible(false);
		}
	}

	private class MouseController implements MouseListener{

		@Override
		public void mouseClicked(MouseEvent e) {
			Player player = game.getTileMap().getPlayer();
			int xOffset = 19;
			int yOffset = 12;
			if(e.getButton() == MouseEvent.BUTTON3){
				Point clickedPoint = e.getPoint();
				int x = (int) (clickedPoint.getX() / 20) - xOffset;
				int y = (int) (clickedPoint.getY() / 20) - yOffset;
				Position targetPosition = new Position(x, y);
				game.attack(player, targetPosition);
				System.out.println("Attacking targetPosition: " + targetPosition.toString());
			}
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mousePressed(MouseEvent e) {

		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

	private class KeyController implements KeyListener{

		@Override
		public void keyPressed(KeyEvent e) {
			if(gameMode != "waiting"){
				int key = e.getKeyCode();
				Player player = game.getTileMap().getPlayer();
				Position playerPosition = player.getPosition();
				Position targetPosition;
				int playerX = player.getPosition().getX();
				int playerY = player.getPosition().getY();
				Vector direction = player.getDirection();
				
				if (key == KeyEvent.VK_A) {
					targetPosition = new Position(playerX - 1, playerY);
					game.setDirectionOnUnit(playerPosition, targetPosition);
					game.moveUnitTo(playerPosition, new Position(playerX - 1, playerY));
				}else if (key == KeyEvent.VK_D) {
					targetPosition = new Position(playerX + 1, playerY);
					game.setDirectionOnUnit(playerPosition, targetPosition);
					game.moveUnitTo(playerPosition, new Position(playerX + 1, playerY));
				}else if (key == KeyEvent.VK_W) {
					targetPosition = new Position(playerX, playerY - 1);
					game.setDirectionOnUnit(playerPosition, targetPosition);
					game.moveUnitTo(playerPosition, new Position(playerX, playerY - 1));
				}else if (key == KeyEvent.VK_S) {
					targetPosition = new Position(playerX, playerY + 1);
					game.setDirectionOnUnit(playerPosition, targetPosition);
					game.moveUnitTo(playerPosition, new Position(playerX, playerY + 1));
				}else if (key == KeyEvent.VK_E) {
					// Action on item
					Item i = game.getTileMap().getItemAt(playerPosition);
					if (i != null) {
						game.action(i);
					}

					// Action on building
					Building b = game.getTileMap().getBuildingAt(playerPosition);
					if (b != null) {
						game.action(b);
					}
				}else if (key == KeyEvent.VK_R) {
					// Action on Zombie
					Position zombiePosition = new Position(playerX + direction.getX(),
							playerY + direction.getY());
					Zombie z = (Zombie) game.getTileMap().getUnitAt(zombiePosition);
					if (z != null) {
						if (game.isUnitWithinAttackRange(player, z)) {
							System.out.println("Attacking: " + z.toString());
							game.attack(player, z);
						}
					}
				}else if(key == KeyEvent.VK_I){
					System.out.println(player.getInventory().toString());
				}
			}
		}

		@Override
		public void keyReleased(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void keyTyped(KeyEvent e) {

		}
	}
}


To be honest, I don’t even know what you mean when you say the tiles are jelly-ish, care to show us a video/give us a test applet?

Made an executable .jar file with the “game”. :slight_smile: Hope that it works :slight_smile:

http://sudopwn.net/Files/Zompocalypse.zip

ohh, and you move with “wasd”, :stuck_out_tongue:

Oh! That’s because the KeyListener is running on the EDT (Event Dispatching Thread) while your game loop is in a different thread. Your options are to use boolean flags in the listener (like true for down and false up) and move the key handling to the update method, or put a big synchronized block inside in the KeyListener methods:


public void run() {
    while(running) {
        synchronized(this) {
            update();
            render();
            draw();
        }
        
        ...
    }
}

....

class KeyController implements KeyListener {
    public void keyPressed(KeyEvent key) {
        synchronized(GUI.this) {
            .....
        }
    }
}

EDIT: Update code

I will try that, thanks a lot!

Well it worked, but now the player just keep going in one direction when you push a button :stuck_out_tongue: and its pretty laggy… I’ll try go with the flaggin’, and then come back and let you know if that is better :slight_smile:

Thanks again, I’ve appreciated your response :slight_smile:

Well now it works, but its VERY laggy, when I press a key it takes for ever to move the player :S

updated the .jar file

http://sudopwn.net/Files/Zompocalypse.zip

Try making the booleans volatile:


private volatile boolean blah = false;
...

Also, what is the FPS that you set?

It’s set to 60



while (running) {
			long time = System.currentTimeMillis();

			update();
			render();
			draw();

			time = (1000 / fps) - (System.currentTimeMillis() - time);
			if (time > 0) {
				try {
					Thread.sleep(time);
				} catch (Exception e) {
					System.out.println(e);
				}
			}
		}


where fps is 60

Hmm volatile didn’t do the trick :frowning: