Gra odświeżanie obrazu

0

Witam
Robię grę czołgi, jednak utknąłem na wyświetlaniu obrazu.

Moja klasa graj, która odpalam z głównej klasy po nacisnieciu przycisku:

 import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.awt.event.KeyListener;
import java.awt.Dimension;

import javax.swing.*;

/**
 *
 * @author Kamil
 */
public class graj extends Canvas implements KeyListener{
    JFrame ramka;
     map mapka = new map();
    JPanel panel;
   sciana2 scianka =  new sciana2();
   sciana1 scianka2 = new sciana1();
     mapa[] mapy= new mapa[3];
     gracz gracz1 = new gracz();
     int x =0,y=20,z=1000;
     aktpanel panele = new aktpanel();
  // sciana1 scianka2 = new sciana1();
    public graj()
    {   
        ramka = new JFrame();
       // scianka=(sciana1) scianka;
        mapy[0]=new mapa();
        mapy[0].dodaj_element1(1,1);
        mapy[0].dodaj_element1(2,2);
        mapy[0].dodaj_element1(3,3);
        mapy[0].dodaj_element1(4,4);
       
        panel = new JPanel();
        ramka.setResizable(false);
       
        


        ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ArrayList<JLabel> zycia = new ArrayList<JLabel>();
        panel.setLayout(null);
        zycia.add(new JLabel("Ilość żyć:  "));
        zycia.add(new JLabel(Integer.toString(x)));
        zycia.add(new JLabel("Ilość pozostałych przeciwników:  "));
        zycia.add(new JLabel(Integer.toString(y)));
        zycia.add(new JLabel("Punkty:  "));
        zycia.add(new JLabel(Integer.toString(z)));
        panel.add(zycia.get(0));
        panel.add(zycia.get(1));
        panel.add(zycia.get(2));
        panel.add(zycia.get(3));
        panel.add(zycia.get(4));
        panel.add(zycia.get(5));
       
       
        ramka.getContentPane().add(BorderLayout.EAST,panele);
      
        ramka.getContentPane().add(BorderLayout.EAST,panel);
           ramka.getContentPane().add(mapka);
        ramka.setSize(640,480);
        ramka.setVisible(true);
        
          ramka.addKeyListener(this);
  
          try {
    Thread.sleep(5000);
    } catch (InterruptedException e) {}
              gracz1.ruch();
       
        ramka.repaint();
      


    }
    public void keyPressed(KeyEvent e) {
gracz1.keyPressed(e);
}public void keyReleased(KeyEvent e) {
gracz1.keyReleased(e);
}
public void keyTyped(KeyEvent e) {}
class map extends JPanel
    {
        public void paintComponent(Graphics g)
        {
            g.setColor(Color.black);
           g.fillRect(0,0,440,440);
           Image obrazek = new ImageIcon("wall2.jpg").getImage();
            for(int k=0;k<mapy[0].i;k++)
         g.drawImage(mapy[0].sciany1[k].obrazek,(mapy[0].sciany1[k].x)*20,(mapy[0].sciany1[k].x)*20,this);
            g.drawImage(gracz1.czolg,(gracz1.x),(gracz1.y), this);
            g.setColor(Color.red);
            g.drawString("KUTAS", 440, 400);
            repaint();
            paint(g);
            //g.drawImage(mapy[0].sciany1[0].obrazek, 0,0,this);
           // g.drawImage(scianka2.obrazek,20,0,this);
        }
    }
}

Problemem jest odświeżanie obrazu, jeśli zrobią pętlę, w której wywołuję repaint okno jest białe, i dopiero na koniec pętli wyświetla końcowy rezultat. Mógłby ktoś podpowiedzieć w jaki sposób to wszystko rysować przez cały okres trwania gry?

Dziękuje i Pozdrawiam

1

g.drawString("siusiak", 440, 400);
:D

0

Sry, że nie wyczyściłem kodu,a stopień zdenerwowania na kod jest duży.
Znalazł ktoś konstruktywną podpowiedź?
Albo jakiś uniwersalny sposób na wstawienie czegoś do ramki i odświeżanie do czasu zamknięcia okna?
Z góry dziękuję

0

Nie wywołuj samodzielnie funkcji paint(). Nie wywołuj repaint() z funkcji paintComponent(), prowadzi to do nieskończonej rekurencji.

0

Repaint w paintcomponent był tylko do testów.
To jak załatwić tą pętlę wyświetlającą odświeżany obraz?

