Reputation: 43
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
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:
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.KeyListener
Upvotes: 1