Java-tworzenie gry, Pacman

0

Witam, chciałabym napisać prostą grę pacman. Na razie zaprogramowałam menu, statystyki, generowanie mapy z pliku .txt oraz proste poruszanie się pacmanem. Teraz chciałabym stworzyć kolizję ze ścianami oraz stworzenie poruszających się przeciwników oraz ich AI. Nie mam jednak za bardzo pomysłu jak to zrealizować. Bardzo proszę o jakieś wskazówki dotyczące realizacji tych elementów. Z góry dziękuje:)

0

AI? Po co AI ;]
Opisz plansze na grafie i poruszaj się po najkrótszej ścieżce :)

0

Okej dziękuje, kolizje już w sumie zrobiłam, ale nie działa ona idealnie,ponieważ poruszanie ludzika odbywa się poprzez przesuwanie obrazka o x pikseli. Chciałabym uzależnić ruch pacmana od czasu, ale nie bardzo wiem jak mam to zrobić. Na każdy kierunek ruchu pacmana(animacje) mam oddzielny watek, wygląda to następująco:
klasa abstrakcyjna ruchu:

 
public abstract class RuchPacman implements Runnable{
    
    public RuchPacman(Pacman p)
    {
        panel=Plansza.getmappanel();
        ludek=p;
        inicjalizacja();
    }
    
    public void inicjalizacja(){}
  
    public void aktualizacjawsp(){}
  
    public synchronized void run() 
    {
        int ib=0;
        while(true)
        {   
            try
            {       
            ludek.setimg(img[ib]);
            aktualizacjawsp();
            panel.repaint();
  
            Thread.sleep(80);
            } 
            catch(InterruptedException ex) 
            {
                ex.printStackTrace();
            }     
            ib++;       
            if(ib==4)
            {
                ib=0;
            }

        }
       
    }
    
    public JPanel panel;            //zmienne public dla przejrzystosci podklas
    public Pacman ludek;
    public Image[] img;
    
}

A teraz np: ruch pacmana w prawo:

 
public class RuchPacmanPrawo extends RuchPacman{
    
    public RuchPacmanPrawo(Pacman p)
    {
        super(p);
    }
    
    public void inicjalizacja()
    {
        img=new Image[4];
        try{
        img[0]=ImageIO.read(new File("/DataG/pacpelny.png"));
        img[1]=ImageIO.read(new File("/DataG/pacprawo0.png"));
        img[2]=ImageIO.read(new File("/DataG/pacprawo1.png"));
        img[3]=ImageIO.read(new File("/DataG/pacprawo2.png"));
        }
        catch(IOException ev)
        {
          ev.printStackTrace();  
        }
    }
    
    public void aktualizacjawsp()
    {        
        if(Kolizja.SprawdzKolizjeMapa(ludek.getx()+ludek.getpredkosc(), ludek.gety(), 'p',ludek)==false)
        {     
            ludek.setx(ludek.getx()+ludek.getpredkosc());                   
        }
        else
            Thread.currentThread().suspend();
          
    }
    
}

A tutaj obsługa klawiatury:

public class Klawiatura implements KeyListener {

    public Klawiatura()
    {
      ludek=Plansza.getpac();
      ilepac=ludek.length;
      r=new RuchPacman[4*ilepac];
      
      r[0]=new RuchPacmanPrawo(ludek[0]);
      r[1]=new RuchPacmanLewo(ludek[0]);
      r[2]=new RuchPacmanGora(ludek[0]);
      r[3]=new RuchPacmanDol(ludek[0]);
      
      if(ilepac==2)
      {
        r[4]=new RuchPacmanPrawo(ludek[1]);
        r[5]=new RuchPacmanLewo(ludek[1]);
        r[6]=new RuchPacmanGora(ludek[1]);
        r[7]=new RuchPacmanDol(ludek[1]);
      }
      
      t=new Thread[4*ilepac];
      for(int i=0;i<t.length;i++)
      {
          t[i]=new Thread(r[i]);
          t[i].start();
          t[i].suspend();
      }
       
    }
    
    public synchronized void aktualizacjawatkow()
    {
        for(int i=0;i<t.length;i++)
        {
            if(i!=pac1||i!=pac2)
                t[i].suspend();
        }
        if(activepac1)
            t[pac1].resume();
        if(activepac2)
            t[pac2].resume();
    }
    
    public void keyTyped(KeyEvent e) {
        
    }

