Creare Giochi multiplayer

« Older   Newer »
  Share  
Tony™
view post Posted on 24/10/2010, 17:33




Giocare i giochi sul proprio computer è divertente, ma giocare contro un altro giocatore può esserlo ancora di più, ed è anche facile da fare visto che non devi implementare l'IA del giocatore-computer. Due giocatori potrebbero anche giocare con lo stesso computer ma con device di input differenti, ma è ancora meglio quando ciascun giocatore può sedersi davanti al proprio computer. O ancora meglio, un giocatore gioca dall'altra parte dell'oceano. Dalla versione 4.1 di Game Maker sono state implementate le funzioni per il multiplayer e questo tutorial ti insegna ad usarle.

Purtroppo creare giochi multiplayer non è facile, perciò è richiesta abbastanza esperienza nell'uso di Game Maker. Devi conoscere, capire e usare molto codice, perciò non vi consiglio di implementare il multiplayer nel vostro primo gioco.

In questo tutorial imparerete a creare un semplice gioco di ping-pong. La cosa più divertente non sarà la grafica stupefacente o la giocabilità elevata, ma solo l'aspetto del multiplayer che poi ti servirà a creare giochi di grafica eccellente e di giocabilità elevata. Noi tratteremo i seguenti aspetti:

- Settare una connessione da computer differenti;

- Creare o partecipare ad una sessione;

- Sincronizzare il tempo di gioco.

L'ultima parte sarà la più difficile in ogni gioco multiplayer. Il problema è come fare a mostrare la stessa visuale durante il gioco. Per esempio, nel gioco di ping-pong, i due giocatori dovranno vedere la palla nella stessa posizione. Game Maker ti offre le istruzioni per farlo, ma dovrai scriverle ogni volta tu per ogni gioco che fai.

Settare una connessione

Per far funzionare un gioco in multiplayer ogni giocatore ha bisogno di una copia del gioco che dovrà avviare. Uno dei giocatori dovrà fungere da server, l'altro da client. Il server dovrà avviare la partita per primo e creare una sessione, il client dovrà partecipare alla sezione e quindi al gioco. il giocatore dovrà scegliere il meccanismo usato per comunicare tra i computer. Per una partita in locale è più diffusa la connessione IPX (vedi dopo per maggiori dettagli). Se tutti i giocatori sono connessi a Internet, la connessione più usata è la TCP/IP. Per questo protocollo bisogna necessariamente sapere l'IP del server. Perciò per la connessione TCP/IP il server deve dare il proprio indirizzo IP al client (per esempio inviandogli un e-mail). Puoi sapere il tuo indirizzo IP aprendo il file chiamato winipcfg.exe nella tua directory di windows. Un altro modo per connettersi è usare una connessione modem (in questo caso il client deve conoscere il numero di telefono del server e fornirlo al gioco) o usando una linea seriale.

Quindi per far comunicare due computer c'è bisogno di un protocollo di connessione. Come molti giochi, Game Maker offre quattro tipi differenti di connessioni; IPX, TCP/IP, Modem e Seriale. La connessione IPX (per essere precisi è un protocollo) lavora in un modo trasparente. Può essere usata per giocare con altre persone nella stessa area locale. Deve essere installata sul computer per essere usata (Se non funziona consulta la documentazione di Windows o vai nel pannello di controllo alla sezione Rete ed aggiungilo). TCP/IP è il protocollo usato in internet. Può essere usato per giocare ad un gioco usando una linea internet, sapendo solo il tuo indirizzo IP. In una connessione locale non è necessario che tu fornisca il tuo indirizzo. Una connessione di tipo modem è usata esclusivamente per chi possiede un modem. Tu devi dare alcune opzioni del modem (una stringa di inizializzazione ed un numero di telefono) per poterlo usare. Infine quando usi una linea seriale (una connessione diretta tra computers) devi dare un numero di porta. Ci sono quattro funzioni GML che permettono di inizializzare queste connessioni:

1. mplay_init_ipx() inizializza una connessione IPX.

2. mplay_init_tcpip(indir) inizializza una connessione TCP/IP. indir è una stringa che può contenere un indirizzo web o IP come "www.gioco.es" o "123.123.123.12" possibilmente seguiti da il numero di porta (che non è indispensabile) come ":12". Solo quando partecipi ad una sessione (vedi dopo) devi provvedere il tuo indirizzo. In un'area locale non c'è bisogno che tu fornisca un indirizzo, ma devi comunque chiamare la funzione.

