Управление анимацией спрайтов с использованием потоков

#java #multithreading #animation

#java #многопоточность #Анимация

Вопрос:

Я нахожусь в процессе создания моей собственной двумерной игры. Каждый объект в игровом мире имеет объект-спрайт, и когда экран отрисовывается, спрайт объекта отрисовывается в местоположении объекта.

Класс sprite может представлять собой либо одно изображение, либо серию изображений, используемых для создания анимируемого спрайта.

 import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
public class Sprite implements Runnable{
    private int currentImage;   
    private BufferedImage[] sprites;
    private int delayMS;
    private Thread animation;

    public Sprite(BufferedImage sprite){
        sprites = new BufferedImage[1];
        sprites[0] = sprite;
    }

    public Sprite(BufferedImage[] spriteAnimation,int delay){
        this.sprites = spriteAnimation;
        currentImage = 0;
        delayMS = delay;
        //start a thread to time animation
        animation = new Thread(this);
        animation.start();
    }

    private void next(){
        if(currentImage < sprites.length - 1)
            currentImage  ;
        else
            currentImage = 0;
    }

    public void run() {
        while (Thread.currentThread() == animation) {
            //delay the animation for delayMS
            try {
                Thread.sleep(delayMS);
            } catch (InterruptedException e) {
                break;
            }
            //next image
            next();
        }
    }

    public void draw(Graphics2D g,int x,int y){
        g.drawImage(sprites[currentImage],null,x,y);
    }
}
  

Я не смог найти никакой достоверной информации по вопросу использования потоков для запуска многих анимаций, и мне было интересно, был ли это лучший подход.
Все работает отлично, пока я не выброшу в мир 200ish идентичных объектов. Частота кадров в секунду начинает снижаться, и некоторые анимированные спрайты начинают менять кадры в разное время. Это имело бы смысл, поскольку потоки начали бы задерживаться при создании экземпляра.

Мои вопросы заключаются в том, существует ли более эффективный способ справиться с этим, позволяющий мне использовать больше объектов без значительной потери кадров в секунду и синхронизировать поток / нити, чтобы анимации переключали кадры вместе.

Комментарии:

1. я не разбираюсь в анимации, но я знаю о потоковой обработке. вы должны сделать переменную члена currentImage изменчивой, чтобы обновления были видны между различными потоками. кроме того, запуск потока в конструкторе — это почти всегда плохой дизайн (если я когда-нибудь захочу создать подкласс этого класса, поток запустится до того, как класс будет полностью сконструирован). используйте статический вспомогательный метод для создания класса и запуска потока (после полной сборки).

Ответ №1:

Обычный способ сделать это — создать игровой цикл, который знает все спрайты и вызывает метод рисования для них (или, предпочтительно, только для тех, которые необходимо перерисовать) для каждого кадра. Таким образом, всякий раз, когда спрайт решает, что хочет анимировать, он не будет делать этого до следующего кадра. Просто выполните анимацию метода draw, например, следующей части (). И, конечно, в игровом цикле вы устанавливаете свою задержку, которая будет определять fps.

Чтобы получить анимацию, не зависящую от частоты кадров, вы делаете то же самое, но добавляете аргумент к методу draw, который сообщает, сколько времени прошло с момента последнего рисования, затем вычисляете объем анимации на основе этого.

Комментарии:

1. Спасибо, я пробовал это до того, как увидел кое-что о потоках, и мне следовало придерживаться этого. Работает намного лучше. К счастью, я использовал время между кадрами для физики, поэтому мне просто нужно было изменить параметры для класса sprite, и я был в пути.

Ответ №2:

Вместо того, чтобы запускать каждый спрайт в своем собственном потоке, вы могли бы поместить спрайты в контейнер и в потоке рендеринга перебирать все видимые спрайты и рисовать их (вы могли бы даже реализовать приоритеты спрайтов, отображать фоновые слои перед спрайтами, …).

Ответ №3:

если вы используете больше потоков для спрайтов (т. Е. один поток для одного спрайта), то это съест ваш процессор и он зависнет. Лучший способ реализовать анимацию в играх — это для каждого цикла выполнения потока изменять последовательности анимации (например, следующее изображение или предыдущее при нажатии клавиш) и рисовать спрайты в конце. Здесь, если будет больше спрайтов, и рисование займет больше времени, тогда FPS упадет за раз, максимум за два или три потока с синхронизацией