    public void keyPressed(KeyEvent e) {
       if(ilepac==2)
        {
            if(e.getKeyCode()==e.VK_D)
            {
                if(Kolizja.SprawdzKolizjeMapa(ludek[1].getx()+ludek[1].getpredkosc(), ludek[1].gety(), 'p',ludek[1])==false)
                {
                    activepac2=true;
                    pac2=4;
                    aktualizacjawatkow();
                }
            }
            else if(e.getKeyCode()==e.VK_A)
            {
                if(Kolizja.SprawdzKolizjeMapa(ludek[1].getx()-ludek[1].getpredkosc(), ludek[1].gety(), 'l',ludek[1])==false)
                {
                    activepac2=true;
                    pac2=5;
                    aktualizacjawatkow();
                }
            }
            else if(e.getKeyCode()==e.VK_W)
            {
                if(Kolizja.SprawdzKolizjeMapa(ludek[1].getx(), ludek[1].gety()-ludek[1].getpredkosc(), 'g',ludek[1])==false)
                {
                    activepac2=true;
                    pac2=6;
                    aktualizacjawatkow();
                }
            }
            else if(e.getKeyCode()==e.VK_S)
            {
                if(Kolizja.SprawdzKolizjeMapa(ludek[1].getx(), ludek[1].gety()+ludek[1].getpredkosc(), 'd',ludek[1])==false)
                {
                    activepac2=true;
                    pac2=7;
                    aktualizacjawatkow();
                }
            }      
        }  
        if(e.getKeyCode()==e.VK_RIGHT)
        {
            if(Kolizja.SprawdzKolizjeMapa(ludek[0].getx()+ludek[0].getpredkosc(), ludek[0].gety(), 'p',ludek[0])==false)
            {
                activepac1=true;
                pac1=0;
                aktualizacjawatkow();
            }
        }
        else if(e.getKeyCode()==e.VK_LEFT)
        {
            if(Kolizja.SprawdzKolizjeMapa(ludek[0].getx()-ludek[0].getpredkosc(), ludek[0].gety(), 'l',ludek[0])==false)
            {
                activepac1=true;
                pac1=1;
                aktualizacjawatkow();
            }
        }
        else if(e.getKeyCode()==e.VK_UP)
        {
            if(Kolizja.SprawdzKolizjeMapa(ludek[0].getx(), ludek[0].gety()-ludek[0].getpredkosc(), 'g',ludek[0])==false)
            {
                activepac1=true;
                pac1=2;
                aktualizacjawatkow();   
            }
        }
        else if(e.getKeyCode()==e.VK_DOWN)
        {
             if(Kolizja.SprawdzKolizjeMapa(ludek[0].getx(), ludek[0].gety()+ludek[0].getpredkosc(), 'd',ludek[0])==false)
             {
                activepac1=true;
                pac1=3;
                aktualizacjawatkow();
             }
        }
       
        if(e.getKeyCode()==e.VK_ESCAPE)
        {
            System.exit(1);
        }
           
    }

    public void keyReleased(KeyEvent e) {

    }
    
    private RuchPacman[] r;
    private Thread[] t; 
    private Pacman[] ludek;
    private int pac1,pac2,ilepac;
    private boolean activepac1,activepac2;
} 

I moje pytanie, to jak zorganizować to aby ruch był zależny od czasu, według wzoru: v=s*t?

0

także gratuluje osiągnięcia :D nie no śmieje się tylko, ale po prostu rozbawiło mnie to bardzo.
A na poważnie mówiąc - ruch postaci masz stały. Czas też za bardzo nie chce ani przyspieszać, ani zwalniać i upływa w czasie constans jednej sekundy na sekundę (no teraz to dowaliłem do pieca ;P Twoja wina!;P) więc przesunięcie postaci można by śmiało wyliczać np co 100ms prostego wzoru - przesunięcie w kierunku ruchu [np px] = 0.1 * prędkość_postaci; I już masz zależność od czasu i prędkości. Możesz sobie bawić się również w ruch nieliniowy modyfikując współczynnik prędkości postaci (też w czasie). Powodzonka!

1
Antoniossss napisał(a):

także gratuluje osiągnięcia :D nie no śmieje się tylko, ale po prostu rozbawiło mnie to bardzo.
A na poważnie mówiąc - ruch postaci masz stały. Czas też za bardzo nie chce ani przyspieszać, ani zwalniać i upływa w czasie constans jednej sekundy na sekundę (no teraz to dowaliłem do pieca ;P Twoja wina!;P) więc przesunięcie postaci można by śmiało wyliczać np co 100ms prostego wzoru - przesunięcie w kierunku ruchu [np px] = 0.1 * prędkość_postaci; I już masz zależność od czasu i prędkości. Możesz sobie bawić się również w ruch nieliniowy modyfikując współczynnik prędkości postaci (też w czasie). Powodzonka!

