当涉及到更改 JLabel 中的许多 ImageIcons 时,有一个 "lag" 或 "delay"。如何避免?

There is a "lag" or "delay" when it comes to changing many ImageIcons inside JLabels. How to avoid?

我目前正在开发一个 2D 模拟器游戏,该游戏发生在 41x23 网格上显示的 Perlin 噪声生成的地形中。玩家(目前位于中心但尚未获得叠加图标)可以使用箭头键移动,但这样做会使玩家保持静止但会相应地移动地图。但是,当我移动时,JFrame 会像地狱一样滞后。某些 JLabel 实例更改其 ImageIcons 的速度比其他实例慢,从而造成巨大的延迟和非“可玩性”。我已经尝试用四个“有效”使播放器更快移动的功能替换低效的功能更新 - 但滞后或延迟仍然存在。我也重新格式化和重构了该功能,但无济于事。所以,我卡住了。

有关详细信息,我使用 32x32 图标表示结构和域,JFrame 的大小为 1280x720。我相信这不是硬件原因,因为该程序与其他内存或核心消耗程序一起运行。有什么办法可以解决卡顿或延迟的问题吗?

主要Class

import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class Main {

    private JFrame frame;
    public static ImageIcon water = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/water.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon sand = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/sand.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon grass = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/grass.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon stone = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/stone.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon ice = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/terrain/ice.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon oak = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/structure/oak.png")).getImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT));
    public static ImageIcon nullstructure = new ImageIcon(new ImageIcon(Main.class.getResource("/textures/structure/nullstructure.png")).getImage().getScaledInstance(32, 32,  Image.SCALE_DEFAULT));
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Main window = new Main();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     * @throws InterruptedException 
     */
    public Main() throws InterruptedException {
        initialize();
        
    }

    /**
     * Initialize the contents of the frame.
     * @throws InterruptedException 
     */
    private void initialize() throws InterruptedException {
        frame = new JFrame();
        frame.setResizable(false);
        frame.setBounds(0, 0, 1280, 720);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);
        
        Coordinate playerPos = new Coordinate(0,0);
        JLabel[][] terrainArray = new JLabel[41][23];
        JLabel[][] structureArray = new JLabel[41][23];
        JLayeredPane layeredPane = new JLayeredPane();
        layeredPane.setBounds(0, 0, 1280, 720);
        frame.getContentPane().add(layeredPane);
        layeredPane.setLayout(null);
            JPanel terrainGrid = new JPanel();
            terrainGrid.setBounds(0, 0, 1280, 720);
            layeredPane.add(terrainGrid);
            GridBagLayout gbl_terrainGrid = new GridBagLayout();
            gbl_terrainGrid.columnWidths = new int[]{0};
            gbl_terrainGrid.rowHeights = new int[]{0};
            gbl_terrainGrid.columnWeights = new double[]{Double.MIN_VALUE};
            gbl_terrainGrid.rowWeights = new double[]{Double.MIN_VALUE};
            terrainGrid.setLayout(gbl_terrainGrid);
            
            JPanel structureGrid = new JPanel();
            layeredPane.setLayer(structureGrid, Integer.valueOf(1));
            structureGrid.setBounds(0, 0, 1280, 720);
            structureGrid.setBackground(new Color(0,0,0,0));
            structureGrid.setOpaque(false);
            layeredPane.add(structureGrid);
            GridBagLayout gbl_structureGrid = new GridBagLayout();
            gbl_structureGrid.columnWidths = new int[]{0};
            gbl_structureGrid.rowHeights = new int[]{0};
            gbl_structureGrid.columnWeights = new double[]{Double.MIN_VALUE};
            gbl_structureGrid.rowWeights = new double[]{Double.MIN_VALUE};
            structureGrid.setLayout(gbl_structureGrid); 
        
            Coordinate[][] map = new Coordinate[Coordinate.MAP_SIZE][Coordinate.MAP_SIZE];
            for(int i = 0; i < Coordinate.MAP_SIZE; i++) {
                for(int j = 0; j < Coordinate.MAP_SIZE; j++) {
                    map[i][j] = new Coordinate(i - ((Coordinate.MAP_SIZE - 1)/2) , j - ((Coordinate.MAP_SIZE - 1)/2));
                }
            }
            
            for(int i = 0; i < 41; i++) {
                for(int j = 0; j < 23; j++) {
                    terrainArray[i][j] = new JLabel("");
                    structureArray[i][j] = new JLabel("");
                    structureArray[i][j].setIcon(Main.nullstructure);
                    terrainArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnTerrainIcon());
                    structureArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnStructureIcon());
                    
                    GridBagConstraints gbc = new GridBagConstraints();
                        gbc.gridx = i; gbc.gridy = j;
                        terrainGrid.add(terrainArray[i][j], gbc);
                        structureGrid.add(structureArray[i][j],gbc);
                }
            }
        
        frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch(e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    playerPos.setZ(playerPos.getZ() - 1);
                    moveUP(terrainArray, structureArray, map, playerPos);
                    
                    break;
                case KeyEvent.VK_DOWN:
                    playerPos.setZ(playerPos.getZ() + 1);
                    moveDOWN(terrainArray, structureArray, map, playerPos);
                    break;
                case KeyEvent.VK_RIGHT:
                    playerPos.setX(playerPos.getX() + 1);
                    moveRIGHT(terrainArray, structureArray, map, playerPos);
                    break;
                case KeyEvent.VK_LEFT:
                    playerPos.setX(playerPos.getX() - 1);
                    moveLEFT(terrainArray, structureArray, map, playerPos);
                    break;
                }
                
            }
        });
    }
    
    public void moveUP(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
        for(int x = 0; x < 41; x++) {
            for(int z = 22; z > 0; z--) {       //23 - 1
                terrainArray[x][z].setIcon(terrainArray[x][z-1].getIcon());
                structureArray[x][z].setIcon(structureArray[x][z-1].getIcon());
            }
            terrainArray[x][0].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() - 11)).returnTerrainIcon()); 
            structureArray[x][0].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() - 11)).returnStructureIcon());
        }
    }
    
    public void moveDOWN(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
        for(int x = 0; x < 41; x++) {
            for(int z = 0; z < 22; z++) {       //23 - 1
                terrainArray[x][z].setIcon(terrainArray[x][z+1].getIcon());
                structureArray[x][z].setIcon(structureArray[x][z+1].getIcon());
            }
            terrainArray[x][22].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() + 11)).returnTerrainIcon()); 
            structureArray[x][22].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + x, playerPos.getZ() + 11)).returnStructureIcon());
        }
    }
    
    public void moveLEFT(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
        for(int z = 0; z < 23; z++) {
            for(int x = 40; x > 0; x--) {
                terrainArray[x][z].setIcon(terrainArray[x-1][z].getIcon());
                structureArray[x][z].setIcon(structureArray[x-1][z].getIcon());
            }
            terrainArray[0][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20, playerPos.getZ() - 11 + z)).returnTerrainIcon());
            structureArray[0][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20, playerPos.getZ() - 11 + z)).returnStructureIcon());
        }
    }
    
    public void moveRIGHT(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
        for(int z = 0; z < 23; z++) {
            for(int x = 0; x < 40; x++) {
                terrainArray[x][z].setIcon(terrainArray[x+1][z].getIcon());
                structureArray[x][z].setIcon(structureArray[x+1][z].getIcon());
            }
            terrainArray[40][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() + 20, playerPos.getZ() - 11 + z)).returnTerrainIcon());
            structureArray[40][z].setIcon(findEntry(map, new Coordinate(playerPos.getX() + 20, playerPos.getZ() - 11 + z)).returnStructureIcon());
        }
    }
    
    public static ImageIcon brightenImage(ImageIcon input, float brightness, float offset) {
        BufferedImage bI = new BufferedImage(input.getImage().getWidth(null),       input.getImage().getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D bIgr = bI.createGraphics();
        bIgr.drawImage(input.getImage(), 0, 0, null);
        bIgr.dispose();
        BufferedImage bO = new BufferedImage(input.getImage().getWidth(null), input.getImage().getHeight(null), BufferedImage.TYPE_INT_RGB);
        
        RescaleOp rop = new RescaleOp(brightness, offset, null);
        
        bO = rop.filter(bI, null);
        ImageIcon output = new ImageIcon(bO);
        return output;
    }
    
//  public void update(JLabel[][] terrainArray, JLabel[][] structureArray, Coordinate[][] map, Coordinate playerPos) {
//      for(int i = 0; i < 41; i++) {
//          for(int j = 0; j < 23; j++) {
//              terrainArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnTerrainIcon());
//              structureArray[i][j].setIcon(findEntry(map, new Coordinate(playerPos.getX() - 20 + i, playerPos.getZ() - 11 + j)).returnStructureIcon());
//          }
//      }
//  }
    
    public Coordinate findEntry(Coordinate[][] map, Coordinate pos) {
        Coordinate entry = null;
        for(int x = 0; x < Coordinate.MAP_SIZE; x++) {
            for(int z = 0; z < Coordinate.MAP_SIZE; z++) {
                if(pos.getX() == map[x][z].getX() && pos.getZ() == map[x][z].getZ()) {
                    entry = map[x][z];
                }
            }
        }
        return entry;
    }
    
}

