Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Intervista a Stop Killing Games: distruggere videogiochi è come bruciare la musica di Mozart
Intervista a Stop Killing Games: distruggere videogiochi è come bruciare la musica di Mozart
Mentre Ubisoft vorrebbe chiedere agli utenti, all'occorrenza, di distruggere perfino le copie fisiche dei propri giochi, il movimento Stop Killing Games si sta battendo per preservare quella che l'Unione Europea ha già riconosciuto come una forma d'arte. Abbiamo avuto modo di parlare con Daniel Ondruska, portavoce dell'Iniziativa Europa volta a preservare la conservazione dei videogiochi
Samsung Galaxy S25 Edge: il top di gamma ultrasottile e leggerissimo. La recensione
Samsung Galaxy S25 Edge: il top di gamma ultrasottile e leggerissimo. La recensione
Abbiamo provato il nuovo Galaxy S25 Edge, uno smartphone unico per il suo spessore di soli 5,8 mm e un peso super piuma. Parliamo di un device che ha pro e contro, ma sicuramente si differenzia dalla massa per la sua portabilità, ma non senza qualche compromesso. Ecco la nostra prova completa.
HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
Pensato per il professionista sempre in movimento, HP Elitebook Ultra G1i 14 abbina una piattaforma Intel Core Ultra 7 ad una costruzione robusta, riuscendo a mantenere un peso contenuto e una facile trasportabilità. Ottime prestazioni per gli ambiti di produttività personale con un'autonomia lontano dalla presa di corrente che permette di lavorare per tutta la giornata
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 07-04-2006, 09:21   #1
DesmoColo
Senior Member
 
L'Avatar di DesmoColo
 
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!
DesmoColo è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 10:57   #2
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Quote:
Originariamente inviato da DesmoColo
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?
Direi proprio di si. Ovviamente quando il numero di nemici si incrementa di molto, dovrai cercare altre soluzioni

High Flying
Sottovento
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 12:37   #3
cionci
Senior Member
 
L'Avatar di cionci
 
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 E' una risposta banale, ma nemmeno tanto
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 14:23   #4
DesmoColo
Senior Member
 
L'Avatar di DesmoColo
 
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);
        }
che disegna gli attori.
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!
DesmoColo è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 14:42   #5
cionci
Senior Member
 
L'Avatar di cionci
 
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 ?
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 15:17   #6
DesmoColo
Senior Member
 
L'Avatar di DesmoColo
 
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;
    }
Quindi gli attori vengono disegnati dal rendering invocando il metodo draw() di un attore.
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!
DesmoColo è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 15:37   #7
cionci
Senior Member
 
L'Avatar di cionci
 
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
   }
}
Ti posto anche timer, giusto per farti capire:
Codice:
public class Timer
{
    private long time;

    public Timer()
    {
        time = System.nanoTime();
    }

    public long getTime()
    {
        return (System.nanoTime() - time) / 1000000;
    }
}
Con il valore 20 (che puoi mettere in una cosatante) specifichi che ogni 20 ms (50fps) venga effettuato un loop del gioco... move esegue il movimento logico dei nemici (sposta il loro valore interno di x e y)... render deve fare il rendering dei nemici e del giocatore...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 16:37   #8
DesmoColo
Senior Member
 
L'Avatar di DesmoColo
 
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...
Allegati
File Type: zip codice.zip (3.7 KB, 3 visite)
__________________
God rides DUCATI!
DesmoColo è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 16:49   #9
cionci
Senior Member
 
L'Avatar di cionci
 
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...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 07-04-2006, 20:35   #10
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
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;
	}
}
Con un attore di questa specie:

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 questo punto vuoi trasformare alcuni attori in personaggi la cui logica sia gestita attraverso dei Thread autonomi dal Thread del proiettore.

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();
}
Qui getTick è il periodo del ciclo della "intelligenza artificiale".

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;
			}
		}
	}
}
A questo punto devi però modificare il ciclo di gioco in modo tale che l'avvio causi avvio anche delle entità concorrenti. La cosa più sentitica che sono riuscito a scrivere al riguardo è:

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;
		}
	}
}
Qui l'avvio del motore di gioco causa (prima istruzione del metodo run()) l'avvio delle entità-attore che siano degli NPC. Specularmente, al termine dell'esecuzione (stop()) GameLoop si occupa anche di fermare tutti gli NPC.

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();
	}
}
Diciamo che questo è un paio di maniche a cui occorre attaccare il resto della camicia. Manca, infatti, la gestione delle collisioni: qui hai un milione di entità di cui non puoi predire l'ordine di movimento. In particolare, Pippo potrebbe rilevare che la posizione (x,y) sia libera e trovarsi, nonostante ciò, accavallato a Mario. Occorre fare in modo che la lettura di una posizione ai fini del rilevamento di collisioni impedisca il movimento fintantochè non sia terminato il computo delle restrizioni allo spostamento. Il che va un po' oltre la semplice sincronizzazione della lettura/scrittura degli stati.
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Intervista a Stop Killing Games: distruggere videogiochi è come bruciare la musica di Mozart Intervista a Stop Killing Games: distruggere vid...
Samsung Galaxy S25 Edge: il top di gamma ultrasottile e leggerissimo. La recensione Samsung Galaxy S25 Edge: il top di gamma ultraso...
HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto HP Elitebook Ultra G1i 14 è il notebook c...
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso Microsoft Surface Pro 12 è il 2 in 1 pi&u...
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet! Recensione REDMAGIC Astra Gaming Tablet: che spe...
Samsung, mega accordo da 16,5 miliardi p...
Le 18 offerte Amazon del weekend, senza ...
Galaxy S25 Ultra 512GB sotto i 1.000€ su...
Vi piace l'iPhone nero? Su Amazon sono s...
MacBook Air M4 16GB/256GB e 16GB/512GB s...
4 portatili per risparmiare tanto ed ess...
San Marino multa TikTok: non controllano...
Dreame e Roborock in saldo su Amazon: ro...
Pazzesco su Amazon: crollano i prezzi de...
La Corea del Sud vorrebbe costruire una ...
Rilasciati i primi risultati delle anali...
Robot umanoidi low cost? Unitree ci prov...
Non solo Rocket Lab, anche Avio potrebbe...
Chips Act UE: 41,5 milioni di euro a Eph...
Ryzen Threadripper 9000 al debutto il 31...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 06:10.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v