编辑:这是一个SSCCE来演示我的问题。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class Main {
    public static BufferedImage map, tileSand, tileSea;
    public static void main(String[] args) {
        map = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
        for(int x = 0; x < 50 ; x++){
            for(int y = 0; y < 50 ; y++){
                boolean colour = Math.random() < 0.5;
                if (colour){
                    map.setRGB(x, y, -256);
                } else {
                    map.setRGB(x, y, -16776961);
                }
            }
        }
        tileSand = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
        Graphics g = tileSand.getGraphics();
        g.setColor(Color.YELLOW);
        g.fillRect(0, 0, 32, 32);
        tileSea  = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
        g.setColor(Color.BLUE);
        g = tileSea.getGraphics();
        g.fillRect(0, 0, 32, 32);
        Island test = new Main.Island();
        test.start();
        long start, sleep;
        while(true) {
            start  = System.currentTimeMillis();
            test.getCanvas().requestFocus();
            test.getCanvas().repaint();
            sleep = 15-(System.currentTimeMillis()-start);
            try {
                Thread.sleep(sleep > 0 ? sleep : 0);
            } catch (InterruptedException e) {
            }
        }
    }

    static class Island implements Runnable {

        private Tile[][] tiles;
        private JFrame frame;
        private JPanel panel;
        private Thread logicThread;
        private boolean running = false;
        private boolean paused = false;
        private Image image;
        private Player player;

        public Island() {
            image = new BufferedImage(1027, 768, BufferedImage.TYPE_INT_ARGB);
            player = new Player();
            tiles = new Tile[map.getWidth()][map.getHeight()];
            int rgb;
            for(int x = 0; x < map.getWidth(); x++) {
                for(int y = 0; y < map.getHeight(); y++) {
                    rgb = map.getRGB(x, y);
                    switch (rgb) {
                        case -16776961: tiles[x][y] = new Tile("sea");
                                        break;
                        case -256:  tiles[x][y] = new Tile("sand");
                                    break;
                    }
                }
            }
            makeMap();
            makeFrame();
            addBindings();
            logicThread = new Thread(this);
        }

        public JPanel getCanvas() {
            return panel;
        }

        public void start() {
            running = true;
            paused = false;
            logicThread.start();
        }

        public void run() {
            long sleep, before;
            while(running){
                before = System.currentTimeMillis();
                player.move();
                try {
                    sleep = 15-(System.currentTimeMillis()-before);
                    Thread.sleep(sleep > 0 ? sleep : 0);
                } catch (InterruptedException ex) {
                }
                while(running && paused);
            }
            paused = false;
        }

        private void makeFrame() {
            frame = new JFrame("Island");
            panel = new JPanel(){
                @Override
                public void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    Graphics2D g2d = (Graphics2D) image.getGraphics();
                    g2d.setColor(Color.BLACK);
                    g2d.fillRect(0, 0, 1024, 768);
                    long xl, yl;
                    xl = player.getLocation().x-512;
                    yl = player.getLocation().y-384;
                    int x2, y2;
                    x2 = (int) Math.floor(xl / 32);
                    y2 = (int) Math.floor(yl / 32);
                    int xoffset, yoffset;
                    xoffset = (int) (xl % 32);
                    yoffset = (int) (yl % 32);
                    for(int x = x2; x < x2+40; x++) {
                        for(int y = y2; y < y2+40; y++) {
                            if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
                                g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
                            }
                        }
                    }
                    g.drawImage(image, 0, 0, null);
                }
            };
            panel.setPreferredSize(new Dimension(1024, 768));
            panel.setIgnoreRepaint(true);
            frame.add(panel);
            frame.pack();
            frame.setVisible(true);
        }

        private void addBindings() {
            InputMap inputMap = panel.getInputMap();
            ActionMap actionMap = panel.getActionMap();
            inputMap.put(KeyStroke.getKeyStroke("Q"),"hold-sprint");
            actionMap.put("hold-sprint", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.sprint(true);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("released Q"),"release-sprint");
            actionMap.put("release-sprint", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.sprint(false);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("RIGHT"),"hold-right");
            actionMap.put("hold-right", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.right(true);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("released RIGHT"),"release-right");
            actionMap.put("release-right", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.right(false);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("DOWN"),"hold-down");
            actionMap.put("hold-down", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.down(true);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("released DOWN"),"release-down");
            actionMap.put("release-down", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.down(false);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("LEFT"),"hold-left");
            actionMap.put("hold-left", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.left(true);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("released LEFT"),"release-left");
            actionMap.put("release-left", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.left(false);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("UP"),"hold-up");
            actionMap.put("hold-up", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.up(true);
                }
            });
            inputMap.put(KeyStroke.getKeyStroke("released UP"),"release-up");
            actionMap.put("release-up", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    player.up(false);
                }
            });
        }

        private void makeMap() {
            for(int x = 0; x < tiles.length; x++) {
                for(int y = 0; y < tiles[0].length; y++) {
                    switch (tiles[x][y].getType()) {
                        case "sea": tiles[x][y].setContent(tileSea);
                                    break;
                        case "sand":    tiles[x][y].setContent(tileSand);
                                        break;
                    }
                }
            }
        }
    }

    static class Player{
        private Point location;
        private int xspeed, yspeed;
        private boolean left, up, right, down, sprint;

        public Player() {
            location = new Point(0, 0);
            left = false;
            up = false;
            right = false;
            down = false;
            sprint = false;
            xspeed = yspeed = 0;
        }
        public void left(boolean state){
            left = state;
        }

        public void up(boolean state){
            up = state;
        }

        public void right(boolean state){
            right = state;
        }

        public void down(boolean state){
            down = state;
        }

        public void sprint(boolean state) {
            sprint = state;
        }

        public void move() {
            if (sprint) {
                if (left) {
                    if(xspeed>-10)
                        xspeed--;
                } if (right) {
                    if(xspeed<10)
                        xspeed++;
                } if (up) {
                    if(yspeed>-10)
                        yspeed--;
                } if (down) {
                    if(yspeed<10)
                        yspeed++;
                }
            } else {
                if (left) {
                    if(xspeed>-5)
                        xspeed--;
                } if (right) {
                    if(xspeed<5)
                        xspeed++;
                } if (up) {
                    if(yspeed>-5)
                        yspeed--;
                } if (down) {
                    if(yspeed<5)
                        yspeed++;
                }
            }
            if (!sprint) {
                if (xspeed > 5) {
                    xspeed--;
                } if (xspeed < -5) {
                    xspeed++;
                }   if (yspeed > 5) {
                    yspeed--;
                } if (yspeed < -5) {
                    yspeed++;
                }
            }
            if (!left && !right) {
                if (xspeed > 0) {
                    xspeed--;
                } if (xspeed < 0) {
                    xspeed++;
                }
            } if (!up && !down) {
                if (yspeed > 0) {
                    yspeed--;
                } if (yspeed < 0) {
                    yspeed++;
                }
            }
            location.x = location.x + xspeed;
            location.y = location.y + yspeed;
        }

        public Point getLocation() {
            return location;
        }
    }

    static class Tile {
        private String type;
        private BufferedImage tile;

        public Tile(String type) {
            this.type = type;
        }

        public String getType() {
            return type;
        }

        public void setContent(BufferedImage newTile) {
            tile = newTile;
        }

        public BufferedImage getContent() {
            return tile;
        }
    }
}