坐标Class

import javax.swing.ImageIcon;

public class Coordinate {
    
    private int x, z;
    private int alt;
    public static final int MAP_SIZE = 199;
    private ImageIcon str = Main.nullstructure;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getZ() {
        return z;
    }

    public void setZ(int z) {
        this.z = z;
    }

    public int getAlt() {
        return alt;
    }

    public void setAlt(int alt) {
        this.alt = alt;
    }

    public Coordinate(int x0, int z0) {
        this.x = x0;
        this.z = z0;
        
        int a = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.1, z*0.1));
        int b = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.05, z*0.05));
        int c = (int) Noise.mapTo(-1 * Math.sqrt(0.5), Math.sqrt(0.5), 0, 100, Noise.noise(x*0.01, z*0.01));
        this.alt = (int) ((0.55*c) + (0.25*b) + (0.20*a));
        if(Math.random() < 0.05 && alt >= 52 && alt < 70) {
            str = Main.oak;
        }
    }
    
    public ImageIcon returnTerrainIcon() {
        if(alt >= 0 && alt < 50) {
            return Main.water;
        }
        else if(alt >= 50 && alt < 52) {
            return Main.brightenImage(Main.sand, (float) ((float) 0.95 + ((alt - 50) * 0.025)), (float) 0.36);
        }
        else if(alt >= 52 && alt < 70) {
            return Main.brightenImage(Main.grass, (float) ((float) 0.85 + ((alt - 52) * 0.025)), (float) 0.36);
        }
        else if(alt >= 80 && alt < 90) {
            return Main.brightenImage(Main.stone, (float) ((float) 0.65 + ((alt - 70) * 0.05)), (float) 0.36);
        }
        else {
            return Main.ice;
        }
    }
    
    public ImageIcon returnStructureIcon() {
        return str;
    }
}