Nie dość że sie naśmiewasz z niego to jeszcze głupoty gadasz =/ co z tego ze masz sleep(80)?? jezeli wątek składa sie z operacji :

  1. aktualizacja_pozycji();
  2. render()
  3. sleep(x)
    To czas trwania klatki jest równy sumie czasów każdej z tych składowych, mało tego czas pkt. 1. i 2. może być zmienny. Co doprowadza do sytuacji, w której aktualizacja pozycji będzie wykonywana w różnych odstępach czasowych i sprawi że postać nie będzie poruszać się płynnie. Nigdy nie widziałeś w grze jak przy złapaniu laga, czy to sieciowego czy graficznego twoja postać niesamowicie szybko sie przemieściła? Właśnie dla tego że wszystkie profesjonalne gry mają uwzględnienie czasu gdyż fps sie zmienia w czasie, co oznacza że czas trwania jednej klatki jest też zmienny w czasie a co za tym idzie formuła typu 0.1 * prędkość_postaci; jest brednią bo zakłada że czas wywołania klatki jest stały.

Wracając do tematu zwykle robi się to tak(pseudokod):

long start_t = (pobranie czasu w ms)     // początkowa inicjalizacja zmiennej pomocniczej
while(true) {
    long cur_t = (pobranie czasu w ms)   // pobranie czasu rozpoczęcia i-tej klatki
    float dt  = (float)(cur_t - start_t) / 1000.0;  // w start_t mamy mieć czas startu poprzedniej klatki
                                                                 // różnica miedzy cur_t a start_t to czas trwania ostatniej klatki
    start_t = cur_t;   // czas startu tej klatki przepisujemy do start_t, przygotowujemy zmienną pod kolejną klatkę

    // teraz możemy wykonać aktualizacje pozycji uwzględniając dt.
    aktualizacja_pozycji(dt);

    render();
    sleep(x);
}

// dt czas w sekundach
void aktualizacja_pozycji(float dt) {
    x += vx * dt;
    y += vy * dt;
}

Jedna mała uwaga nie v = s * t tylko S = vt lub dokładniej S = całka 0->t z (vdt), każde wywołanie funkcji aktualizacja_pozycji(dt) to tak naprawdę właśnie wywołanie v * dt, natomiast twoja pozycja to właśnie suma(całka) takich składowych.
Gdybyś teraz chciał np uwzględnić przyśpieszenie to musiałbyś tylko modyfikować v w każdej klatce w analogiczny czyli np
v = a*t czyli znowu v = a * dt; wygląda to ładniej kiedy postać stopniowo przyśpiesza i zwalnia ;-)

0

Przy takiej "skomplikowanej" grze wymagającej potężnej mocy obliczeniowej, może jednak wystarczyłoby w zamknąć wszystko w dwóch wątkach - logikę gry w jednym a renderowanie w osobnym co ?? :>
No właśnie postacie przyspieszają bo czas masz stały a komp przyciął..... <- jeżeli mówimy o grach sieciowych - normalnie mogłoby się bez tego obyć i zrobić można teleport. Jak mówisz o lagu lokalnym, to błagam, wszystko zamarza wtedy
Więc Władziu... co Ty mi tu....

1
Antoniossss napisał(a):

Przy takiej "skomplikowanej" grze wymagającej potężnej mocy obliczeniowej, może jednak wystarczyłoby w zamknąć wszystko w dwóch wątkach - logikę gry w jednym a renderowanie w osobnym co ?? :>
No właśnie postacie przyspieszają bo czas masz stały a komp przyciął..... <- jeżeli mówimy o grach sieciowych - normalnie mogłoby się bez tego obyć i zrobić można teleport. Jak mówisz o lagu lokalnym, to błagam, wszystko zamarza wtedy
Więc Władziu... co Ty mi tu....

No to sie popisałeś... przykład, jedną klatkę GPU ci wyrenderuje 10ms drugą np. w 50ms(mowa o lagu GPU NIE ZAWIESZENIU kompa, przypominam że lag == latencja == opóźnienie, poza tym nie musi to być nawet lag, a zwykła zmiana liczby wyświetlanych obiektów na ekranie) i juz proste x+=v jest do bani. Do tego render nie jest w pełni niezależny od zmian, musi gdzieś nastąpić jego synchronizacja, mało tego, sleep(x), gwarantuje tylko tyle ze wątek poczeka minimum x ms, a nie dokładnie x(do tego nawet to nie jest takie 100% pewne bo może pojawić się przerwanie). Nie zapominaj także o tym że wątek uśpiony musi jeszcze poczekać aż zostanie wybudzony, a to oznacza ze musi czekać aż inny wątek będzie można wywłaszczyć. Do tego zakładasz fizyczną równoległość wątków co też jest nieprawdą... co powiesz chociażby o procesorze z jednym rdzeniem? Podobnie moze sie zdażyć gdy wielordzeniowy procek ma wiele wątków do obsłużenia. Nie wprowadzaj go w błąd.

0

Chętnie mogę pomóc, gg - 940289.

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