2D平铺地图中的撕裂/伪影

时间:2013-09-15 21:16:56

标签: java lines tile

首先感谢您花时间阅读我的问题! 我正在开发一个带有基于图块的地图的2D java游戏。当我的角色走动时, everthing很好,虽然当他向左移动时,屏幕上会出现垂直的白线,也称为伪像/撕裂。当他向上移动时会发生同样的事情,尽管线条是水平的并且宽度要小得多。奇怪的是,当我向右或向下移动时,这不会发生。我已经在互联网上寻找解决方案,但我没有遇到任何适合我的问题。

这是代码,虽然为了测试我已经大量缩小并简化了它。因此可以在没有任何图像的情况下运行。感谢您提供的任何答案!

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();
    }
}

1 个答案:

答案 0 :(得分:1)

更新地图的线程与图形之间没有同步。因此,在绘图过程中地图可能处于不一致状态。

快速解决方法是将地图更新并绘制在同步块中:

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

(或者只是制作整个方法synchronized此外,其他字段(如在密钥监听器中修改的字段)也容易处于不一致状态。

还有其他问题:

  • 不要覆盖框架的paint()。而是覆盖paintComponent()的{​​{1}}。没有必要在每次重绘时创建图像,默认情况下,swing绘制机制是双缓冲的。请参阅custom painting in swing.
  • 使用KeyBindings代替JPanel
  • 只能在event dispatch thread
  • 中访问(和创建)Swing组件