Perlin(非原创)

import java.util.Random;

//<pre>
// Copyright 2001 Ken Perlin
// Courtesy of https://mrl.cs.nyu.edu/~perlin/experiments/packing/render/Noise.java
/** 
    Computes Perlin Noise for one, two, and three dimensions.<p>
    The result is a continuous function that interpolates a smooth path
    along a series random points. The function is consitent, so given
    the same parameters, it will always return the same value.
    @see ImprovedNoise
*/

public final class Noise {

   /** 
   Initialization seed used to start the random number generator.
   */
   static Random randseed = new Random();
   public static int seed = (int) Math.floor(randseed.nextInt());

   private static final int P = 8;
   private static final int B = 1 << P;
   private static final int M = B - 1;

   private static final int NP = 8;
   private static final int N = 1 << NP;

   private static int p[] = new int[B + B + 2];
   private static double g2[][] = new double[B + B + 2][2];
   private static double g1[] = new double[B + B + 2];
   private static double[][] points = new double[32][3];

   static {
      init();
   }

   private static double lerp(double t, double a, double b) {
      return a + t * (b - a);
   }

   private static double s_curve(double t) {
      return t * t * (3 - t - t);
   }

   /** 
   Computes noise function for one dimension at x.
   @param x 1 dimensional parameter
   @return the noise value at x 
   */
   public static double noise(double x) {

      int bx0, bx1;
      double rx0, rx1, sx, t, u, v;
      t = x + N;
      bx0 = ((int) t) & M;
      bx1 = (bx0 + 1) & M;
      rx0 = t - (int) t;
      rx1 = rx0 - 1;

      sx = s_curve(rx0);
      u = rx0 * g1[p[bx0]];
      v = rx1 * g1[p[bx1]];

      return lerp(sx, u, v);
   }

