Płynność animacji

Odpowiedz Nowy wątek
2009-12-05 21:49

Rejestracja: 15 lat temu

Ostatnio: 9 lat temu

0

Witam,

Tworzę małą grę w Javie, wykorzysując Swinga.
Natrafiłem na problem, dotyczący płynności animacji. Gdy uruchamiam poniżej podany kod, zuzycie CPU wzrasta do 100%, a na oko z 5-10 FPS-ów widać na ekranie.

Do wyświetlania animacji na JPanelu wykorzystałem przeciążoną metodę paint():

        @Override
        public void paint(Graphics g) {
            grafiki.animacja++;
            if (grafiki.animacja == 25) {
                grafiki.animacja = 0;
            }

            g.drawImage(grafiki.tlo, 0, 0, this);
            g.drawImage(grafiki.img[grafiki.animacja], 0, 0, this);
        }

W grafiki.img[] mam 25 klatek animacji, ktora jest zapętlona.

Odświeżanie grafiki wykonuję w oddzielnym wątku, wykonując metodę repaint()

    class watek extends Thread {

        @Override
        public void run() {
            while (true) {

                mainPanel.repaint();

                try {
                    Thread.sleep(5);
                } catch (Exception e) {}
            }
        }
    }

Pytanie do Was: jak powinno się wyświetlać animacje, aby nie obciążały tak komputera? Co robię źle?

Pozdrawiam

Pozostało 580 znaków

2009-12-05 22:47

Rejestracja: 16 lat temu

Ostatnio: 30 minut temu

0

5ms sleepa? to jest jakieś 200fps, wiec się nie dziw że obciąża procesor.
Mniej może byc widać ze względu na przerysowywanie obrazków. Użyłeś podwójnego buforowania?
http://www.realapplets.com/tutorial/DoubleBuffering.html


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2009-12-05 23:00

Rejestracja: 15 lat temu

Ostatnio: 9 lat temu

0

Zmieniłem sleepa na 20ms (50FPS), to juz powinien 3GHz dwurdzeniowy procek udźwignąć, prawda?:P

Uzylem tez podwojnego buforowania, ale to nawet pogorszyło wydajność.

Podwojne buforowanie wykonałem tak:

 @Override
        public void paint(Graphics g) {
            grafiki.animacja_nog++;
            if (grafiki.animacja_nog == 25) {
                grafiki.animacja_nog = 0;
            }

            BufferedImage tmp = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);

            Graphics2D g2 = (Graphics2D) tmp.getGraphics();
            g2.drawImage(grafiki.tlo, 0, 0, null);
            g2.drawImage(grafiki.img[grafiki.animacja_nog], player.x, player.y, null);

            g2.drawRenderedImage(tmp, null);

            g.drawImage(tmp, 0, 0, this);
        }

Chyba poprawnie, nową klatkę generuję "na boku", dopiero podczas g.drawImage(tmp, 0, 0, this) podmieniam ją z grafiką na JPanelu.

EDIT:

Właśnie zauważyłem dziwną rzecz: odpaliłem program na laptopie (porownywalny ze stacjonarką - procek 2,4GHz CoreDuo), gdzie animacja jest extra-płynna!!

Zaraz sprawdzę dokładniej roznice między zainstalowanymi JDK, ale powinny byc obie najnowsze...

Pozostało 580 znaków

2009-12-06 00:39

Rejestracja: 16 lat temu

Ostatnio: 30 minut temu

0

A doczytałeś na tej stronie to:

There is one dangerous pitfall here, when you create an offscreen image that's very large
the applet might run slow because it takes a lot of resources and effort.
I would not recommend offscreen images larger than 500*500 when redrawn at 30FPS.

? ;)
No i pamiętaj ze ludzkie oko i tak nie łapie wiecej niż 25-30 fps.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2009-12-06 13:01

Rejestracja: 15 lat temu

Ostatnio: 9 lat temu

0

Znalazłem w internecie taką funkcję:

public static BufferedImage optimizeImage(BufferedImage img)
    {
        GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();

        boolean istransparent = img.getColorModel().hasAlpha();

        BufferedImage img2 = gc.createCompatibleImage(img.getWidth(), img.getHeight(), istransparent ? Transparency.BITMASK : Transparency.OPAQUE);
        Graphics2D g = img2.createGraphics();
        g.drawImage(img, 0, 0, null);
        g.dispose();

        return img2;
    }

Konwerwuje ona obrazki na format zgodny z wyświetlanym, dzięki czemu drawImage szybciej działa.

Przyśpieszyło to animację, teraz bez podwojnego buforowania mogę osiągnąć nawet te 200FPS na stacjonarce. Jednak przy podwojnym buforowaniu na laptopie mam nadal 200FPS, stacjonarka muli z ~30FPS :D

Magia dla mnie..

Pozostało 580 znaków

2009-12-09 21:26

Rejestracja: 11 lat temu

Ostatnio: 9 godzin temu

Lokalizacja: Polska, Warszawa

0

Przegoogluj "active rendering". Po prostu animacji nie robi się tak jak to robisz.

Swing jest jednowątkowy i odpalanie repaint() z innego wątku, to chędożenie Swinga. Trzeba sobie napisać kod, który będzie pomijał renderowanie klatek, które nie zmieszczą się w sekundzie jeżeli wydajność obliczeniowa będzie zbyt mała.


Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?

Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0