Переместить изображение в JFrame без перерисовки()

Я пытаюсь построить 2D-игру.

У меня есть статичное фоновое изображение и изображение персонажа. Когда я нажимаю клавишу перемещения (WASD), основной класс (где есть прослушиватель клавиш) вызывает функцию в классе с именем Player. Функция меняет местоположение персонажа (изображение). И после вызова этой функции я использую repaint(), чтобы перерисовать символ в новой позиции. Если я удалю фон, я увижу старые изображения, оставшиеся с других позиций. Так что это означает, что я должен перекрашивать плеер и фон для каждого шага.

Может быть лучшее решение для этого? Наихудший сценарий: это онлайн-игра, в которой перемещается много игроков, и каждые 100 миллисекунд вызывается перерисовка для обновления позиций каждого игрока. У меня такое ощущение, что это вытянет всю память компьютера игрока или, по крайней мере, игра не будет такой хорошей.


person Philip Andersson    schedule 18.08.2011    source источник
comment
Если вы можете определить ограничивающий прямоугольник для игрока, вы можете перекрасить только ту часть фона, после того как персонаж отойдет от него. Следует держать вещи быстро. Если персонаж движется плавно, а не прыгает по одной плитке за раз, перекрашиваемый прямоугольник можно сделать еще меньше. Однако, если персонажи могут двигаться по диагонали, вам понадобятся два прямоугольника.   -  person G_H    schedule 19.08.2011
comment
попробуйте переопределить paintComponent () jcomponent, как сказал thrashgod (я использовал jpanel внутри jframe), и используйте буферизованное изображение java.awt.image. это то, что я сделал.   -  person pif    schedule 19.08.2011


Ответы (5)


Не рисуйте прямо на панели содержимого JFrame. Вместо этого переопределите paintComponent() в файле JComponent. Это AnimationTest приводит к a JPanel, который по умолчанию имеет двойную буферизацию. Пример также показывает один из подходов к изучению бюджета времени, затрачиваемого на рисование.

person trashgod    schedule 19.08.2011

Насколько я знаю, другого решения нет. Перерисовка каждые 100 мс обычно не слишком интенсивно использует память на большинстве компьютеров.

person Jeffrey    schedule 18.08.2011
comment
Окей, спасибо за быстрый ответ. Тогда это так, как я думал. Просто когда я делаю шаги, иногда изображение игрока мигает. Это не большая проблема, но это дало мне ощущение, что я делаю это неправильно. Но, как вы говорите, другого решения нет, тогда я продолжаю... спасибо! - person Philip Andersson; 19.08.2011
comment
Если изображение мигает, попробуйте двойную буферизацию или даже тройная буферизация. - person Jeffrey; 19.08.2011

Я думаю, что перекрашивание - единственное решение, однажды я создал игру-симулятор 2D-машины, и это то, что я делаю, я также меняю координаты всех объектов Car, а затем перекрашиваю все это. Я попытался смоделировать 2000 объектов Car, работающих со скоростью 100 мс, перерисовать их все без проблем. хехе весело

person pif    schedule 19.08.2011
comment
для записи я переопределяю paintComponent () [не перекрашиваю ()] jPanel и использую java.awt.image.BufferedImage для своих автомобилей. лол все равно весело - person pif; 19.08.2011

(я использовал jpanel внутри jframe) и использовал буферизованное изображение java.awt.image

Вместо этого вы можете попробовать использовать 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.

person camickr    schedule 19.08.2011

Эффективно перерисовывать только часть вашего компонента. Прочтите этот руководство.

По сути, вам нужно вызвать component.repaint(posX, posY, length, height) дважды: один раз в старой позиции изображения игрока (будет перекрашивать фон), а затем в новой позиции.

(Это решение также было предложено G_H в комментариях.)

person toto2    schedule 19.08.2011