   /** 
   Computes noise function for two dimensions at the point (x,y).
   @param x x dimension parameter
   @param y y dimension parameter
   @return the value of noise at the point (x,y)
   */
   public static double noise(double x, double y) {

      int bx0, bx1, by0, by1, b00, b10, b01, b11;
      double rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v, q[];
      int i, j;

      t = x + N;
      bx0 = ((int) t) & M;
      bx1 = (bx0 + 1) & M;
      rx0 = t - (int) t;
      rx1 = rx0 - 1;

      t = y + N;
      by0 = ((int) t) & M;
      by1 = (by0 + 1) & M;
      ry0 = t - (int) t;
      ry1 = ry0 - 1;

      i = p[bx0];
      j = p[bx1];

      b00 = p[i + by0];
      b10 = p[j + by0];
      b01 = p[i + by1];
      b11 = p[j + by1];

      sx = s_curve(rx0);
      sy = s_curve(ry0);

      q = g2[b00];
      u = rx0 * q[0] + ry0 * q[1];
      q = g2[b10];
      v = rx1 * q[0] + ry0 * q[1];
      a = lerp(sx, u, v);

      q = g2[b01];
      u = rx0 * q[0] + ry1 * q[1];
      q = g2[b11];
      v = rx1 * q[0] + ry1 * q[1];
      b = lerp(sx, u, v);

      return lerp(sy, a, b);
   }

   /** 
   Computes noise function for three dimensions at the point (x,y,z).
   @param x x dimension parameter
   @param y y dimension parameter
   @param z z dimension parameter
   @return the noise value at the point (x, y, z)
   */
   static public double noise(double x, double y, double z) {

      int bx, by, bz, b0, b1, b00, b10, b01, b11;
      double rx0, rx1, ry0, ry1, rz, sx, sy, sz, a, b, c, d, u, v, q[];

      bx = (int) Math.IEEEremainder(Math.floor(x), B);
      if (bx < 0)
         bx += B;
      rx0 = x - Math.floor(x);
      rx1 = rx0 - 1;

      by = (int) Math.IEEEremainder(Math.floor(y), B);
      if (by < 0)
         by += B;
      ry0 = y - Math.floor(y);
      ry1 = ry0 - 1;

      bz = (int) Math.IEEEremainder(Math.floor(z), B);
      if (bz < 0)
         bz += B;
      rz = z - Math.floor(z);

      //if (bx < 0 || bx >= B + B + 2)
      //System.out.println(bx);

      b0 = p[bx];

      bx++;

      b1 = p[bx];

      b00 = p[b0 + by];
      b10 = p[b1 + by];

      by++;

      b01 = p[b0 + by];
      b11 = p[b1 + by];

      sx = s_curve(rx0);
      sy = s_curve(ry0);
      sz = s_curve(rz);

      q = G(b00 + bz);
      u = rx0 * q[0] + ry0 * q[1] + rz * q[2];
      q = G(b10 + bz);
      v = rx1 * q[0] + ry0 * q[1] + rz * q[2];
      a = lerp(sx, u, v);
      q = G(b01 + bz);
      u = rx0 * q[0] + ry1 * q[1] + rz * q[2];
      q = G(b11 + bz);
      v = rx1 * q[0] + ry1 * q[1] + rz * q[2];
      b = lerp(sx, u, v);
      c = lerp(sy, a, b);
      bz++;
      rz--;
      q = G(b00 + bz);
      u = rx0 * q[0] + ry0 * q[1] + rz * q[2];
      q = G(b10 + bz);
      v = rx1 * q[0] + ry0 * q[1] + rz * q[2];
      a = lerp(sx, u, v);
      q = G(b01 + bz);
      u = rx0 * q[0] + ry1 * q[1] + rz * q[2];
      q = G(b11 + bz);
      v = rx1 * q[0] + ry1 * q[1] + rz * q[2];
      b = lerp(sx, u, v);
      d = lerp(sy, a, b);

      return lerp(sz, c, d);
   }

