在 JFrame 上移动图像而不使用 repaint()

发布于 2024-11-30 05:59:56 字数 301 浏览 1 评论 0原文

我正在尝试制作一款 2d 游戏。

我有一个静态的背景图像和一个角色图像。当我按下移动键(WASD)时,主类(按键监听器是)调用名为 Player 的类中的函数该函数正在更改角色(图像)的位置。调用此函数后,我使用 repaint() 在新位置重新绘制角色。 如果我删除背景,我可以看到其他位置仍然留下的旧图像。所以这意味着我必须为每一步重新绘制播放器和背景。

对此可能有更好的解决方案吗?最坏的情况:这是一款在线游戏,有很多玩家在移动,每 100 毫秒就会调用重绘来更新每个玩家的位置。我有一种感觉,这会耗尽玩家电脑的所有内存,或者至少游戏感觉不会那么好

I'm trying to build a 2d game.

I have a background-image that static and an Image of the character. When i press a move-key (WASD) the Mainclass (were the keylistener is) calling a function in a class called Player The function is changing the location of the character (Image). And after this function is called i use repaint() to repaint the character on new position.
If i remove the background i can see the old images still left from the other positions. So this meens i have to repaint the player and the background for each step.

There might be a better solution for this? Worst case scenario: It's an onlinegame and there are many players moving around and each 100 milliseconds the repaint is called for update every players posisions. I have a feeling this will take out all the memory of the players computer or at least the game will not feel so good

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

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

发布评论

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