3. mplay_init_modem(strinizial,n°telefon) inizializza una connessione modem. strininizial sta per stinga di inizializzazione del modem (può essere vuota). n°telefon è una stringa che conterrà il numero da chiamare (es. "0453232242"). Solo quando partecipi ad una sessione devi fornire il numero di telefono.

4. mplay_init_serial(n°port,baudrate,stopbits,parity,flow) inizializza una connessione seriale. n°port è il numero di porta, da 1 a 4. baudrate è il baudrate da usare (100-256K). stopbits è il numero di stopbits(0=1 bit, 1=1.5 bit, 2=2 bits). parity indica il numero di parity(0=none, 1=odd, 2=even, 3=mark). E flow indica il tipo di controllo flow (0=none, 1=xon/xoff, 2=rts, 3=dtr, 4=rts e dtr). Restituisce se ha successo. Una tipica chiamata seriale è "1,57600,0,0,4".

Il tuo gioco dovrebbe chiamare una di queste. Tutte le funzioni restituiscono se hanno successo. Non hanno successo se un particolare protocollo non è installato o non è supportato dalla macchina.

Quindi nella prima stanza dovresti mostrare una lista dei quattro protocolli tra le quali il giocatore dovrà scegliere (potresti anche omettere le ultime due visto che sono poco usate nei giochi). Noi chiamiamo la funzione di inizializzazione nell'evento mouse al click sinistro, e se avrà successo andremo alla pagina successiva, altrimenti gli stamperemo un fatidico messaggio d'errore. Quindi nell'evento mouse del bottone IPX dobbiamo digitare il seguente codice:


if (mplay_init_ipx())
{
room_goto_next()
}
else
{
show_message('Fallita la connessione IPX')
}

Quando finiamo il gioco, dobbiamo sempre terminare qualsiasi protocollo in esecuzione con:

1. mplay_end() finisce la connessione corrente. Restituisce se ha successo.

Sessioni di gioco

Quando ti connetti, possono esserci numerosi giochi che si svolgono nello stesso istante. Noi chiameremo ognuna di esse "sezioni". Differenti sessioni possono appartenere a giochi differenti o allo stesso gioco. Ogni gioco deve identificare se stesso sulla rete. Fortunatamente viene gestito automaticamente anche questo da Game Maker. L'unica cosa che devi sapere e che quando cambi l'id del tuo gioco della scheda Option è come se i due giochi siano differenti. Questo è utile a chi fa due versioni del gioco e che non vuole che funzionino insieme.

Se vuoi iniziare a giocare in multiplayer devi creare una sessione. Per fare questo devi chiamare questa funzione:

1. mplay_session_create(nomesessione,n°giocatori,nomegioca) crea una nuova sessione sulla seguente connessione. nomesessione è la stringa che indica il nome della sessione. n°giocatori è un numero che indica il numero massimo di giocatori che ci può essere in una sezione (scrivi 0 per un numero arbitrario). nomegioca è il nome che si dà al giocatore mentre gioca. Restituisce se ha successo.

In molti casi il nome del giocatore non è usato ed equivale ad una stringa vuota. Mentre il nome della sessione è importante se vuoi dare al giocatore la possibilità di partecipare ad una sessione.

Quindi un giocatore deve creare la sessione. L'\gli altro\i deve\ono partecipare alla sessione. Questa è una cosa abbastanza complicata. Il primo passo da fare è vedere quale delle sessioni è disponibile e quale no, dopo far partecipare il giocatore ad una di esse. Ci sono tre importanti funzioni per fare ciò:

1. mplay_session_find() cerca tutte la sessioni disponibili e restituisce il numero di esse.

2. mplay_session_name(n°) restituisce il nome della sessione n°(0 è la prima sessione). Questa funzione può essere chiamata solo dopo aver chiamato la precedente.

3. mplay_session_join(n°,nomegioca) ti fa partecipare alla sessione numero n°(0 è la prima). nomegioca è il nome che si vuole dare al giocatore. Restituisce se ha successo.

4. mplay_session_mode(muovi) setta se o non muovere l'host su di un altro computer quando il computer che fa host decide di uscire dalla sezione, molto utile se bisogna fare giochi che continuano fino a quando non ci sono giocatori. muovi può essere true o false (in default)