0

Pomoże ktoś?

0

Jak umieszczasz kod na forum, to umieszczaj ten który sprawia problemy. A nie jakiś wymyślony. Wskażę jakiś błąd, a Ty znów napiszesz, że w Twoim kodzie tego błędnego fragmentu nie ma. Szkoda mojego czasu.

0

Po pierwsze musisz mieć stałą ilość odrysowań w czasie tego co chcesz wyświetlać. Bez tego nie ma żadnej gry bo inaczej raz coś Ci będzie zwalniać, a innym razem przyspieszać. Tym czymś może być Timer, którego procedura zegarowa (run) powinna robić w jednym wywołaniu tylko trzy rzeczy: Odczytanie stanu kontrolerów, zmiana stanu gry i dezaktualizacja obrazu.
Odczytanie stanu kontrolerów powinno odczytać ostatni zaktualizowany przez Twoje listenery stan sterowania grą (o tym dalej).
Zmiana stanu gry, to nic innego jak np. przesuwanie czołgów, strzelanie, sprawdzanie trafień itp. Wszystko co wymaga liczenia, reakcji, sprawdzania i "myślenia".
Dezaktualizacja obrazu w przypadku użycia Swinga to po prostu wywołanie repaint() dla okna/panelu gry.
Ponieważ GUI jest asynchroniczny trzeba się zabezpieczyć przed przypadkowym odrysowywaniem gry w wyniku zasłonięcia i odsłonięcia okna gry (gra i tak po minięciu równego okresu czasu odświeży stan obrazu). Robi się to przez wywołanie metody setIgnoreRepaint().

Wszystkie zarejestrowane przez Ciebie listenery wywołują się asynchronicznie - wyjątkowo nie po drodze ze sposobem działania gier. Żeby kontrolery stały się synchroniczne potrzeba abyś w grze trzymał dane dotyczące klawiszy, ruchu myszą, joyem itp. - tych, które będą interesować Twoją grę. Np. W keypressed sprawdzasz jaki klawisz został wciśnięty i zapisujesz sobie, że ten klawisz X jest właśnie wciśnięty. Twoja gra w fazie odczytu kontrolerów powinna odczytać ostatni stan klawisza X i na tej podstawie zmienić (lub nie) stan gry. Podobnie z wychyleniem joya, aktualnym wektorem ruchu myszy itd.

Odrysowywanie gry musi następować tylko i wyłącznie w kodzie metody paint panelu, który u Ciebie ma zawierać obraz (całej) gry. Paint może odwoływać się wyłącznie do danych stanu gry i niczego więcej (nie może czytać nawet stanu kontrolerów). Nie może wywoływać żadnych metod Swinga, a tylko metody rysujące AWT. Nie powinna niczego tworzyć, ani alokować pamięci (żadnych new). Powinno się tam znaleźć tylko czyste rysowanie lub wywołania procedur rysujących (np. sprite'y). Jeżeli potrzebujesz do wyświetlenia coś policzyć (szczególnie coś czasochłonnego), to znaczy, że źle zaprojektowałeś grę i powinieneś to liczenie przenieść do miejsca, gdzie zmienia się stan gry. Paint powinien tylko z tego korzystać. Jeżeli tak nie będzie i czas jej wykonywania przekroczy 1/x sekundy, to zostanie wywołany kolejne run() z timera, gdzie dane, które właśnie odczytujesz zaczną się już zmieniać, co może spowodować konflikty/kolizje, opóźnienia, uszkodzenia danych przez różne wątki - a kolejne repaint najpewniej zostanie przez Swinga zignorowane. Krótko mówiąc otrzymasz to, co właśnie dostajesz.

Twoja gra powinna również pauzować. Pauza w grze to nic innego jak sprawdzenie czy stan klawisza "odpauzowującego" zmienił się, a jeżeli nie, to anulowanie całej fazy zmiany stanu gry. Nie oznacza to zatrzymywania wyświetlania gry - paint nadal będzie wywoływana co ułamek sekundy - tyle, że będzie wciąż odrysowywała nie zmieniający się stan gry. Ale to nie znaczy, że będzie się wyświetlał nieruchomy obraz. Menu gry wciąż musi działać, a gracz wciąż może przesuwać polem gry (np. klawiszami - stan kontrolerów powinien być wciąż uaktualniany), a w grach 3D można nawet obracać kamerą nad nieruchomym widokiem gry.

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