评论(5

最丧也最甜 2024-12-07 05:59:56

不要直接在 JFrame 内容窗格中绘制。相反,请在 JComponent 中重写 paintComponent()。这个AnimationTest 绘制到 JPanel 中,默认情况下它是双缓冲的。该示例还展示了一种检查绘画时间预算的方法。

Don't paint directly in the JFrame content pane. Instead, override paintComponent() in a JComponent. This AnimationTest draws into a JPanel, which is double buffered by default. The example also shows one approach to examining the time budget devoted to painting.

稀香 2024-12-07 05:59:56

据我所知,没有其他解决办法。在大多数计算机上,每 100 毫秒重新绘制一次通常不会占用太多内存。

As far as I know, there is no other solution. Repainting every 100 ms generally isn't too memory intensive on most computers.

糖粟与秋泊 2024-12-07 05:59:56

我认为重新绘制是唯一的解决方案,我曾经创建了一个 2d 汽车模拟游戏,这就是我所做的,我还更改了所有汽车对象的坐标,然后重新绘制整个事物。我尝试模拟 2000 个以 100 毫秒重新绘制速度运行的汽车对象,并且没有出现任何问题。呵呵有趣

I think repaint is the only solution, I once created a 2d car simulation game and that's what i do, I also change the coordinates of all Car objects and then repaint the whole thing. I tried to simulate 2000 Car objects running at 100 ms repaint on all of them without trouble. hehe fun

各自安好 2024-12-07 05:59:56

(我在jframe内使用了jpanel)并使用java.awt.image的bufferedimage

相反,您可以尝试使用带有图标的 JLabel。然后您要做的就是调用标签的 setLocation(...) 方法。 Swing RepaintManager 将在重新绘制旧位置和新位置后进行处理。

这是一个帮助您入门的示例。此示例对每个图像使用单独的计时器。在游戏中,当单个计时器触发时,您将同时重置所有图像的位置。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AnimationBackground extends JLabel implements ActionListener
{
    int deltaX = 2;
    int deltaY = 3;
    int directionX = 1;
    int directionY = 1;

    public AnimationBackground(
        int startX, int startY,
        int deltaX, int deltaY,
        int directionX, int directionY,
        int delay)
    {
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        this.directionX = directionX;
        this.directionY = directionY;

        setIcon( new ImageIcon("dukewavered.gif") );
        setSize( getPreferredSize() );
        setLocation(startX, startY);
        new javax.swing.Timer(delay, this).start();
    }

    public void actionPerformed(ActionEvent e)
    {
        Container parent = getParent();

        //  Determine next X position

        int nextX = getLocation().x + (deltaX * directionX);

        if (nextX < 0)
        {
            nextX = 0;
            directionX *= -1;
        }

        if ( nextX + getSize().width > parent.getSize().width)
        {
            nextX = parent.getSize().width - getSize().width;
            directionX *= -1;
        }

        //  Determine next Y position

        int nextY = getLocation().y + (deltaY * directionY);

        if (nextY < 0)
        {
            nextY = 0;
            directionY *= -1;
        }

        if ( nextY + getSize().height > parent.getSize().height)
        {
            nextY = parent.getSize().height - getSize().height;
            directionY *= -1;
        }

        //  Move the label

        setLocation(nextX, nextY);
    }

    public static void main(String[] args)
    {
        JPanel panel = new JPanel(null)
        {
            Image image = new ImageIcon("mong.jpg").getImage();

            protected void paintComponent(Graphics g)
            {
                g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
                super.paintComponent(g);
            }
        };
        panel.setOpaque(false);
//      panel.add( new AnimationBackground(10, 10, 2, 3, 1, 1, 10) );
        panel.add( new AnimationBackground(300, 100, 3, 2, -1, 1, 20) );
        panel.add( new AnimationBackground(200, 200, 2, 3, 1, -1, 20) );
        panel.add( new AnimationBackground(50, 50, 5, 5, -1, -1, 20) );
//      panel.add( new AnimationBackground(0, 000, 5, 0, 1, 1, 20) );
        panel.add( new AnimationBackground(0, 200, 5, 0, 1, 1, 80) );

        JFrame frame = new JFrame();
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(400, 400);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

您需要为代码创建 ImageIcon 的标签提供背景图像和图像。

(i used a jpanel inside the jframe) and use bufferedimage of java.awt.image

Instead you can try using a JLabel with Icons. Then all you do is invoke the setLocation(...) method of the label. The Swing RepaintManager will look after repainting the old location and the new location.

Here's an example to get you started. This example uses separate Timers for each image. In your game you would reset the location of all images at the same time when your single Timer fires.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AnimationBackground extends JLabel implements ActionListener
{
    int deltaX = 2;
    int deltaY = 3;
    int directionX = 1;
    int directionY = 1;

    public AnimationBackground(
        int startX, int startY,
        int deltaX, int deltaY,
        int directionX, int directionY,
        int delay)
    {
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        this.directionX = directionX;
        this.directionY = directionY;

        setIcon( new ImageIcon("dukewavered.gif") );
        setSize( getPreferredSize() );
        setLocation(startX, startY);
        new javax.swing.Timer(delay, this).start();
    }

    public void actionPerformed(ActionEvent e)
    {
        Container parent = getParent();

        //  Determine next X position

        int nextX = getLocation().x + (deltaX * directionX);

        if (nextX < 0)
        {
            nextX = 0;
            directionX *= -1;
        }

        if ( nextX + getSize().width > parent.getSize().width)
        {
            nextX = parent.getSize().width - getSize().width;
            directionX *= -1;
        }

        //  Determine next Y position

        int nextY = getLocation().y + (deltaY * directionY);

        if (nextY < 0)
        {
            nextY = 0;
            directionY *= -1;
        }

        if ( nextY + getSize().height > parent.getSize().height)
        {
            nextY = parent.getSize().height - getSize().height;
            directionY *= -1;
        }

        //  Move the label

        setLocation(nextX, nextY);
    }

    public static void main(String[] args)
    {
        JPanel panel = new JPanel(null)
        {
            Image image = new ImageIcon("mong.jpg").getImage();

            protected void paintComponent(Graphics g)
            {
                g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
                super.paintComponent(g);
            }
        };
        panel.setOpaque(false);
//      panel.add( new AnimationBackground(10, 10, 2, 3, 1, 1, 10) );
        panel.add( new AnimationBackground(300, 100, 3, 2, -1, 1, 20) );
        panel.add( new AnimationBackground(200, 200, 2, 3, 1, -1, 20) );
        panel.add( new AnimationBackground(50, 50, 5, 5, -1, -1, 20) );
//      panel.add( new AnimationBackground(0, 000, 5, 0, 1, 1, 20) );
        panel.add( new AnimationBackground(0, 200, 5, 0, 1, 1, 80) );

        JFrame frame = new JFrame();
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(400, 400);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

You will need to provide a background image and an image for the label where the code creates an ImageIcon.

梦与时光遇 2024-12-07 05:59:56

仅重绘组件的一部分是有效的。阅读此教程

基本上你必须调用 component.repaint(posX, posY, length, height) 两次
一次在旧玩家图像位置(将重新绘制背景),然后在新位置。

(这个解决方案也是G_H在评论中提出的。)

There is efficient to redraw only part of your component. Read this tutorial.

Basically you have to call component.repaint(posX, posY, length, height) twice:
once at he old player image position (will repaint the background) and then at the new position.

(This solution was also proposed by G_H in the comments.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文