Quindi normalmente dovresti chiamare la funzione mplay_session_find() per cercare tutte le sessioni esistenti. Potresti usare la funzione mplay_sessin_name() per mostrare al giocatore il nome di tutte le sessioni o farlo partecipare direttamente alla prima sessione disponibile (nota che per cercare le sessioni ci vuole molto tempo, quindi evita di chiamare questa sessione ogni step).

Un giocatore può stoppare la sessione attraverso questa funzione:

1. mplay_session_end() finisce la sessione per questo giocatore.

Questo è utile per prima avvertire l'altro giocatore ma non è indispensabile.

Quindi ritornando al nostro pong, la seconda stanza ti darà la possibilità di creare una sessione o partecipare ad una sessione. Per fare questo inseriamo il seguente codice nell'evento del tasto sinistro del mouse:


if(mplay_session_create('',2,''))
{
global.master = true
room_goto_next()
}
else
{
show_message('Fallita la creazione della sessione')
}

Nota la variabile master impostata a true. Quella variabile sarà impostata in quel modo perchè vogliamo far differire chi crea la sessione (detto master), da chi invece partecipa (detto slave, schiavo). Il master è responsabile della maggior parte della giocabilità del gioco, mentre lo slave lo segue soltanto.

La seconda cosa è far partecipare il giocatore ad una partita. Per il codice guarda qui:


if (mplay_session_find() > 0)
{
if (mplay_session_join(0,''))
{
global_master = false
room_goto(rm_gioco)
}
else
{
show_message('Fallita la procedura di partecipazione')
}
}
else
{
show_message('Non ci sono partite a cui partecipare')
}

In questo pezzo di codice, oltre ad impostare la variabile globale master a falso, facciamo partecipare il giocatore alla prima sessione disponibile.

Gestire il giocatore

Una volta che il master ha creato la sessione, dobbiamo far si che aspetti che un altro giocatore partecipi. In questo caso ci possono essere utili le seguenti funzioni:

1. mplay_player_find() cerca tutti i giocatori della sezione seguente e restituisce il numero di essi.

2. mplay_player_name(n°) restituisce il nome del giocatore numero n° (scrivi 0 per indicare il primo della lista, che sei sempre tu). Questa funzione deve essere sempre chiamata prima di aver chiamato la prima.

3. mplay_player_id(n°) restituisce l' id del giocatore numero n° (scrivi 0 per indicare il primo della lista, che sei sempre tu). Questa funzione deve essere sempre chiamata prima di aver chiamato la prima. L'id è utile per inviare e ricevere messaggi ad/da un determinato giocatore (vedremo dopo).

Nella nostra terza stanza attenderemo semplicemente che i giocatori siano 2.


if(mplay_player_find()=2)
{
room_goto_next()
}

(Noi non dobbiamo far andare lo slave in questa stanza)

Sincronizzare le azioni

Adesso che abbiamo settato la connessione, abbiamo impostato la sessione ed abbiamo due giocatori in essa, il vero gioco può iniziare. Ma significa anche che la vera comunicazione tra i computer inizia e con questa anche la parte più complicata del multiplayer. Il vero problema in un gioco multiplayer è il sincronismo. Come possiamo essere sicuri che i giocatori vedano la stessa identica cosa su i propri computer? Questo è cruciale. Quando un giocatore, nell'esempio del nostro gioco di pong, vede la palla in un posto diverso dell'altro, delle cose molto strane e curiose possono accadere (un giocatore per esempio colpisce la palla con la paletta, mentre l'altro vede che l'ha mancata). Il gioco va semplicemente fuori sincronismo, creando caos nel gioco.

La cosa peggiore è che dovremo correggere tutto questo con un limitato numero di comunicazioni. Se per esempio stai giocando con un modem la connessione può essere lenta, perciò limitare la comunicazione tra i due computer è indispensabile. Ci potrebbero anche essere dei ritardi quando i dati arrivano all'altro computer. Infine potrebbe essere che i dati non arrivino neanche dall'altra parte.

La migliore soluzione al tuo problema dipende dal tipo di gioco che stai creando. In un gioco strategico a turni usi un meccanismo completamente diverso da quello che potresti usare per un gioco in tempo reale.

