java 当我重绘太多时停止摆动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17965850/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stop flickering in swing when i repaint too much
提问by sanchixx
I am making an RPG with a tilemap. To generate the tilemap i loop through a 2 dimensional array but that means that when I repaint I have to do that each time. If I repaint too much the screen flickers how could I stop this.
我正在制作带有 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;
}
}
}
}
Thank you for your help
谢谢您的帮助
Edit
编辑
Using javax.swing.Timer
removes all flickering even with a 10 ms delay.
javax.swing.Timer
即使有 10 毫秒的延迟,使用也会消除所有闪烁。
回答by MadProgrammer
A number of small things jump out at me.
一些小事情突然出现在我身上。
Firstly. You might be better using javax.swing.Timer
instead of java.util.Timer
, this will at least allow the events to flow a little better.
第一。您可能会更好地使用javax.swing.Timer
而不是java.util.Timer
,这至少可以让事件更好地流动。
Secondly, 10 milliseconds is to short a time period, seriously, you don't need 100fps, 60fps is about 17 milliseconds, I normally use 40 milliseconds for 25fps. This might give the EDT some breathing room to actually respond to the repaint requests.
其次,10毫秒是缩短一个时间段,说真的,你不需要100fps,60fps大约是17毫秒,我一般用40毫秒换25fps。这可能会给 EDT 一些喘息的空间来实际响应重绘请求。
Thirdly, you should be using paintComponent
instead of paint
. It's low enough in the call chain to guaranteed to be double buffered
第三,你应该使用paintComponent
而不是paint
. 它在调用链中足够低以保证双缓冲
Fourthly, you should avoid calling any method that might reschedule a repaint
(like setDoubleBuffered
for example, to this in the constructor if you must, but, Swing components are double buffered by default)
第四,您应该避免调用任何可能重新安排 a 的方法repaint
(setDoubleBuffered
例如,如果必须的话,可以在构造函数中调用this,但是,Swing 组件默认情况下是双缓冲的)
Fifthly, where possible, paint all "static" or slow changing content to a backing buffer and paint that instead. This will increase the speed at which paint
can work as it doesn't get stuck in a lot of small loops.
第五,在可能的情况下,将所有“静态”或缓慢变化的内容绘制到后备缓冲区并进行绘制。这将提高paint
可以工作的速度,因为它不会卡在很多小循环中。
You may want to take a look at Painting in AWT and Swingfor more details about the paint process
您可能需要查看在 AWT 和 Swing中绘制以了解有关绘制过程的更多详细信息
Some additional examples...
一些额外的例子...
- Swing animation running extremely slow- was able to go from 500 elements up to 4500 elements moving on the screen at one time - talks about resource management as well
- Java Bouncing Ball
- How to make line animation smoother?
- the images are not loading
- Swing 动画运行速度极慢- 一次可以从 500 个元素增加到 4500 个元素在屏幕上移动 - 也谈到了资源管理
- Java弹跳球
- 如何使线条动画更流畅?
- 图像未加载
And because kleo scares me (and it's also a good idea), you should also take a look at How to use Key Bindings, which will solve your focus issues with the KeyListener
因为 kleo 吓到我了(这也是个好主意),你还应该看看如何使用键绑定,这将解决你的焦点问题KeyListener
回答by Qwerky
You have set double buffering on the panel, but the things you are drawing on it yourself are not being double buffered. Calling setDoubleBuffered(true)
only applies buffering for child components of the container.
您在面板上设置了双缓冲,但您自己在其上绘制的内容并未被双缓冲。调用setDoubleBuffered(true)
仅对容器的子组件应用缓冲。
You need manually buffer stuff you draw yourself.
您需要手动缓冲您自己绘制的内容。
I would suggest moving away from a JPanel
and use a Canvas
instead. Have a look at how a Canvas
is used with a buffer strategy in this class, where it can handle hundreds of things being drawn on screen with perfect smoothness and no flickering (the game runs on a 10ms sleep loop too).
我建议远离 aJPanel
并使用 aCanvas
代替。看看 aCanvas
是如何与此类中的缓冲策略一起使用的,它可以处理在屏幕上绘制的数百个事物,并且具有完美的平滑度和无闪烁(游戏也以 10 毫秒的睡眠循环运行)。
回答by Loki
Not really sure if it solves your problem, but you can consider to use a 1dimensional array.
不确定它是否能解决您的问题,但您可以考虑使用一维数组。
when int width;
is the width of your screen/tile/whatever you loop and int height
is the height you coud do the following:
什么时候int width;
是你的屏幕/瓷砖/任何你循环的宽度,int height
是你可以执行以下操作的高度:
instead of, what you do:
而不是,你做什么:
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
// dosomething with your array
myarray[x][y];
}
}
you could go through this way
你可以通过这种方式
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
// dosomething with your array
myarray[x + y * width];
}
}