我有一个带有修改后的paintComponent方法的JPanel。在这种方法中,我根据玩家的位置从2d数组向屏幕绘制相关的图块。我将所有图块都绘制到BufferedImage上,然后在paint方法末尾将其应用到屏幕上。从理论上讲,这不应该造成撕裂,因为我是双重缓冲?这是合适的代码,图像只是具有屏幕尺寸的BufferedImage:

    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) image.getGraphics();
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, 1024, 768);
        long xl, yl;
        xl = player.getLocation().x-512;
        yl = player.getLocation().y-384;
        int x2, y2;
        x2 = (int) Math.floor(xl / 32);
        y2 = (int) Math.floor(yl / 32);
        int xoffset, yoffset;
        xoffset = (int) (xl % 32);
        yoffset = (int) (yl % 32);
        for(int x = x2; x < x2+40; x++) {
            for(int y = y2; y < y2+40; y++) {
                if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
                    g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
                }
            }
        }
        g.drawImage(image, 0, 0, null);
    }


我认为撕裂可能是由于玩家的位置在绘画方法的持续时间内发生变化而导致瓷砖不匹配而引起的,玩家进行得越快,效果就越明显。但是我从一开始就获得了玩家的位置并将其存储在两个long中,我的印象是,longs是通过值而不是引用传递的,因此在方法运行时,玩家位置应该是恒定的。

我很乐意提供更多代码:),并在此先感谢。

最佳答案

如此一来,如果人们发现我的问题并想知道我最终要“解决”该问题的原因,然后再转而使用c ++和SDL或其他图像库,那么对于这种事情,这将是更好的选择。

09-26 02:46