Game Maker usa due meccanismi di comunicazione: i dati condivisi ed i messaggi. I dati condivisi sono un meccanismo abbastanza semplice da usare. Mandare messaggi è molto versatile ma necessita la conoscenza di come funziona la comunicazione.

Comunicazione con dati condivisi

I dati condivisi sono sicuramente il modo migliore per sincronizzare il gioco. Tutte le comunicazioni sono gestite da te. Consiste in una serie di 10000 valori comuni per tutte le entità del gioco. Ogni entità può leggere i valori e modificarli. Per far ciò ci sono due funzioni

1. mplay_data_read(ind,var) scrive la variabile var (una stringa o un numero) nella posizione ind (ind può essere tra 0 e 10000).

2. mplay_data_read(ind) restituisce il valore contenuto nella locazione ind (ind può essere da 0 a 10000). Se non settate dalla precedente funzione il valore sarà 0.

Per usare questo meccanismo devi determinare quale valore è usato e per cosa serve, e chi deve cambiarlo. Preferibilmente solo una istanza del gioco è abilitata a cambiare o a scrivere il valore.

Nel nostro caso ci sono 4 importanti valori da trasmettere: il valore y della paletta del master per il quale utilizzeremo la postazione 1, il valore y della paletta dello slave per il quale utilizzeremo la postazione 2, ed il valore x ed y della palla con la locazione 3 e 4. Naturalmente ogni giocatore dovrà settare la variabile della propria posizione y. Mentre sarà il master a settare la variabile x ed y della palla mentre lo slave dovrà semplicemente occuparsi di disegnare la palla nella posizione in cui si trova quella del master.

Come facciamo a far eseguire tutto questo? Intanto la paletta del master dovrà essere controllata solo dal master. Questo vuol dire che negli eventi su e giù della tastiera della paletta rossa dobbiamo assicurarci che il giocatore sia il master e viceversa per la paletta blu. Il tutto con questo codice:


if global.master
{
y -= 6
mplay_data_write(1,y);
}

Nell'evento step della paletta blu dobbiamo eseguire il codice caso mai il giocatore è slave attraverso il seguente codice:


if global.master = false
{
y = mplay_data_read(1);
}

Qualcosa di simile per la paletta blu.

Per quanto riguarda la palla dobbiamo essere sicuri che quando urta o contro le palette o contro il muro rimbalzi. Questo deve essere gestito solo dal master. Per comunicare la posizione della palla dobbiamo semplicemente usare questo pezzo di codice nell'evento step dell'oggetto:


if global.master
{
mplay_data_write(3,x);
mplay_data_write(4,y);
}
else
{
mplay_data_read(3);
mplay_data_read(4);
}

