|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Sep 2003
Città: Lucca
Messaggi: 379
|
[JAVA]applicazione 2d: conviene usare i thread?
In una semplice applicazione 2d, dove ho un player che si muove tramite input e 3 nemici che sonon mossi dal pc, conviene usare i thread per implementare il giocatore e i nemici?
__________________
God rides DUCATI! |
![]() |
![]() |
![]() |
#2 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
High Flying Sottovento
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Se ti serve usare i thread allora li usi
![]() ![]() |
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Sep 2003
Città: Lucca
Messaggi: 379
|
Potrei anche usare un array con dentro i nemici e le loro posizioni all'interno della finestra, ma forse usare i thread è meglio per ragioni di efficienza....
Per fare gli attori come thread avrei bisogno di un consiglio sull'architettura da seguire: La classe attori ha un metodo Codice HTML:
public void draw(Graphics g,Window w){ g.drawImage(loadImage(),getX(),getY(),w); } per far diventare gli attori thread mi serve il metodo run() che va ad eseguire la draw(). Cisi come ho strutturato la classe è un po problematica, come mi consigliate di procedere? Modifico la draw()? Come?
__________________
God rides DUCATI! |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Altra domanda...hai bisogno di efficienza ?
Se vai a vedere nella sottosezione Diamonds, abbiamo fatto tutto il gioco senza thread... Il problema dei thread in una situazione come questa è che dovrai comunque sincronizzare il tutto e molto strettamente (farai un refresh dello schermo ogni tot milisecondi), quindi se ci arrivi senza thread, perchè usarli ? |
![]() |
![]() |
![]() |
#6 |
Senior Member
Iscritto dal: Sep 2003
Città: Lucca
Messaggi: 379
|
Uso i thread....perchè il prof con faccio il progetto mi ha chiesto di usarli!!!
![]() Se mi confermi che posso eveitarli però, mi togli un peso, perchè infatto sta riscontrando numerosi problemi di soncronizzazione, per cui forse un array è meglio. Cerco di spiegrami meglio partendo dall'inizio Devo appunto fare una piccola applicazione grafica 2d, in cui vi è un giocatore che muovo io e tre spring che deve muovere la macchina: tanto per vedere se funziona mi basta che una figurina parta dalle coordinate (0,0) e ad ogni aggiornamento del buffer di 5 pixel, finchè le coordinate non sono (400,400). A gestire la figurina che muovo tramite input non ho nessun problema: ogni 5 millisecondi il double buffering disegna le coordinate x,y aggiornate (se appunto sono cambiate a causa di un evento da tastiera). Il problema nasce nel disegnare e spostare gli altri spring mossi dall'intelligenza artificiale. Il metodo render della mia finestra è fatto in queto modo: Codice HTML:
public boolean render (Graphics g){ g.setColor (backgroundColor) ; g.fillRect (0,0,getWidth(),getHeight()); for(int i = 0; i < iterator+1;i++){ attori[i].draw(g,this); } return true; } Come faccio dunque a simulare lo spostamento degli altri 3 attori non mossi da input? Io ed il mio prof avevamo pensato di far diventare gli attori dei thread affinche tramite l'invocazione del metodo start() avvenisse lo spostamento. Come posso fare senza starvolgere tutto il codice trasformando gli attri in thread?
__________________
God rides DUCATI! |
![]() |
![]() |
![]() |
#7 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Sprite
![]() Un metodo molto semplice: Codice:
Timer timer = new Timer(); int timeStamp = timer.getTime(); while(true) { if(timeStamp + 20 <= timer.getTime()) { timeStamp += 20; giocatore.processInput(); giocatore.doAction(); for(int i = 0; i < numeroNemici; ++i) nemico[i].move(); engine.render(g); //qui ci vuole anche un Thread.Sleep(1); per non occupare tutta la CPU } } Codice:
public class Timer { private long time; public Timer() { time = System.nanoTime(); } public long getTime() { return (System.nanoTime() - time) / 1000000; } } |
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Sep 2003
Città: Lucca
Messaggi: 379
|
Purtroppo mi sa che come è strutturato il mio codice non funziona il metodo da te suggerito.
Non so come spiegarmi, così allego a questo post un file zip contenente i file java che ho scritto e che ti possono far capire meglio la situazione. Per motivi implementativi successivi, preferirei non modificare la struttura della classe Test, ovvero il main deve per forza terminare con l'invocazione del metodo gameInit(); Inoltre vedi come è strutturato il render della finestra? così com'è non so proprio come applicare quanto mi hai postato prima...
__________________
God rides DUCATI! |
![]() |
![]() |
![]() |
#9 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Il fatto che il main termini con l'invocazione di gameInit non è un problema... GameInit può benissimo contenere il codice sopra...
|
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Provo a darti un'idea ma concedimi le attenuanti dell'aver scritto al volo.
Hai un proiettore fatto all'incirca così: Renderer.java Codice:
import java.awt.*; import java.awt.image.*; import java.util.*; public class Renderer { private BufferStrategy bs; private java.util.List<Attore> attori; private final Rectangle viewRect; public Renderer(BufferStrategy bs, Rectangle viewArea, Attore...a) { this.bs = bs; viewRect = (Rectangle)viewArea.clone(); attori = Collections.unmodifiableList(Arrays.asList(a)); } public boolean render() { Graphics g = bs.getDrawGraphics(); g.setColor(Color.BLACK); g.fillRect(0, 0, viewRect.width, viewRect.height); for(Attore a : attori) { a.draw(g); } bs.show(); return true; } } Attore.java Codice:
import java.awt.*; import java.awt.image.*; public class Attore { private Point location = new Point(); private BufferedImage image; public Attore(BufferedImage image) { this.image = image; } public Point getLocation() { return new Point(location); } public void setLocation(int x, int y) { location.move(x, y); } public void move(int dx, int dy) { location.translate(dx, dy); } public void draw(Graphics g) { g.drawImage(image, location.x, location.y, null); } } A me risulta una cosa di questo tipo. Separo la definizione di "intelligenza" da quella di personaggio intelligente, giusto per non affastellare troppo nei "personaggi concorrenti": AI.java Codice:
public interface AI { void apply(Attore a); long getTick(); } Il Thread che gestisce un singolo personaggio non giocante applica un AI. AI può alterare gli stati da cui dipende la proiezione del personaggio e, dunque, esiste un problema di accesso condiviso agli stati del personaggio. In particolare, il proiettore (Renderer) legge alcuni valori conservati da un Attore (posizione e figura) che un AI concorrente può modificare. Per rendere il proiettore consistente con il singolo attore concorrente direi che basti rendere atomiche e mutualmente esclusive le operazioni di lettura e scrittura degli stati di un attore. Usando il composition and forwarding possiamo creare un secondo tipo di attori che risponda a queste caratteristiche: Codice:
import java.awt.*; import java.util.concurrent.locks.*; public class NPC extends Attore implements Runnable { private final Attore attore; private Lock lock = new ReentrantLock(); private volatile boolean running; private long sleepTime; private AI ai; public NPC(Attore a, AI ai) { super(null); attore = a; sleepTime = ai.getTick() / 1000000; this.ai = ai; } public Point getLocation() { lock.lock(); try { return attore.getLocation(); } finally { lock.unlock(); } } public void setLocation(int x, int y) { lock.lock(); try { attore.setLocation(x, y); } finally { lock.unlock(); } } public void move(int dx, int dy) { lock.lock(); try { attore.move(dx, dy); } finally { lock.unlock(); } } public void start() { lock.lock(); try { if(!running) { running = true; new Thread(this).start(); } } finally { lock.unlock(); } } public void stop() { lock.lock(); try { running = false; } finally { lock.unlock(); } } public void draw(Graphics g) { lock.lock(); try { attore.draw(g); } finally { lock.unlock(); } } public void run() { long time0 = System.nanoTime(); while(running) { long time1 = System.nanoTime(); long dTime = time1 - time0; while(dTime >= ai.getTick()) { dTime -= ai.getTick(); ai.apply(this); } time0 = time1 - dTime; try { Thread.sleep(sleepTime); } catch(InterruptedException ex) { running = false; return; } } } } GameLoop.java Codice:
import java.awt.*; import java.awt.image.*; import java.util.*; import javax.swing.*; import javax.imageio.*; public class GameLoop implements Runnable { private long tick = 10000000; private volatile boolean loop; private Renderer renderer; private java.util.List<Attore> attori; public GameLoop(Renderer r, Attore...a) { attori = Collections.unmodifiableList(Arrays.asList(a)); renderer = r; } public void start() { if(!loop) { loop = true; new Thread(this).start(); } } public void stop() { loop = false; for(Attore a : attori) { if(a instanceof NPC) ((NPC)a).stop(); } } public void run() { for(Attore a : attori) { if(a instanceof NPC) ((NPC)a).start(); } long time0 = System.nanoTime(); while(loop) { long time1 = System.nanoTime(); long dTime = time1 - time0; while(dTime >= tick) { dTime -= tick; renderer.render(); } long sleepTime = (tick - dTime) / 1000000; if(sleepTime > 0) { try { Thread.sleep(sleepTime); } catch(InterruptedException ex) { loop = false; } } time0 = time1 - dTime; } } } Nel mucchio, Attore e Renderer sono rimasti invariati. GameLoop cambia solo per quanto riguarda l'avvio e l'arresto degli NPC. Giusto per provare ad incollare i vari pezzi: Main.java Codice:
import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.util.*; import javax.swing.*; import javax.imageio.*; public class Main { /** Movimento orizzontale a badalucco */ private AI horizontalMove = new AI() { public long getTick() { return 100000000; //100 ms } public void apply(Attore a) { a.move(1, 0); } }; /** Movimento verticale a badalucco */ private AI verticalMove = new AI() { public long getTick() { return 50000000; //50 ms } public void apply(Attore a) { a.move(0, 1); } }; private Renderer renderer; private GameLoop gameLoop; private void startApp() { BufferedImage white, blue; try { white = ImageIO.read(Main.class.getResource("/white.png")); blue = ImageIO.read(Main.class.getResource("/blue.png")); } catch(Exception ex) { throw new RuntimeException("cannot load images"); } final NPC whiteNPC = new NPC(new Attore(white), horizontalMove); final NPC blueNPC = new NPC(new Attore(blue), verticalMove); final JFrame window = new JFrame("Sample") { { enableEvents(AWTEvent.KEY_EVENT_MASK); } protected void processKeyEvent(KeyEvent e) { manageKey(e); } }; window.setSize(640, 480); window.setIgnoreRepaint(true); window.setUndecorated(true); SwingUtilities.invokeLater(new Runnable() { public void run() { window.setVisible(true); window.createBufferStrategy(2); GraphicsConfiguration cfg = window.getGraphicsConfiguration(); GraphicsDevice device = cfg.getDevice(); if(device.isFullScreenSupported()) { device.setFullScreenWindow(window); } else { Rectangle bounds = cfg.getBounds(); window.setSize(bounds.width, bounds.height); } BufferStrategy bs = window.getBufferStrategy(); renderer = new Renderer(bs, new Rectangle(0, 0, window.getWidth(), window.getHeight()), whiteNPC, blueNPC); gameLoop = new GameLoop(renderer, whiteNPC, blueNPC); gameLoop.start(); } }); } private void manageKey(KeyEvent e) { gameLoop.stop(); Window w = JOptionPane.getFrameForComponent((Component)e.getSource()); GraphicsConfiguration cfg = w.getGraphicsConfiguration(); GraphicsDevice dev = cfg.getDevice(); if(dev.isFullScreenSupported()) { dev.setFullScreenWindow(null); } w.dispose(); } public static void main(String...args) { new Main().startApp(); } } |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 06:10.