Java: Наложение / наложение анимированного gif на другой анимированный gif

Я делаю небольшую игру. Это не экшн, а головоломка, поэтому производительность не так важна. Теперь у меня есть основная игровая область, фоновое изображение. В определенных случаях я хочу нарисовать другие изображения поверх частей фонового изображения. Моя проблема в том, что как фоновое изображение, так и наложенные изображения могут быть анимированными гифками с неизвестным количеством кадров (в основном, выбранными пользователем).

Теперь то, что я хочу сделать, это в основном: нарисовать фоновое изображение и анимировать его (если это гифка), затем нарисовать 0-n анимированных гифок меньшего размера поверх него, положение относительно фонового изображения, заданное в пиксельных координатах. Кроме того, его размер должен изменяться, чтобы изображения увеличивались / перемещались соответственно.

Как может выглядеть конечный результат: http://i.stack.imgur.com/PxdDt.png (только представьте, что это анимировано)

Я нашел решение, которое работает, устанавливая диспетчер компоновки на null и используя абсолютно позиционированные JLabels с иконками, чтобы анимировать их, используя один в качестве фона, а другой добавленный к нему в качестве переднего плана:

background.setSize(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight());
foreground.setSize(foregroundIcon.getIconWidth(), foregroundIcon.getIconHeight());
background.setLocation(0, 0);
foreground.setLocation(30, 30);
background.setLayout(null);
background.add(foreground);
frame.setLayout(null);
frame.add(background);

(полный код ниже)

Как я слышал, установка диспетчера компоновки на null является проблематичной (особенно, поскольку я хотел бы добавить текст к изображению позже, хотя я бы использовал другую метку внутри фоновой метки, а не саму метку фона или что-то еще ), и изменение размера, похоже, невозможно таким образом, поскольку я не могу изменить размер значка изображения JLabels (нашел несколько решений, которые разбили gif на одно bufferedImage для каждого слоя и изменили их размер, прежде чем снова собрать их вместе, из-за чего он теряет определенные задержки между кадрами и так далее). Кроме того, поскольку позиция должна быть идеальной до пикселя, изменение размера, даже если это возможно, может быть проблематичным из-за ошибок округления.

Итак, есть ли лучший способ сделать это? Могу ли я как-то загрузить анимированные гифки и объединить их вручную (даже если у них может быть разное количество слоев), чтобы мне пришлось рисовать только одно изображение? Есть ли менеджер компоновки, в котором я могу установить позиции компонентов вручную, но который автоматически масштабирует их, если вы изменяете размер окна / панели? Может быть, есть сторонний графический проект, который мог бы делать то, что я хочу, с места в карьер?

В идеале было бы что-то вроде того, что я сделал бы, если бы они не были анимацией, например, создание объединенного изображения, а затем изменение размера и отображение этого.

Полный код:

import java.awt.Dimension;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public final class Tester  extends JFrame {
    public static void main(String[] args) throws MalformedURLException {
        new Tester();
    }

    private Tester() throws MalformedURLException {
        setTitle("Tester");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Icon backgroundIcon = new ImageIcon(new URL("http://s5.favim.com/orig/51/animated-gif-gif-hands-sign-language-Favim.com-542945.gif"));
        Icon foregroundIcon = new ImageIcon(new URL("http://i.imgur.com/89HANHg.gif"));

        JLabel background = new JLabel(backgroundIcon);
        JLabel foreground = new JLabel(foregroundIcon);

        // ugly
        background.setSize(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight());
        foreground.setSize(foregroundIcon.getIconWidth(), foregroundIcon.getIconHeight());
        background.setLocation(0, 0);
        foreground.setLocation(30, 30);
        background.setLayout(null);
        background.add(foreground);
        setLayout(null);
        add(background);

        // set size of frame to size of content
        setResizable(false);
        getContentPane().setPreferredSize(new Dimension(backgroundIcon.getIconWidth(), backgroundIcon.getIconHeight()));
        pack();

        setLocationRelativeTo(null);
        setVisible(true);
    }
}

person Kadser    schedule 25.08.2013    source источник
comment
В своем sscce получите доступ к опубликованным изображениям через URL, как показано здесь или ниже; используйте синтетические изображения, как показано здесь; или используйте UIManager значки, как показано здесь.   -  person trashgod    schedule 26.08.2013