   private static double[] G(int i) {
      return points[i % 32];
   }

   private static void init() {
      int i, j, k;
      double u, v, w, U, V, W, Hi, Lo;
      java.util.Random r = new java.util.Random(seed);
      for (i = 0; i < B; i++) {
         p[i] = i;
         g1[i] = 2 * r.nextDouble() - 1;

         do {
            u = 2 * r.nextDouble() - 1;
            v = 2 * r.nextDouble() - 1;
         } while (u * u + v * v > 1 || Math.abs(u) > 2.5 * Math.abs(v) || Math.abs(v) > 2.5 * Math.abs(u) || Math.abs(Math.abs(u) - Math.abs(v)) < .4);
         g2[i][0] = u;
         g2[i][1] = v;
         normalize2(g2[i]);

         do {
            u = 2 * r.nextDouble() - 1;
            v = 2 * r.nextDouble() - 1;
            w = 2 * r.nextDouble() - 1;
            U = Math.abs(u);
            V = Math.abs(v);
            W = Math.abs(w);
            Lo = Math.min(U, Math.min(V, W));
            Hi = Math.max(U, Math.max(V, W));
         } while (u * u + v * v + w * w > 1 || Hi > 4 * Lo || Math.min(Math.abs(U - V), Math.min(Math.abs(U - W), Math.abs(V - W))) < .2);
      }

      while (--i > 0) {
         k = p[i];
         j = (int) (r.nextLong() & M);
         p[i] = p[j];
         p[j] = k;
      }
      for (i = 0; i < B + 2; i++) {
         p[B + i] = p[i];
         g1[B + i] = g1[i];
         for (j = 0; j < 2; j++) {
            g2[B + i][j] = g2[i][j];
         }
      }

      points[3][0] = points[3][1] = points[3][2] = Math.sqrt(1. / 3);
      double r2 = Math.sqrt(1. / 2);
      double s = Math.sqrt(2 + r2 + r2);

      for (i = 0; i < 3; i++)
         for (j = 0; j < 3; j++)
            points[i][j] = (i == j ? 1 + r2 + r2 : r2) / s;
      for (i = 0; i <= 1; i++)
         for (j = 0; j <= 1; j++)
            for (k = 0; k <= 1; k++) {
               int n = i + j * 2 + k * 4;
               if (n > 0)
                  for (int m = 0; m < 4; m++) {
                     points[4 * n + m][0] = (i == 0 ? 1 : -1) * points[m][0];
                     points[4 * n + m][1] = (j == 0 ? 1 : -1) * points[m][1];
                     points[4 * n + m][2] = (k == 0 ? 1 : -1) * points[m][2];
                  }
            }
   }

   private static void normalize2(double v[]) {
      double s;
      s = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
      v[0] = v[0] / s;
      v[1] = v[1] / s;
   }
   
   public static double mapTo(double a1, double a2, double b1, double b2, double x) {
      return b1 + ((x-a1)*(b2-b1))/(a2-a1);
   }
}

要用到的图标和资源在这个Github代码里(仓库,我猜的,我是新手Github): https://github.com/rubiksRepository/Perlin.git

如有任何帮助,我将不胜感激。谢谢!

到目前为止,Raildex 的建议是有效的。将地图编译成单个缓冲图像极大地减少了延迟并使游戏“可玩”。对于代码中的添加,我制作了一个支持所用纹理的纹理class;和一个 MapField,其对象具有包含已编译 BufferImage 的字段。

import java.awt.image.BufferedImage;

