如何消除动画过程中出现的闪烁?

发布于 2024-08-10 10:46:27 字数 697 浏览 6 评论 0原文

我正在通过在 JApplet 中制作一个小游戏来学习 Java。 我的精灵动画遇到了一些问题。

这是代码:

this.sprite.setBounds(0,0,20,17);

this.sprite.setIcon(this.rangerDown);
for(int i = 0; i< 16;i++)
{
    this.sprite.setBounds(this.sprite.getX(), this.sprite.getY()+1, 20, 17);
    this.sprite.update(this.sprite.getGraphics());

    try{
        Thread.currentThread().sleep(100);
    }catch(InterruptedException e){
}

}

它在动画过程中留下了一些闪烁。动画结束后,闪烁消失,但有点难看......我想我错过了一些步骤。 我使用这种方法是因为它目前可以提供更好的结果,但如果可能的话,我希望不使用 AWT,而是使用 Swing。

有什么想法可以消除闪烁吗?

感谢您的阅读。

屏幕截图(无法发布图片,抱歉)。

I'm learning Java by making a small game in a JApplet.
I got a little problem with my sprite's animation.

Here is the code :

this.sprite.setBounds(0,0,20,17);

this.sprite.setIcon(this.rangerDown);
for(int i = 0; i< 16;i++)
{
    this.sprite.setBounds(this.sprite.getX(), this.sprite.getY()+1, 20, 17);
    this.sprite.update(this.sprite.getGraphics());

    try{
        Thread.currentThread().sleep(100);
    }catch(InterruptedException e){
}

}

It left some flicker during the animation. Once the animation end, the flicker disappears, but it's kind of ugly... I guess there is some step I missed.
I use this method because it gives the better result for now, but I would like to stay without AWT if possible, using Swing instead.

Any ideas how to get rid of the flicker?

Thanks for reading.

Screenshoot (Can't post images, sorry).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情深如许 2024-08-17 10:46:27

这不是影子。它是你的精灵的边界。它只是恰好是黑色的并且看起来像一个阴影。如果你改变精灵的移动量(比如 50 像素,而不仅仅是 1),你就会明白我的意思。

要解决这个问题,您需要做的是每次更新精灵位置时也绘制背景。尽管这可能会产生闪烁。

正确的方法是改变绘制对象的方式。您需要重写面板的paintComponent方法,然后在每次更新精灵的位置时调用repaint。

编辑:

请参阅此代码示例以了解基本用法。注意:这不是使用线程编写动画的方式。我写这个是为了向您展示 PaintComponent 方法中的内容,并编写动画线程来向您展示您提到的“阴影”已经消失。线程中永远不要有非结束的运行循环:)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame("Test");
        MyPanel c = new MyPanel();
        f.getContentPane().add(c);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(350, 100);
        f.setVisible(true);
    }

}

class MyPanel extends JPanel {

    int x = 0;
    boolean toTheRight = true;

    public MyPanel() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    x = (toTheRight)?x+5:x-5;
                    if (x>300)
                        toTheRight = false;
                    if (x<0)
                        toTheRight = true;
                    repaint();
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g.create();
        g2.setPaint(Color.white);
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.setPaint(Color.red);
        g2.fillOval(x-2, 50, 4, 4);
    }

}

This is not a shadow. Its the border of your sprite. It just happens to be black and appears as a shadow. If you change the amount you shift your sprite (lets say by 50 pixels, not just 1) you will see what i mean.

To fix it what you need to do is to draw the background as well each time you update the location of your sprite. Although this will probably produce flickering.

The correct way to do it is to change the way you draw your objects. You need to override the paintComponent method of your panel and then simply call repaint each time you have updated the locations of your sprites.

EDIT:

See this code sample for basic usage. NOTE: This is NOT how you should write animation using Threads. I wrote that to show you what goes in the paintComponent method and wrote the animation Thread to show you that the "shadow" you mentioned is gone. NEVER have a non ending run loop in a thread :)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame("Test");
        MyPanel c = new MyPanel();
        f.getContentPane().add(c);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(350, 100);
        f.setVisible(true);
    }

}

class MyPanel extends JPanel {

    int x = 0;
    boolean toTheRight = true;

    public MyPanel() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    x = (toTheRight)?x+5:x-5;
                    if (x>300)
                        toTheRight = false;
                    if (x<0)
                        toTheRight = true;
                    repaint();
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g.create();
        g2.setPaint(Color.white);
        g2.fillRect(0, 0, getWidth(), getHeight());
        g2.setPaint(Color.red);
        g2.fillOval(x-2, 50, 4, 4);
    }

}
谢绝鈎搭 2024-08-17 10:46:27

问题是双缓冲。

在小程序中:
双缓冲几乎是自动完成的。在您的方法中调用 repaint() 而不是 Paint。

在 Swing 中,有很多方法可以做到这一点。我通常选择 BufferStrategy 路线。当您初始化框架时,请执行以下操作:

JFrame frame;
... code to init frame here
frame.createBufferStrategy(2);

然后在绘制方法中:

Graphics g = getBufferStrategy().getDrawGraphics();
..code to do drawing here...
g.dispose();
getBufferStrategy().show();

The problem is double buffering.

In Applets:
Double buffering is done almost automatically. Call repaint() instead of paint in your method.

In Swing, there are many ways to do it. I usually go for the BufferStrategy route. When you're initializing your frame, do this:

JFrame frame;
... code to init frame here
frame.createBufferStrategy(2);

Then in your draw methods:

Graphics g = getBufferStrategy().getDrawGraphics();
..code to do drawing here...
g.dispose();
getBufferStrategy().show();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文