Ответы (1)


У меня это работает. Меньшее изображение с орбиты центрируется внутри большого изображения фаз Луны.

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

public final class Tester  extends JFrame {
    public static void main(String[] args) throws MalformedURLException {
        new Tester();
    }

    private Tester() throws MalformedURLException {
        setTitle("Tester");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Icon backgroundIcon = new ImageIcon(
                new URL("http://1point1c.org/gif/moon/moonphases.gif"));
        Icon foregroundIcon = new ImageIcon(
                new URL("http://1point1c.org/gif/thum/plnttm.gif"));

        JLabel background = new JLabel(backgroundIcon);
        JLabel foreground = new JLabel(foregroundIcon);

        background.setLayout(new GridBagLayout());
        background.add(foreground);
        add(background);

        pack();

        setLocationByPlatform(true);
        setVisible(true);
    }
}
person Andrew Thompson    schedule 25.08.2013
comment
Это (или другие менеджеры компоновки) было бы хорошо, если бы изображение переднего плана должно было быть центрировано, но оно должно быть в очень конкретном месте. Представьте, например, фоновое изображение, показывающее стену с пустой рамкой для рисования, в которой при наведении курсора мыши или около того должен отображаться (наложенный) анимированный gif. он должен быть точно внутри кадра, поэтому все менеджеры компоновки, которые я могу придумать, не будут работать. - person Kadser; 26.08.2013
comment
Что, значит, «пустая рамка для рисования» (что бы это ни было) не центрирована? Он движется или находится в неподвижном месте? - person Andrew Thompson; 26.08.2013
comment
он должен быть точно внутри фрейма, Точно где? поэтому все менеджеры компоновки, о которых я могу думать, не будут работать. Если есть логика для позиционирования 2-го изображения эту логику можно включить в диспетчер компоновки. - person Andrew Thompson; 26.08.2013
comment
Я имею в виду пустой фрейм не в программном смысле, а в том смысле, что вы вешаете его на стену, например это. Вы знаете положение кадра по осям X / Y, но оно не по центру. Представьте себе это изображение, и затем, посредством некоторого взаимодействия с пользователем, в один из кадров будет помещен анимированный gif. (форма рамки значения не имеет, это всего лишь пример, с помощью которого я надеюсь объяснить, что мне нужно) - person Kadser; 26.08.2013
comment
+1 для sscce; Клауэ: OverlayLayout, возможно, стоит взглянуть - person trashgod; 26.08.2013
comment
Немного посмотрел, но с overlayLayout, похоже, нет способа указать положение оверлеев. В связанном вопросе также есть JLayeredPane, который выглядел многообещающе, но позиция задается setBounds на компоненте, что на самом деле не кажется улучшением по сравнению с моим вышеупомянутым методом (он поддерживает больше слоев, что хорошо, поэтому я, вероятно, все равно используйте его, но это не решает основной проблемы). Я думаю, мне просто нужно признать, что нет лучшего способа сделать это - person Kadser; 26.08.2013
comment
Совет: добавьте @trashgod (или кого-то еще, @ важен), чтобы уведомить человека о новом комментарии. Я думаю, что это, возможно, случай «забыть о менеджерах компоновки и раскрасить все изображения в один BufferedImage, отображаемый в JLabel». Но мне понравилось предложение trashgod .. - person Andrew Thompson; 26.08.2013
comment
@Klaue: Использование setSize() возлагает на вас ответственность за правильный размер; остерегайтесь этой ловушки. - person trashgod; 26.08.2013
comment
@ Эндрю-Томпсон, спасибо, я еще здесь новенький. Надеюсь, с тире там все было правильно. Единственный BufferedImage был первым, что я выбрал, но BufferedImage имеет только один кадр и не поддерживает анимацию. - person Kadser; 26.08.2013
comment
@thrashgod Я думаю, что в моем случае это не должно быть проблемой, поскольку размер, который мне нужен, равен размеру фонового изображения. Тем не менее, спасибо - person Kadser; 26.08.2013
comment
@Andrew Thompson хммм +1 JLabel.setLayout (новый GridBagLayout ()); - person mKorbel; 26.08.2013