Con questo abbiamo finito la comunicazione di base del pong. Cosa ci rimane sono piccolezze come il punteggio dei punti. Tutto questo dovremmo mettere tutto nelle mani del master. Quindi il master sancirà quando un giocatore ha perso (per fare questo ci dovremmo servire di una posizione extra tra le locazioni per comunicare all'altro giocatore il punteggio), e giocare una nuova palla.

Nota che il gioco che abbiamo appena fatto manca di sincronismo, ma questo è un problema che risolveremo.

Messaggi

Il secondo meccanismo di comunicazione che Game Maker supporta è l'inviare e ricevere messaggi. Un giocatore può mandare un messaggio ad un giocatore specifico o a tutti i giocatori. Il giocatore che riceve un messaggio agisce a seconda del messaggio. I messaggi possono essere inviati in modo garantito e puoi essere sicuro che arrivi al destinatario (ma è molto lento), e in modo non garantito, che è molto più veloce.

Noi utilizzeremo i messaggi inizialmente solo per aggiungere qualche effetto sonoro al nostro gioco. Faremo partire un suono quando la palla urta le palette, quando il muro, e quando un giocatore segna un punto. Solo il master deve controllare questi eventi e quindi è il master a decidere se un suono deve essere suonato. E' facile suonare il suono sul proprio computer ma non altrettanto sul computer dello slave. Potremo usare i dati condivisi per fare ciò ma sarebbe ancora più complicato. Usare i messaggi è molto semplice. Il master invia semplicemente un messaggio allo slave e gli dice di suonare il suono. Lo slave riceve il messaggio e suona il corretto suono. Tutto ciò è permesso usando le seguenti funzioni:

1. mplay_message_send(giocat,id,valore) manda un messaggio al giocatore indicato in giocat (il nome che lo identifica; usa 0 per inviare il messaggio a tutti). id è il numero che identifica il messaggio e valore è il valore del messaggio. Il messaggio è inviato in modo non garantito.

2. mplay_message_send_guaranteed(giocat,id,valore) manda un messaggio al giocatore indicato in giocat (il nome che lo identifica; usa 0 per inviare il messaggio a tutti). id è il numero che identifica il messaggio e valore è il valore del messaggio. Il messaggio è inviato in modo garantito.

3. mplay_message_receive(giocat) riceve il prossimo messaggio che si trova nella lista del giocatore giocat (nome di identificazione). Usa 0 per ricevere messaggi da tutti i giocatori. La funzione restituisce se il computer ha ricevuto il messaggio. Se sì, si possono usare le seguenti funzioni per scoprire il contenuto:

1. mplay_message_id() restituisce il numero di identificazione dell'ultimo messaggio.

2. mplay_message_value() restituisce il valore dell'ultimo messaggio.

3. mplay_message_player() restituisce il numero del giocatore che ti ha inviato l'ultimo messaggio ricevuto.

4. mplay_message_name() restituisce il nome del giocatore che ti ha inviato l'ultimo messaggio ricevuto.

5. mplay_message_count(giocat) restituisce il numero dei messaggi che devi ancora ricevere del giocatore giocat (indica 0 se vuoi il numero di tutti i messaggi che ancora devi ricevere).

Qui bisogna soffermarsi un po'. Prima di tutto se vuoi inviare un messaggio ad un giocatore in particolare, devi conoscere il suo id. Puoi ottenerlo facilmente con la funzione mplay_player_id(). Questo id può essere usato pure per ricevere messaggi da un particolare giocatore. Una alternativa all'id è fornire il nome del giocatore come stringa, cosicchè se più giocatori hanno lo stesso nome bisogna per forza usare il primo metodo.

In secondo luogo, potresti pensare perchè ogni messaggio ha un numero id. La ragione è che questo aiuta la tua applicazione ad inviare diversi tipi di messaggi. Ad ogni id equivale una diversa azione (in messaggi non garantiti, inviare id e valore in diversi messaggi potrebbe causare numerosi problemi e potresti immaginarti il perchè).

Per suonare dovremo fare come segue: quando il master determina che la palla urta la paletta dovrà eseguire il seguente codice:


if global.master
{
// suona il rimbalzo
sound_play(snd_Rimbalzo); // suona su se stesso
mplay_message_send(0,100,snd_Rimbalzo); // manda il comando di suonare sullo slave
}

Quindi l'oggetto controllo nell'evento step esegue il seguente codice:


// Ricevere i messaggi
while (mplay_message_receive(0))
{
messid = mplay_message_id();
val = mplay_message_value();
// Vede se ci sono suoni da suonare
if messid = 100
{
sound_play(val)
}
}

Adesso, se non avete capito bene, vedremo nello specifico come funziona il codice per ricevere i messaggi. Se l'id del messaggio è uguale a 100 dovrà suonare il suono, che specifica il contenuto del messaggio.

Tipicamente questo è lo scheletro che dovresti usare in ogni tuo gioco nell'evento step del tuo oggetto controllo:


while (mplay_message_recive(0))
{
da = mplay_message_player()
nome = mplay_message_name()
messid = mplay_message_id()
val = mplay_message_value()
if messid = 1
{
//Fa qualcosa
}
if messid = 2
{

}//Fa qualcos'altro
//eccetera
}

Disegnare con cura il protocollo usato (cioè indicare che messaggio è inviato, da chi, in quale momento e come il giocatore deve reagire in seguito) è estremamente importante.

Esperienza e studiare attentamente gli esempi degli altri aiuta molto.

Dead-reckoning

Ma il pong da noi creato presenta nuovamente un grosso problema. Quando c'è un problema nella comunicazione (un hick-up) la palla dello slave si ferma momentaneamente, poichè non arrivano altre coordinate e la palla rimane nello stesso posto dello step precedente. Questo problema succede in seguito a distanza elevate e/o quando la comunicazione è lenta. Quando tu farai un gioco più complesso ti servirà lo scambio di più valori, e quando ci sarà un enorme numero di cifre in ogni step ci sarà da trasmettere valori in grande quantità. Questo può causare o il rallentamento del gioco in corso o fa diminuire il sincronismo.

Una prima cosa per evitare questo può essere non inviare dati condivisi in modo garantito. Per fare ciò usa questa funzione:

1. mplay_data_mode(garan) setta se usare o no il modo garantito per la comunicazione con dati condivisi. garan può essere true (in default) o false.

Un modo intuitivo per rimediare a queste situazioni è quello di usare il metodo del cosiddetto dead-reckoning. Noi inviamo le informazioni solo volta per volta. Il gioco dovrà funzionare con il minimo della comunicazione tra i computer e quindi di prendere solo i dati vitali allo svolgimento del gioco.

Useremo questo nel nostro pong. Noi non invieremo più le informazioni della posizione della palla in ogni step, ma invieremo solo ogni tanto la direzione e la velocità del momento. Lo slave quindi dovrà dipendere un po' di più da se stesso e dovrà fare da se la maggior parte dei calcoli. Quando non arrivano più informazioni dal master semplicemente calcola dove si sposterà la palla

Quindi in questo caso non useremo i dati condivisi ma i messaggi. Ci saranno messaggi che indicheranno un cambiamento nella posizione della palla, la velocità, della posizione della paletta, ecc. Il master invia i messaggi quando qualcosa cambia mentre l'oggetto di controllo dello slave riceve i messaggi e setta i giusti parametri. Ma se lo slave non riceve niente tutto continua a muoversi come niente fosse. Se ci fossero degli errori, il messaggio del master correggerà la posizione. Così nell'evento step della palla potremo usare il seguente codice:


if global.master = false
{
mplay_message_send(0,11,x)
mplay_message_send(0,12,y)
mplay_message_send(0,13,speed)
mplay_message_send(0,14,direction)
}

Mentre nell'evento step dell'oggetto controllo così:


// Ricevere i messaggi
while (mplay_message_receive(0))
{
messid = mplay_message_id();
val = mplay_message_value();
// Vede se ci sono cambiamenti nella posizione delle palette
if messid = 1
{
obj_Paletta_rossa.y = val
}
if (messid == 2)
{
obj_Paletta_blu.y = val
}
// Vede se ci sono cambiamenti nella palla
if messid = 11
{
obj_Palla.x = val
}
if messid = 12
{
obj_Palla.y = val
}
if messid = 13
{
obj_Palla.speed = val
}
if messid = 14
{
obj_Palla.direction = val
}
// Vede se ci sono suoni da suonare
if messid = 100
{
sound_play(val)
}
}

Nota che il messaggio non ha bisogno di essere inviato in modo garantito. Se ne saltiamo uno non dovrebbe causare un grosso problema.

Adesso se proverai ad avviare il gioco il problema più visibile è il fatto che la trasmissione è lenta. Questo significa che lo slave riceve moltissimi messaggi per step e non è capace di gestirli tutti. Quindi metterà la palla molto indietro e quando arriverà il nuovo messaggio con la posizione la trasferirà molto più avanti di prima. La soluzione è nel gioco incluso nel file zip multiplayer.zip.

In questo caso scambiamo le informazioni solo quando la palla urta contro la paletta perciò per il resto lo slave userà il dead-reckoning. Il master è responsabile di quello che accade dalla sua parte e lo slave dell'altra parte. Mentre la palla si muove da una parte all'altra non c'è scambio di messaggi.

Dovresti vedere la palla muoversi fluidamente. Solo quando la palla urta potrebbe esserci un piccolo hick-up o la palla potrebbe iniziare a muoversi prima che abbia raggiunto la paletta dell'avversario. La ragione di tutto questo è che questo meccanismo presuppone che i due giochi vadano alla stessa velocità. Se uno dei computer è lento potrebbe causare problemi. Ma un hick-up ad una paletta è più accettabile di uno durante il movimento. Per risolvere questo problema bisognerebbe usare tecniche molto avanzate. Per esempio potresti vedere la velocità di un computer e diminuire tutte le velocità degli altri giocatori.

Conclusione

Le funzioni multiplayer di Game Maker ti permettono di creare giochi complessi e belli, ma tutto dipende dall'abilità del programmatore di saperle usare e gestirle sapendole implementare perfettamente nel proprio gioco. Elenco qui alcune note importanti per poter fare un gioco multiplayer
 
Top
0 replies since 24/10/2010, 17:33   200 views
  Share