在没有重绘()的情况下在JFrame上移动图像

时间:2011-08-18 23:49:56

标签: java image swing jframe repaint

我正在尝试建立一个2D游戏。

我有一个静态的背景图像和一个角色的图像。当我按下一个移动键(WASD)时,Mainclass(是keylistener)在一个名为Player的类中调用一个函数。该函数正在改变角色的位置(Image)。在调用此函数后,我使用repaint()重新绘制新位置上的字符。 如果我删除背景我可以看到旧图像仍然从其他位置。因此,我必须重新绘制每个步骤的播放器和背景。

可能有更好的解决方案吗?最糟糕的情况:这是一个在线游戏,并且有很多玩家四处移动,每100毫秒重新调用一次,每个玩家的位置都需要更新。我有一种感觉,这将夺走玩家电脑的所有记忆,或者至少游戏不会感觉那么好

5 个答案:

答案 0 :(得分:4)

不要直接在JFrame内容窗格中绘画。相反,在paintComponent()中覆盖JComponent。此AnimationTest绘制为JPanel,默认为双缓冲。该示例还显示了一种检查用于绘画的时间预算的方法。

答案 1 :(得分:2)

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

答案 2 :(得分:2)

我认为重绘是唯一的解决方案,我曾经创建了一个2D汽车模拟游戏,这就是我做的,我也改变了所有Car对象的坐标,然后重新绘制整个事物。我试图在没有任何问题的情况下模拟以100毫秒重新绘制的2000个Car对象。嘿嘿好玩

答案 3 :(得分:1)

  

(我在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的标签提供背景图像和图像。

答案 4 :(得分:0)

可以有效地重新绘制组件的部分。阅读此tutorial

基本上你必须拨打component.repaint(posX, posY, length, height) 两次: 一旦在他的旧玩家形象位置(将重新绘制背景)然后在新位置。

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