3

嗨,我正在阅读 Ian Cinnamon 的《为邪恶天才编程视频游戏》一书。在其中一个项目中,他解释了如何为赛车游戏创建一些动画。我在下面写了一个简单的代码(删除“几乎”所有不必要的东西)。但结果是一样的:闪烁的.

我的问题是,如何通过使用相同的代码(显然几乎没有修改)让它停止闪烁?我的意思不是找到另一种方法(修改整个代码),因为我已经能够使用JLabelImageIcon类和 spritesheets 图像文件创建整个游戏。我的观点是在不移除这些形状的情况下解决闪烁问题 [ Rectangle (fillRect & if possible drawImage)]。

顺便说一句,如果这是不可能的“你为什么要那样做!?” 或“不可能”也是很好的答案。(让我们尽量不要使用它们!)

谢谢你!

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class Race extends JFrame {
    public static void main(String[] args){
        new Race();
    }
        private Rectangle r1 = new Rectangle(0,0,800,100);
        private Rectangle r2 = new Rectangle(0,100,100,400);
        Image img = null;

    public Race(){
        super("Some Title");
        setVisible(true);
        setSize(800,600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        try{
             URL url= this.getClass().getResource("someImage.png");
            img =Toolkit.getDefaultToolkit().getImage(url);
        }catch(Exception e){}
        Race.GameLoop gameHeart = new Race.GameLoop();
        gameHeart.run();
    }

    public void paint(Graphics g){
        super.paint(g);
        g.setColor(Color.GREEN);
        g.fillRect(r1.x, r1.y, r1.width, r1.height);
        g.setColor(Color.RED);
        g.fillRect(r2.x, r2.y, r2.width, r2.height);
        g.drawImage(img, r2.x, r2.y, r2.width, r2.height, this);
        try {
            Thread.sleep(75);
        } catch (InterruptedException ex) {}
        repaint();
    }

    public class GameLoop extends Thread {
        public void run(){
            while(true){
                //game animations and logic
                //even if I put repaint() here it still flicker
            }
        }
    }
}
4

2 回答 2

4

不要在顶级容器(如JFrame)上绘制,它们不支持双缓冲。

相反,使用类似的东西JPanel

约定更喜欢覆盖paintComponent而不是paint. 这样做主要是因为paint实际上是一种非常复杂的方法

切勿以任何paint方式这样做:

try {
    Thread.sleep(75);
} catch (InterruptedException ex) {}
repaint();

首先,任何延迟都应该由游戏线程处理,Thread#sleep在paint方法中调用将使事件调度线程进入睡眠状态,这将阻止它发布事件(关于鼠标和键盘交互)并使你的程序看起来没有响应,这将导致您以后出现问题。

永远不要从绘画方法内部调用repaint(或任何可能调用repaint的方法)。这只是要求重绘管理器安排另一个绘制周期,这将占用您的 CPU 直到您的程序变得无响应。同样,这是您的游戏线程的功能。

请记住,Swing不是线程保存。与 UI 的所有交互都必须在事件调度线程的上下文中进行。阅读Swing 中的并发以获取更多信息

你可以看看如何使线条动画更平滑?Java 弹跳球作为示例

您可能想阅读在 AWT 和 Swing 中执行自定义绘画和绘画

于 2012-11-26T20:00:29.077 回答
0

这是一个快速的答案(如果您太懒或没有时间阅读 MadProgrammer 和垃圾神在答案中给出的文档,顺便帮我写这个)。但我强烈建议您一有空闲时间就阅读文档。

这是重新编写的问题中的代码,因此不会闪烁。我将代码分为两个类:在 GameFrame 类中包含游戏的 JFrame 和在扩展 JPanel 的 Race 类中的赛车游戏本身(如问题中的一部分)。

GameFrame.java

import javax.swing.*;

public class GameFrame extends JFrame {

    public static void main(String args[]){
        new GameFrame();
    }

    public GameFrame(){
        super("Graphics with JFrame");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(800,600);
        Race game = new Race();
        this.getContentPane().add(game);
        this.setVisible(true);
        game.run();
    }

}

种族.java

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class Race extends JPanel implements Runnable {

    private Rectangle r1 = new Rectangle(0,0,800,100);
    private Rectangle r2 = new Rectangle(0,100,100,400);
    Image img = null;

    public Race(){
        try{
             URL url= this.getClass().getResource("someImage.png");
            img =Toolkit.getDefaultToolkit().getImage(url);
        }catch(Exception e){}
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.GREEN);
        g.fillRect(r1.x, r1.y, r1.width, r1.height);
        g.setColor(Color.RED);
        g.fillRect(r2.x, r2.y, r2.width, r2.height);
        g.drawImage(img, r2.x, r2.y, r2.width, r2.height, this);
}

    public void run() {
        while(true){
            try {
                Thread.sleep(75);
            } catch (InterruptedException ex) {}
            repaint();

            //game animations and logic
        }
    }
}

再次感谢 MadProgrammer 和垃圾神。很抱歉,我回答了我的问题而不是评论其他人的问题,但我必须明确表明之前和之后之间的区别。同样,如果您不明白我为什么要进行这些修改以避免闪烁。阅读 MadProgrammer 和垃圾神评论和答案。

于 2012-11-27T07:33:53.417 回答