public class MapField {
    private BufferedImage terrain;
    private BufferedImage structure;
    
    public MapField(Coordinate[][] map) {
        BufferedImage[] colsT = new BufferedImage[Coordinate.MAP_SIZE];
        BufferedImage[] colsS = new BufferedImage[Coordinate.MAP_SIZE];
        for(int z = 0; z < Coordinate.MAP_SIZE; z++) {
            colsT[z] = Texture.mergeTeU(map[z]);
            colsS[z] = Texture.mergeStU(map[z]);
        }
        terrain = Texture.mergeH(colsT);
        structure = Texture.mergeH(colsS);
    }

    public BufferedImage getTerrain() {
        return terrain;
    }

    public void setTerrain(BufferedImage terrain) {
        this.terrain = terrain;
    }

    public BufferedImage getStructure() {
        return structure;
    }

    public void setStructure(BufferedImage structure) {
        this.structure = structure;
    }
}

同样在Textureclass中,有一些方法可以用于合并BufferedImages的行和列,使用Graphics2D绘图过程:

public static BufferedImage toBI(ImageIcon input) {
        BufferedImage output = new BufferedImage(input.getImage().getWidth(null), input.getImage().getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D outputGr = output.createGraphics();
        outputGr.drawImage(input.getImage(), 0, 0, null);
        outputGr.dispose();
        return output;
    }
    
    public static BufferedImage mergeH(BufferedImage[] x) {
        int i = 0;
        BufferedImage rowOutput = new BufferedImage(x[0].getWidth() * x.length, x[0].getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D rowOutputG = rowOutput.createGraphics();
        for(BufferedImage xBI : x) {
            rowOutputG.drawImage(xBI, i * x[0].getWidth(), 0, null);
            i++;
        }
        rowOutputG.dispose();
        return rowOutput;
    }
    
    public static BufferedImage mergeTeH(Coordinate[] x) {
        BufferedImage[] xIcons = new BufferedImage[x.length];
        for(int i = 0; i < x.length; i++) {
            xIcons[i] = Texture.toBI(x[i].returnTerrainIcon());
        }
        return mergeH(xIcons);
    }
    
    public static BufferedImage mergeStH(Coordinate[] x) {
        BufferedImage[] xIcons = new BufferedImage[x.length];
        for(int i = 0; i < x.length; i++) {
            xIcons[i] = Texture.toBI(x[i].returnStructureIcon());
        }
        return mergeH(xIcons);
    }
    
    public static BufferedImage mergeU(BufferedImage[] x) {
        int i = 0;
        BufferedImage colOutput = new BufferedImage(x[0].getWidth(), x[0].getHeight() * x.length, BufferedImage.TYPE_INT_ARGB);
        Graphics2D colOutputG = colOutput.createGraphics();
        for(BufferedImage xBI : x) {
            colOutputG.drawImage(xBI, 0, i * x[0].getHeight(), null);
            i++;
        }
        colOutputG.dispose();
        return colOutput;
    }
    
    public static BufferedImage mergeTeU(Coordinate[] x) {
        BufferedImage[] xIcons = new BufferedImage[x.length];
        for(int i = 0; i < x.length; i++) {
            xIcons[i] = Texture.toBI(x[i].returnTerrainIcon());
        }
        return mergeU(xIcons);
    }
    
    public static BufferedImage mergeStU(Coordinate[] x) {
        BufferedImage[] xIcons = new BufferedImage[x.length];
        for(int i = 0; i < x.length; i++) {
            xIcons[i] = Texture.toBI(x[i].returnStructureIcon());
        }
        return mergeU(xIcons);
    }

所以底线是:对于基于滚动的地图,您可以编译与地图对应的纹理以提高可玩性(FPS或减少延迟)。对于与游戏的交互,通过将其变为透明或更改纹理在像素范围内编辑 BufferedImage 会有所帮助,至少对我而言。在回答一般要点方面并不是很好,因为我只是在处理我的案例(虽然试图在其他人身上模拟这个解决方案)并且滚动基础地图是根据具体情况而定的,但我希望我的解决方案有所帮助。