Прогулочная анимация

Итак, я просматривал исходный код Metagun Нотча и не могу понять, как ему удалось добиться анимации спрайтов. Прямо сейчас все, что я пытаюсь сделать, это перебрать некоторые изображения анимации ходьбы персонажа. Вот код, мой вывод пока показывает только первое изображение ходьбы, на котором персонаж стоит на месте: анимация пакета;

import java.awt.*;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.swing.JComponent;

public class SpriteAnimation extends JComponent{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    int frame=0;
    public void paint(Graphics g){
        try{
        BufferedImage still = ImageIO.read(SpriteAnimation.class.getResource("still.png"));
        BufferedImage walkRight = ImageIO.read(SpriteAnimation.class.getResource("right.png"));
        BufferedImage midWalk = ImageIO.read(SpriteAnimation.class.getResource("mid.png"));
        BufferedImage walkLeft = ImageIO.read(SpriteAnimation.class.getResource("left.png"));
        BufferedImage[] states={still,walkRight,midWalk};       
        int frame=0;
        do{
            frame++;
            if(frame>=3){
                frame=0;
                g.drawImage(states[frame],0,0,null);
            }
        }
        while(true);
        }catch(Exception e){

        }
    }


}

person user1058860    schedule 22.07.2013    source источник
comment
Перво-наперво: там не должно быть петли. paint вызывается каждый раз, когда компонент должен быть перерисован, но ваш код пытается действовать как основной цикл анимации, хотя на самом деле он должен просто отрисовывать один кадр. Цикл анимации должен контролироваться каким-то Timer, который просит окно перерисовывать себя каждые X миллисекунд, а ваш метод paint должен рисовать текущий кадр вашей анимации.   -  person asermax    schedule 23.07.2013
comment
1) Измените код формы catch (Exception e) { .. на catch (Exception e) { e.printStackTrace(); // very informative! .. 2) while(true); никогда не делайте этого в графическом интерфейсе!   -  person Andrew Thompson    schedule 23.07.2013
comment
1) Чтобы быстрее получить помощь, опубликуйте SSCCE. 2) Для пользовательского рисования в JComponent переопределите paintComponent(Graphics) вместо paint(Graphics).   -  person Andrew Thompson    schedule 23.07.2013


Ответы (2)


Я не знаю, почему другие ребята пошли дальше и просто попытались реорганизовать ваш код, даже не упомянув о реальной проблеме: если вы используете Swing для создания анимации, этот цикл представляет собой большой нет-нет. Делая это, вы в основном перегружаете EDT и останавливаете весь графический интерфейс.

Вы должны переписать свой код, чтобы ваш SpriteAnimation отрисовывал только один кадр каждый раз, когда вызывается метод paint, в то время как цикл анимации управляется внешним таймером.

Быстрый пример:

public class SpriteAnimation extends JComponent{
    private int currentFrame = 0;
    private BufferedImage[] frames;

    public SpriteAnimation(){
        /**
         * Load your frames
         */
    }

    public void paintComponent(Graphics g){
        currentFrame++;
        if(frame >= 3)
            frame = 0;

        // we pass this as the ImageObserver in case the images are 
        // loaded asynchronously
        g.drawImage(frames[currentFrame], 0, 0, this);                
    }
}

И в вашем основном методе:

// Timer is a swing timer
Timer timer = new Timer(
    100, 
    new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            // main frame is your main animation canvas (eg a JFrame)
            mainFrame.repaint();
        }
    });
timer.start();
person asermax    schedule 22.07.2013

Проблема здесь:

if(frame>=3){
    frame=0;
    g.drawImage(states[frame],0,0,null);
}

должно быть:

if(frame>=3){
    frame=0;
}
g.drawImage(states[frame],0,0,null);

кроме того, в вашем массиве states отсутствует walkLeft:

BufferedImage[] states={still,walkRight,midWalk};

что также означает, что вы, вероятно, хотите, чтобы ваше условие было frame > states.length в приведенном выше фрагменте.

ПРИМЕЧАНИЕ. Вам действительно следует использовать таймеры, как это предлагается в комментарии @asermax, но это должно исправить, по крайней мере, ошибки, которые у вас были.

person Luke    schedule 22.07.2013