Java 我在减少图像闪烁方面有问题

Java 我在减少图像闪烁方面有问题,java,swing,awt,paint,Java,Swing,Awt,Paint,闪烁并不总是发生,但是当它发生时(大约50%的时间),它是非常糟糕的。我试着做了一些事情,最初我使用的是canvas,然后我尝试更改为jpanel并覆盖paintcomponent,但问题仍然存在 我使用两种不同的方法来绘制,我在主循环中调用它们(第一种方法绘制背景地形,第二种方法在上面绘制图像),速度为60 fps 这就是我创建Jpanel的方式: private void createDisplay(){ frame = new JFrame(title); //linha m

闪烁并不总是发生,但是当它发生时(大约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();
}    
这是地形的第一种绘制方法(很长,我只包括第一部分):

这是在地形(或背景)顶部绘制图像的最后一种绘制方法:

公共静态组件(图形g){
//Código Comum a todas作为班级
//bs=Display.getCanvas().getBufferStrategy();
//如果(bs==null){
///Display.getCanvas().createBufferStrategy(3);
//返回;
//}
g=Display.getCanvas().getGraphics();
//g、 clearRect(0,0510510);
//敌人
p=0;
//同时,作为一个整体,作为一个增量p,作为一个变量,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为
while(p0.05){
//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,(int)Main.enemylist.get(p).targetx-16,(int)Main.enemylist.get(p).targety-16,null);
}
p++;
}
//单位
p=0;
//同时,作为一个整体,作为一个增量p,作为一个变量,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为一个整体,作为
while(p0.05){
//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、 处置();
}

我希望我能很好地解释我的问题,并且我包括了所有需要的内容,我对java和编程相当陌生,希望它不会很混乱。

默认情况下,JPanel是双缓冲的,可以防止闪烁。这依赖于在唯一的事件调度线程上传入的事件,然后调用paintComponent。例如,
repaint(50L)
也可以手动(间接)调用此paintComponent

动画可以通过一个摆动计时器,通过一个周期性调用的方法来完成

这将取代
while
循环

这是一个由内而外的过程,但它消除了处理所有事务的长循环。一种是编写单独的事件处理程序,例如,按下键可以增加
速度
计数器等

在paintComponent中,通常不需要清晰的颜色。其余部分的优化是一个创造性的问题。例如,一个.png图像可以有透明度,这样你就可以制作一个完整的有孔帧图像

g = Display.getCanvas().getGraphics();     
不要使用getGraphics()方法

paintComponent()方法已具有图形对象。那是你应该用来作画的东西

您还应具备: 超级组件(g)


在方法的顶部清除面板的背景。这比使用带有硬编码值的clearRect(…)方法要好。

1)要更快获得更好的帮助,请发布(最小完整可验证示例)或(简短、自包含、正确的示例)。2) 例如,获取图像的一种方法是热链接到中看到的图像。进一步提示:1)使用逻辑一致的代码行和代码块缩进形式。缩进的目的是使代码的流程更易于遵循!2) 在源代码中只需要一行空白就可以了。
{
之后或
}
之前的空行通常也是多余的。3)
static
不是你的朋友。它经常破坏事物而不是修复它们。看起来你在绘画方法中绘制了大量的图像。也许您可以尝试减少绘制的图像数量,如果您将4个相邻图像放在一个图像中,这将大大降低性能影响。或者,如果这是不可能的,您可以让java构建一个当前的大图像,包括所有的小图像,然后绘制一个更大的图像。(只是一个想法,不知道代码应该是什么样子)@OfficerBacon谢谢你的回复,我有很多图像,因为背景是由许多不同的瓷砖组成的,我在每个瓷砖上分别画一个图像。“这可能是导致闪烁的原因吗?”安德烈·霍姆普森谢谢你的帮助,下次我会尽量把东西整理得更好。我已经注意到了静态可能产生的问题,我将尽可能避免它,但是很多时候我不能,因为“你不能对非静态方法错误进行静态引用”,我想我应该读一下这个主题,并尝试改进Ethank以获得你的帮助。我做了一些改变,尝试使用super.paintComponent(g);而不是getGaphics();然而,我得到了一个java.lang.NullPointerException。如果使用旧的行:g=Display.getCanvas().getGraphics();问题没有发生。@Aquan1111,在使用传递给Swing组件的paintComponent()方法的图形对象时,我从未遇到过NPE,所以我不知道您在做什么。我建议您先从上的Swing教程开始学习基础知识,然后再编写更复杂的绘画代码。谢谢您的回答,我已经发布了另一个问题,我想我可以更好地解释这个问题,如果您也希望看到它的网址:
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(); 

}
g = Display.getCanvas().getGraphics();