当我重新涂抹太多时,停止在摇摆中闪烁

我正在制作一个带有tilemap的RPG。 为了生成tilemap,我循环通过一个二维数组,但这意味着当我重新绘制时,我必须每次都这样做。 如果我重画太多屏幕闪烁,我怎么能阻止这个。

package sexyCyborgFromAnOtherDimension; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Timer; import java.util.TimerTask; import javax.swing.JPanel; @SuppressWarnings("serial") public class Game extends JPanel { KeyLis listener; int mapX = 20; int mapY = 20; boolean up = false; boolean down = false; boolean right = false; boolean left = false; String[][] map; public Game() { super(); try { map = load("/maps/map1.txt"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } listener = new KeyLis(); this.setFocusable(true); this.requestFocus(); this.addKeyListener(listener); Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { if(up) { mapY++; repaint(); } if(down) { mapY--; repaint(); } if(right) { mapX--; repaint(); } if(left) { mapX++; repaint(); } } }; timer.scheduleAtFixedRate(task, 0, 10); } public void paint(Graphics g) { super.paintComponent(g); setDoubleBuffered(true); Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int x = 0; x < map.length; x++) { for (int y = 0; y < map[x].length; y++) { switch(map[x][y]) { case "0": g.setColor(Color.GREEN); break; case "1": g.setColor(Color.GRAY); break; } g.fillRect(y*20+mapX, x*20+mapY, 20, 20); } } g.setColor(Color.BLACK); g.fillRect(400, 400, 20, 20); } String[][] load(String file) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file))); int lines = 1; int length = br.readLine().split(" ").length; while (br.readLine() != null) lines++; br.close(); BufferedReader br1 = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file))); String[][] map = new String[lines][length]; for (int i = 0; i < lines; i++) { String line = br1.readLine(); String[] parts = line.split(" "); for (int y = 0; y < length; y++) { map[i][y] = parts[y]; } } br1.close(); return map; } private class KeyLis extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: up = true; break; case KeyEvent.VK_DOWN: down = true; break; case KeyEvent.VK_LEFT: left = true; break; case KeyEvent.VK_RIGHT: right = true; break; } } @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: up = false; break; case KeyEvent.VK_DOWN: down = false; break; case KeyEvent.VK_LEFT: left = false; break; case KeyEvent.VK_RIGHT: right = false; break; } } } } 

谢谢您的帮助

编辑

即使延迟10毫秒,使用javax.swing.Timer可以消除所有闪烁。

一些小事突然冒出来。

首先。 你可能更好地使用javax.swing.Timer而不是java.util.Timer ,这至少会让事件更好地流动。

其次,10毫秒是短时间段,严重的是,你不需要100fps,60fps约为17毫秒,我通常使用40毫秒为25fps。 这可能会给EDT一些喘息的空间来实际响应重绘请求。

第三,你应该使用paintComponent而不是paint 。 它在调用链中足够低,保证是双缓冲的

第四,你应该避免调用任何可能重新安排repaint (例如setDoubleBuffered ,如果你必须在构造函数中调用它,但是,Swing组件默认是双缓冲的)

第五,在可能的情况下,将所有“静态”或缓慢变化的内容绘制到后备缓冲区并进行绘制。 这样可以提高paint工作速度,因为它不会卡在很多小环中。

您可能需要查看AWT和Swing中的绘画,了解有关绘画过程的更多详细信息

一些额外的例子……

  • Swing动画运行速度极慢 – 能够同时从屏幕上移动500个元素到4500个元素 – 讨论资源管理
  • Java Bouncing Ball
  • 如何使线条动画更流畅?
  • 图像没有加载

而且因为kleo吓到了我(这也是一个好主意),你还应该看看如何使用Key Bindings ,这将解决你的KeyListener焦点问题

你已经在面板上设置了双缓冲,但是你自己绘制的东西不是双缓冲的。 调用setDoubleBuffered(true)仅对容器的子组件应用缓冲。

您需要手动缓冲自己绘制的内容。

我建议远离JPanel并使用Canvas代替。 看看Canvas如何与这个类中的缓冲策略一起使用,它可以处理屏幕上绘制的数百个事物,具有完美的平滑性和无闪烁(游戏也在10ms的睡眠循环上运行)。

不确定它是否能解决您的问题,但您可以考虑使用1维数组。

int width; 是你的屏幕/平铺的宽度/你循环的任何东西和int height是你做的以下高度:

而不是你做了什么:

 for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { // dosomething with your array myarray[x][y]; } } 

你可以通过这种方式

 for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { // dosomething with your array myarray[x + y * width]; } }