Więc tak mam napisać grę i chcę wiedzieć czy koncepcja którą przyjąłem będzie dobra dla płynnej animacji i czy nie nastąpią problemy z interakcjami między wątkami.
Mam klasę:
public class MainGamePanel extends JPanel
implements Runnable, KeyListener, MouseListener ,MouseMotionListener
{
private static final int PANEL_W = 1000; //wymiary panelu
private static final int PANEL_H = 600;
private Thread animator; // watek animujacy
boolean running=false;
public MainGamePanel()
{
addMouseListener(this);
addKeyListener(this);
setFocusable(true);
}
public void run()
{
while(running)
{
uptadeGame();
renderGame();
refreshImage();
sleep(STALA-(czas_obecny-czas_poprzedni));
}
}
@Override public void addNotify() //wystartuje po dodaniu panelu do Frame
{
super.addNotify();
startGame();
}
}
Ta klasa to jest tylko fragment podglądowy.
czas_obecny i czas_poprzedni będę uzyskiwał z jakiegoś timera i będzie to czas jaki upłyną od poprzedniego odświeżenia stanu gry, renderingu i odświeżenia obrazu.
STALA- to jakaś wartość w zależności od tego ile chcę FPS.
Ogólnie to będzie to bardziej rozbudowane, tak ze jeśli czas między kolejnymi wykonaniami pętli będzie za duży wątek nie zostanie uśpiony, chyba że przekroczona zostanie limit wykonań bez sleepa (np 16) to wtedy wykonany zostanie yield(). Myślę że to powinno działać dobrze, bo podobne rozwiązanie widziałem w tutorialu jakimś. Martwi mnie tylko jak animacja będzie współpracować z innymi wątkami które mają wpływ na wygląd obrazu.
Wymaganiem są jednostki z których każda musi być sterowana własnym, osobnym wątkiem.
Nie będę podawał szczegółów tylko chyba to co najważniejsze:
abstract public class Unit extends Thread
{
public void run()
{
while(hp>0) //hit points jednostki
{
Unit enemy=EnemyInRange();//sprawdz czy wrog w zasiegu
if (enemy!=null) attack(enemy); //atakuj jesli wrog w zasiegu
if (moving) move(); //jesli ma rozkaz poruszania to sie porusza w wybrane miejsce
try{
sleep(20);
}
catch(InterruptedException e){};
}
owner.units.removeElement(this);
};
}
To też tylko fragment podglądowy i klasa będzie bardziej rozbudowana.
Czy w przypadku klasy Unit wywołując sleepa muszę postąpić tak jak w klasie MainGamePanel, czyli z timera liczyć czas jaki upłyną i sleepa na odpowiedni czas ustawić? Bo jak zostawię stałą wartość 20 to te jednostki mogą się chyba z różną prędkością na komputerach o różnej wydajności poruszać?
Czy dałoby się zrobić coś takiego, i czy byłoby to dobre rozwiązanie gdyby w MainGamePanel.uptadeGame() wywołać notifyAll() a w klasie Unit w tej pętli w run() dać wait(). Wtedy wszystkie Unit'sy wykonałyby swój jeden cykl pętli dokładnie raz w ciągu cyklu pętli animującej.
Teraz to działa tak że EnemyInRange() przechodzi vector jednostek wroga i sprawdza czy odległość jest mniejsza od swojego zasięgu ataku. Czy ta funkcja powinna być synchronized ze względu na współrzędne wroga czy nie? Tzn. czy wewnątrz tej funkcji założyć lock na współrzędne wrogiej jednostki żeby ona w tym czasie ich przypadkiem nie zmieniła?
Jak najlepiej zrobić wyświetlanie tych jednostek? Planuję zrobić tak żeby zrobić funkcję Unit.draw(graphics g) która rysuje gifa na współrzędnych na których znajduje się jednostka.
W MainGamePanel.render() planuje zrobić wrzucenie tła do bufora a później po kolei wywołać Unit.draw(g) i rysować na tym buforze jednostki. Czy funkcja Unit.draw(graphics g) też powinna zakładać lock na współrzędne jednostki, żeby przypadkiem się nie zmieniły?
Później MainGamePanel.refreshImage() wrzuca bufor na ekran i kończy się przetwarzanie tej klatki.
Czy takie rozwiązanie będzie dobrze działać? Czy powinienem to jakoś inaczej zrobić.