闪烁并不总是发生,但是当它发生时(大约50%的时间)它非常糟糕。我尝试做了一些事情,最初我使用的是canvas,然后我尝试更改为jpanel并覆盖paintcomponent,但问题仍在继续。
我使用两种不同的方法进行绘画,我在主循环上调用(第一个绘制背景地形,第二个绘制顶部的图像),速度为60 fps。
这就是我创建Jpanel的方式:
private void createDisplay(){
frame = new JFrame(title); //linha mais importante, é criada uma JFrame com as propriedades definidas em baixo
frame.setSize(width, height); //tamanho
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //linha necessário para que a operação acabe quando se sai da janela
frame.setResizable(false); //remove a opção de alterar o tamanho da janela
frame.setLocationRelativeTo(null); //definição da posição relativa, neste caso nula
frame.setVisible(true); //torna a janela visivel
canvas = new JPanel();
//canvas = new Canvas(); //inicialização da canvas
canvas.setPreferredSize(new Dimension(width, height)); //alteração do tamanho da canvas
canvas.setMaximumSize(new Dimension(width, height)); //tamanho máximo e minimo são definidos para que a
canvas.setMinimumSize(new Dimension(width, height)); //canvas tenha sempre o mesmo tamanho
frame.add(canvas); //linha essencial, adicina a canvas á jframe
frame.pack(); //necessário para que a canvas fique bemcentrada na frame (para que se veja toda a canvas)
frame.addMouseListener(new MouseInput());
canvas.addMouseListener(new MouseInput());
}
这是我的主类循环的一部分,我调用了paint方法:
@Override
public void run() {
init();
Terrain.init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
@SuppressWarnings("unused")
int ticks = 0;
long timer = 0;
while(running) {
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1){
gamepack.Terrain.paintComponent(g);
gamepack.Units.tick();
gamepack.Enemy.tick();
//gamepack.Enemy.render();
gamepack.Render.paintComponent(g);
ticks++;
delta--;
}
if(timer >= 1000000000){
//System.out.println(ticks); Verificação das actualizações (ticks e render por segundo)
ticks = 0;
timer = 0;
}
}
stop();
}
这是地形的第一种绘画方法(它很长,我只包括第一部分):
public static void paintComponent(Graphics g) {
// bs = Display.getCanvas().getBufferStrategy();
//if(bs==null) {
// Display.getCanvas().createBufferStrategy(3);
// return;
//}
g = Display.getCanvas().getGraphics();
g.clearRect(0, 0, 510, 510);
//Primeira Linha (1)
g.drawImage(grasstopleftcorner ,0,0, null); //1
g.drawImage(grasstopleftcorner ,34,0, null); //2
g.drawImage(path ,68,0, null); //3
g.drawImage(path ,102,0, null); //4
g.drawImage(grasstopleftcorner ,136,0, null); //5
g.drawImage(grasstopleftcorner ,170,0, null); //6
g.drawImage(grasstopleftcorner ,204,0, null); //7
g.drawImage(grasstopleftcorner ,238,0, null); //8
g.drawImage(grasstopleftcorner ,272,0, null); //9
g.drawImage(grasstopleftcorner ,306,0, null); //10
g.drawImage(grasstopleftcorner ,340,0, null); //11
g.drawImage(grasstopleftcorner ,374,0, null); //12
g.drawImage(grasstopleftcorner ,408,0, null); //13
g.drawImage(grasstopleftcorner ,442,0, null); //14
g.drawImage(grasstopleftcorner ,476,0, null); //15
//Segunda Linha (2)
g.drawImage(grasstopleftcorner ,0,34, null); //1
g.drawImage(grasstopleftcorner ,34,34, null); //2
g.drawImage(path ,68,34, null); //3
g.drawImage(path ,102,34, null); //4
g.drawImage(grasstopleftcorner ,136,34, null); //5
g.drawImage(grasstopleftcorner ,170,34, null); //6
g.drawImage(grasstopleftcorner ,204,34, null); //7
g.drawImage(grasstopleftcorner ,238,34, null); //8
g.drawImage(grasstopleftcorner ,272,34, null); //9
g.drawImage(grasstopleftcorner ,306,34, null); //10
g.drawImage(grasstopleftcorner ,340,34, null); //11
g.drawImage(grasstopleftcorner ,374,34, null); //12
g.drawImage(grasstopleftcorner ,408,34, null); //13
g.drawImage(grasstopleftcorner ,442,34, null); //14
g.drawImage(grasstopleftcorner ,476,34, null); //15
这是在地形(或背景)上绘制图像的最后一种绘画方法:
public static void paintComponent(Graphics g){
//Código Comum a todas as Classes
//bs = Display.getCanvas().getBufferStrategy();
//if(bs==null) {
/// Display.getCanvas().createBufferStrategy(3);
// return;
//}
g = Display.getCanvas().getGraphics();
//g.clearRect(0, 0, 510, 510);
//Enemies
p=0;
//Este while serve para actualizar as imagens de todas as unidades ao incrementar o p, todas as variáveis do drawimage são actualizadas no tick()
while(p<Main.enemylist.size()){
if(Main.enemylist.get(p).health > 0){
// g.drawImage(Main.castleimg,(int) 100,(int)100, null);
g.drawImage(Main.enemylist.get(p).usedimg.getSubimage(Main.enemylist.get(p).imgx*32, Main.enemylist.get(p).imgy*32 , 32, 32),(int) Main.enemylist.get(p).targetx - 16,(int) Main.enemylist.get(p).targety- 16, null);
}
p++;
}
//Units
p=0;
//Este while serve para actualizar as imagens de todas as unidades ao incrementar o p, todas as variáveis do drawimage são actualizadas no tick()
while(p<Main.dudelist.size()){
if(Main.dudelist.get(p).selected){
g.drawImage(Main.dotimage,(int) Main.dudelist.get(p).currentx + 7,(int) Main.dudelist.get(p).currenty - 19, null);
}
if (Main.dudelist.get(p).health > 0){
// g.drawImage(Main.castleimg,(int) 100,(int)100, null);
g.drawImage(Main.dudelist.get(p).usedimg.getSubimage(Main.dudelist.get(p).imgx*32, Main.dudelist.get(p).imgy*32 , 32, 32),(int) Main.dudelist.get(p).currentx ,(int) Main.dudelist.get(p).currenty, null);
}
p++;
}
g.dispose();
}
我希望我能很好地解释我的问题,并且我包含了所有需要的内容,对于java和编程来说还是一个新手,希望它不会让人感到困惑。
答案 0 :(得分:1)
默认情况下,JPanel是双缓冲的,可防止闪烁。这依赖于唯一的Event Dispatching Thread进入的事件,然后调用paintComponent。此paintComponent也可以通过例如repaint(50L)
手动(间接)调用。
动画可以通过Swing Timer完成,并定期调用方法。
这应该取代您的while
循环。
这有点内而外,但不会处理所有的长循环。一个人编写单独的事件处理程序,例如在按键时可以增加speed
计数器,等等。
在paintComponent中,不需要clear(通常)。其余的优化是创造性的问题。例如,.png图像可以具有透明度,因此您可以制作整个带孔的帧图像。
答案 1 :(得分:1)
g = Display.getCanvas().getGraphics();
不要使用getGraphics()方法。
paintComponent()方法已经有了一个Graphics对象。这是你应该用于绘画的对象。
您还应该: super.paintComponent方法(克);
在方法的顶部清除面板的背景。这比使用带有硬编码值的clearRect(...)方法更好。