停止闪烁的摆动,当我重新绘制太多 [英] Stop flickering in swing when i repaint too much

查看:242
本文介绍了停止闪烁的摆动,当我重新绘制太多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用tilemap制作RPG。要生成瓷砖地图i循环通过一个2维数组,但这意味着,当我重新绘制我必须这样做每次。如果我重新绘制太多的屏幕闪烁,我怎么能阻止这个。

  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自动生成的catch块
e.printStackTrace();
}
listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);

定时器timer =新的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 {
for(int y = 0; y< map [x] .length; y ++)
{
switch(map [x] [y])
{
case0:
g.setColor(Color.GREEN);
break;
case1:
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 )));
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;
}
}
}
}



c $ c>即使延迟10 ms,也会移除所有闪烁。

解决方案

/ p>

首先。你可能最好使用 javax.swing.Timer 而不是 java.util.Timer ,这将至少允许



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



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



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



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



您可以参阅在AWT和Swing中绘画





因为kleo恐吓我这也是一个好主意),您还应该查看如何使用键绑定,这将解决您的焦点问题与 KeyListener


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.

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.

解决方案

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.

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.

Thirdly, you should be using paintComponent instead of paint. It's low enough in the call chain to guaranteed to be double buffered

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)

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.

You may want to take a look at Painting in AWT and Swing for more details about the paint process

Some additional examples...

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

这篇关于停止闪烁的摆动,当我重新绘制太多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