user2614974
user2614974

Reputation: 43

Tearing/Artifacting in 2D tile map

first of all thanks for taking the time to read my question! I'm developing a 2D java game, with a tile based map. When my character moves around, everthing is fine, although when he moves left, vertical white lines, also know as artifacting/tearing, appear on the screen. Same thing happens when he moves up, though the lines are horizontal and much smaller in width. Oddly enough, this doesn't happen when I move right or down. I have searched around on internet to find a solution, though I haven't encountered anything that fit my problem.

Here's the code, although I've heavily downsized and simplified it for the sake of testing. It can therefore be run without any images. Thank you for any answer you provide!

package adriana;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;

/**
 *
 * @author Christophe
 */
public class Main extends JFrame implements Runnable{

    public Image dbImage;
    public Graphics dbGraphics;

    //Image + Array size
    final static int listWidth = 500, listHeight = 500;


    //Move Variables
    int playerX = 320, playerY = 240, xDirection, yDirection;

    //Sprites
    BufferedImage spriteSheet;

    //Lists for sprite sheet: 1 = STILL; 2 = MOVING_1; 3 = MOVING_2
    BufferedImage[] ARCHER_NORTH = new BufferedImage[4];
    BufferedImage[] ARCHER_SOUTH = new BufferedImage[4];
    BufferedImage[] ARCHER_EAST = new BufferedImage[4];
    BufferedImage[] ARCHER_WEST = new BufferedImage[4];

    Image[] TILE = new Image[12];

    //Animation Variables
    int currentFrame = 0, framePeriod = 150;
    long frameTicker = 0l;
    Boolean still = true;
    Boolean MOVING_NORTH = false, MOVING_SOUTH = false, MOVING_EAST = false, MOVING_WEST = false;

    BufferedImage player;

    //World Tile Variables
    //20 X 15 = 300 tiles 
    Rectangle[][] blocks = new Rectangle[listWidth][listHeight];

    int tileX = 250, tileY = 250;

    Rectangle playerRect = new Rectangle(playerX + 4,playerY+20,32,20);

    //Map Navigation
    static final byte PAN_UP = 0, PAN_DOWN  = 1, PAN_LEFT = 2, PAN_RIGHT = 3;
    final int speed = 8;



    public Main(){

        this.setTitle("JAVA4K");
        this.setSize(640,505);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        addKeyListener(new AL());

        for(int y = 0; y < listHeight; y++){
            for(int x = 0; x < listWidth; x++){
                blocks[x][y] = new Rectangle(x*32-8000, y*32-8000, 32, 32);
            }
        }

    }

    //Key Listener

    public class AL extends KeyAdapter{

        public void keyPressed(KeyEvent e){

            int keyInput = e.getKeyCode();
            still = false;
            if(keyInput == e.VK_LEFT){

                navigateMap(PAN_RIGHT);

            }if(keyInput == e.VK_RIGHT){

                navigateMap(PAN_LEFT);

            }if(keyInput == e.VK_UP){

                navigateMap(PAN_DOWN);

            }if(keyInput == e.VK_DOWN){

                navigateMap(PAN_UP);
            }
        }

        public void keyReleased(KeyEvent e){

            int keyInput = e.getKeyCode();
            setYDirection(0);
            setXDirection(0);

            if(keyInput == e.VK_LEFT){


            }if(keyInput == e.VK_RIGHT){


            }if(keyInput == e.VK_UP){


            }if(keyInput == e.VK_DOWN){

            }

        }
    }


    public void moveMap(){

        for(int a = 0; a < 500; a++){
                for(int b = 0; b < 500; b++){
                    if(blocks[a][b] != null){
                        blocks[a][b].x += xDirection;
                        blocks[a][b].y += yDirection;

                    }
                }
            }
    }


    public void navigateMap(byte pan){
        switch(pan){
            default:
                System.out.println("Unrecognized pan!");
                break;
            case PAN_UP:
                setYDirection(-1 * speed);
                break;
            case PAN_DOWN:
                setYDirection(+1 * speed);
                break;
            case PAN_LEFT:
                setXDirection(-1 * speed);
                break;
            case PAN_RIGHT:
                setXDirection(+1 * speed);
                break;
        }
    }


    public void setXDirection(int xdir){
        xDirection = xdir;
        if(blocks[0][0] != null) tileX = ((playerRect.x - blocks[0][0].x) / 32)-1;
    }


    public void setYDirection(int ydir){
        yDirection = ydir;
        if(blocks[0][0] != null) tileY = ((playerRect.y - blocks[0][0].y) / 32)-1;
    }



    public void paint(Graphics g){

        dbImage = createImage(getWidth(), getHeight());
        dbGraphics = dbImage.getGraphics();
        paintComponent(dbGraphics);
        g.drawImage(dbImage, 0, 25, this);

    }

    public void paintComponent(Graphics g){

        requestFocus();

        //Draws tiles and rectangular boundaries for debugging
        for(int a = tileX - 18; a < tileX + 20; a++){
            for(int b = tileY - 15; b < tileY + 17; b++){
                    g.setColor(Color.RED);
                    g.fillRect(blocks[a][b].x, blocks[a][b].y, 32, 32);
                    g.setColor(Color.BLACK);
                    g.drawRect(blocks[a][b].x, blocks[a][b].y, 32, 32);
            }
        }  

        //Draw player 
        g.drawRect(playerX, playerY, 40, 40);

        repaint();
    }

    public void run(){
        try{
            System.out.println("Running");
            while(true){
                moveMap();

                Thread.sleep(13);
            }
        }catch(Exception e){
            e.printStackTrace();
        }    
    }


    public static void main(String[] args) {
        Main main = new Main();

        //Threads
        Thread thread1 = new Thread(main);
        thread1.start();
    }
}

Upvotes: 1

Views: 452

Answers (1)

kiheru
kiheru

Reputation: 6618

You have no synchronization between the thread updating the map and the drawing. So the map can be in inconsistent state during drawing.

A quick fix would be wrapping the map updating and drawing in a synchronized block:

synchronized(blocks) {
    // drawing or modification here
}

(or just making the whole methods synchronized) Also, the other fields (like those modified in the key listener) are also susceptible being in inconsistent state.

There are other problems too:

  • Don't override paint() of a frame. Instead override paintComponent() of a JPanel. There's no need to create an image at every redraw, the swing painting mechanism is by default double buffered. See custom painting in swing.
  • Use KeyBindings instead of a KeyListener
  • Swing components must be accessed (and created) only in the event dispatch thread.

Upvotes: 1

Related Questions