我正在尝试绘制背景图像,然后在其上绘制一个角色。我的代码工作,直到我加入睡眠,我没有得到1500 fps。
package sylvyrfysh.screen;
import javax.swing.*;
import java.awt.*;
import game.infos.Information;
public class ImageLoadDraw extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(){
DisplayMode dm=new DisplayMode(Information.sX,Information.sY,16,DisplayMode.REFRESH_RATE_UNKNOWN);
ImageLoadDraw i = new ImageLoadDraw();
i.run(dm);
}
public void run(DisplayMode dm){
setBackground(Color.PINK);
setForeground(Color.WHITE);
setFont(new Font("Arial",Font.PLAIN,24));
s=new Screen();
try{
loadpics();
s.setFullScreen(dm,this);
try{
Thread.sleep(10000);
}finally{
doRun=false;
s.restoreScreen();
}
}catch(Exception e){
e.printStackTrace();
}
}
private void loadpics() {
bg=new ImageIcon("src/sylvyrfysh/screen/maze_icon.png").getImage();
chara=new ImageIcon("src/sylvyrfysh/screen/char.png").getImage();
repaint();
}
public void paint(Graphics g){
if(g instanceof Graphics2D){
Graphics2D g2=(Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
while(true&&doRun){
g.drawImage(bg,0,0,null);
g.drawImage(bg,0,480,null);
g.drawImage(bg,360,0,null);
g.drawImage(bg,360,480,null);
g.drawImage(bg,720,0,null);
g.drawImage(bg,720,480,null);
g.drawImage(chara,imgX,imgY,null);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Screen s;
public static int imgX=0;
private int imgY=525;
private Image bg,chara;
private Boolean doRun=true;
}
关于导致它的原因和解决方法的任何想法?就像我说的那样,没有睡觉就行得很好。
答案 0 :(得分:1)
Swing是一个单线程框架。这就是所有UI交互和修改都应该在事件调度线程的内容中执行,包括重绘请求。
任何停止,阻止或以其他方式阻止此线程运行的内容都将阻止EDT处理新事件,包括重绘请求。从本质上讲,这将使程序看起来已挂起(或停止响应),因为它有。
在run
方法中,您呼叫Thread.sleep
。这可能会阻止EDT处理新事件,但是因为你实际上已经从“主”线程调用了该方法,所以它实际上可以工作,但是...
在paint
方法中,您有一个无限循环和一个Thread.sleep
调用。这些将阻止EDT运行,因为在EDT的上下文中调用了paint
。
在某些系统上,绘图并不总是立即发生,直到paint
方法返回,它可能不会被推送到设备进行输出,所以,即使是在paint
内循环的想法无论它会给EDT带来什么问题,无论如何都是一个坏主意。
与其他一些UI框架不同,您不需要实现“主循环”,Swing会为您解决此问题。
相反,在paint
方法中,您应该简单地描绘您为该周期绘制所需的内容并退出。
相反,你应该做点像......
public void paint(Graphics g){
// Painting is a complex series of chained methods, failing to call super.paint
// to cause significant issues
super.paint(g);
// Graphics is guaranteed to be an instance of Graphics2D since I think 1.4
// You should create a copy, so any changes you make are not carried onto the
// next component, Graphics is shared between all the components being painted
// in this paint cycle.
Graphics2D g2=(Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(bg,0,0,null);
g2.drawImage(bg,0,480,null);
g2.drawImage(bg,360,0,null);
g2.drawImage(bg,360,480,null);
g2.drawImage(bg,720,0,null);
g2.drawImage(bg,720,480,null);
g2.drawImage(chara,imgX,imgY,null);
// If you create, you should dispose of it...
g2.dispose();
}
...代替
而不是Thread.sleep
你应该使用像javax.swing.Timer
这样的东西,例如......
s=new Screen();
try{
loadpics();
s.setFullScreen(dm,this);
Timer timer = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
s.restoreScreen();
}
});
timer.setRepeats(false);
timer.start();
}catch(Exception e){
e.printStackTrace();
}
请查看Concurrency in Swing了解详情。
您还应该避免覆盖顶级容器,尤其是覆盖paint
。绘制一系列复杂的链式方法调用,每个调用执行一个特定的工作,相互叠加以产生最终结果。
相反,您应该从某种自定义组件开始,例如从JPanel
延伸,并覆盖它的paintComponent
方法,确保在执行任何操作之前调用super.paintComponent
你自己画画。
请查看Performing Custom Painting了解详情
答案 1 :(得分:0)
这一个Thread.sleep(10000);
关闭一切10秒钟。这不是你想要的。即使是30毫秒(约30帧/秒)也不是你想要的,因为它甚至会停止输入等。
你应该使用Timer。它在另一个线程中运行计时,并且它会在给定的milisec数量下自动休眠和唤醒该线程,因此它不会影响您的程序,并且只能在30milisec之后调用它。
仍然要有良好的应用程序,这个计时器应该具有较低的值,你应该计算通过System.nanoTime()
多长时间,例如每30milisec重新绘制一次,但是每个5milisec读取输入等。
答案 2 :(得分:0)
我认为 - >这是因为你需要调用loadpics()
并行,试试这个
public void run(DisplayMode dm){
setBackground(Color.PINK);
setForeground(Color.WHITE);
setFont(new Font("Arial",Font.PLAIN,24));
s=new Screen();
loadpics();
s.setFullScreen(dm,this);
try{
new Thread(new Runnable() {
@Override
public void run() {try {Thread.sleep(1000);doRun=false;s.restoreScreen();} catch (Exception e) {}
}
}).start();
}
还将doRun
设置为易失性。
private Boolean doRun=true;