View Full Version : Collision detect e oggetti veloci
Come posso determinare la collisione tra un proiettile(un oggetto che si muove a velocità altà rispetto il sistema) e una matrice di bit(true=terreno, false=nulla)?
Mi spiego, io ora controllo semplicemente se nella matrice di bit alla posizione del proiettile ho un true o un false. Funziona benone e sopratutto è velocissimo, il problema è che se l'oggetto in questione si muove troppo veloce, quindi nel tempo dt di elaborazione si sposta di troppi pixel, vado incontro a due problemi:
1) Mettiamo che ogni dt l'ogetto si sposti di 10 pixel, un attimo prima di elaborare la posizione esso non collide, ma l'attimo dopo si...e siccome si è spostato di molto la collisione viene "registrata" in una posizione troppo distante da dove effettivamente c'era.
2)L'effetto di vedere un oggetto spostarsi di tanti pixel alla volta non è bello anche se il tutto è fluido, come posso creare una certa continuità della scena?
Per ora la mia unica effettiva soluzione è stata quella di diminuire il tempo di elaborazione, in questo modo la CPU fa molti più calcoli di posizioni ma il carico diventa troppo...
Il fatto di conoscere la vera posizione di collisione è fondamentale in quanto mi serve per sapere dove danneggiaere il terreno.
Nella situazione attuale accade che se il proiettile va molto veloce il terreno si danneggia internamente e non sulla superficie...tenete come esempio worms.
Il fatto di conoscere la vera posizione di collisione è fondamentale in quanto mi serve per sapere dove danneggiaere il terreno.
Nella situazione attuale accade che se il proiettile va molto veloce il terreno si danneggia internamente e non sulla superficie...tenete come esempio worms.
Non mi pare difficile...
se tu conosci la posizione del tuo terreno, una volta che determini la collisione, danneggi il terreno in quel punto.
Per esempio:
Ora non sò se è 3D cmq, se hai coordinate del terreno per esempio un quadrato in pixel xyz 10,0,10 (y è l'altezza) e il proiettile ha coordinate (come tu dici, sorpassa il terreno ovvero posizioneProiettile <=0 ovvero y l'altezza) se il proiettile ha coordinate 7,0,8 significa che collide con il terreno ma come tu dici si sposta per 10 pixel in avanti quindi con il tuo proiettile fai un controllo della collisione tipo:
posizioneProiettile 7,-10,8 terreno 10,0,10 il risultato è che -10 è < di 0 quindo collisione a questo punto danneggi il terreno alle coordinate del terreno 7,0,8 è chiaro che devi sempre danneggiare il terreno a coordinate 0 ovvero la y infatti se danneggi il terreno a coordinate -10 danneggeresti il terreno a -10 pixel dal sul punto reale.
Pseudo code:
posizioneTerreno = 10,0,10
PosizioneProiettile = 7,47,4
PosizioneProiettile = 7,37,4
PosizioneProiettile = 7,27,4
PosizioneProiettile = 7,17,4
PosizioneProiettile = 7,7,4
PosizioneProiettile = 7,-3.4 // cè collisione allora
danneggiamentoTerreno = 7,0,4
quale è il problema??
Non è così semplice, il gioco è in 2D, come terreno ho una immagine, fai conto che l'immagine sia a 2 colori, bianco e nero, nero=terreno bianco=aria.
Il proiettile si sposta dentro questa immagine quindi le sue coordinate sono gli indici della matrice terreno[y][x].
Io non so a priori a che altezza si trova il terreno, io so che ho impattato quando effettivamente tocco il terreno, se non lo tocco non so nemmeno che esiste...
http://img205.imageshack.us/img205/6529/collisioneuh8.th.jpg (http://img205.imageshack.us/my.php?image=collisioneuh8.jpg)
invece di fare la collision per pixel, falla per range.
prendi il punto di partenza, il punto di arrivo e verifichi se al suo interno sia presente del terreno.
pero nel caso di traiettorie curve la cosa è abbastanza complicata..
Si ci avevo pensato ma il problema non è che è complicato, ma esoso per la cpu, considera che lo dovrebbe fare per ogni proiettile, e i proiettili sono davvero tanti...
Non è così semplice, il gioco è in 2D, come terreno ho una immagine, fai conto che l'immagine sia a 2 colori, bianco e nero, nero=terreno bianco=aria.
Il proiettile si sposta dentro questa immagine quindi le sue coordinate sono gli indici della matrice terreno[y][x].
Io non so a priori a che altezza si trova il terreno, io so che ho impattato quando effettivamente tocco il terreno, se non lo tocco non so nemmeno che esiste...
http://img205.imageshack.us/img205/6529/collisioneuh8.th.jpg (http://img205.imageshack.us/my.php?image=collisioneuh8.jpg)
Allora puoi fare in 2 modi:
1. Metodo molto performante.
Leggi l'immagine come si fà per un terrain engine calcolando i punti dei pixel dell'immagine dove il bianco è 0 e il nero 255 (ovvero i pixel dell'immagine) infatti se hai solo il bianco e il nero ricavi una matrice, matrice ovviamente la fai bidimensionale (x,z), come la coordinata del proiettile (x,z) si trova interpola il 255 di valore ci sarà collisione. Il tutto lo devi precalcolare prima nell'init(); e poi con le coordinate del proiettile fai l'algoritmo di iterpolazione.
2. Metodo
Non sò di quanti pixel è l'immagine che adotti cmq se è quella postata essa è di 246, 188 pixel (per esempio) prepari una griglia bidimensionale di:
griglia(246, 188);
Ora fai contenere in questa griglia tanti quadrati di 10 pixel x 10 pixel.
Ti trovi quanti quadrati ci sono in griglia, che ne sò in questo caso avrai 24.6 quadrati in x e 18.8 quadrati in z. Totale quadrati 18.8 x 24.6.
L'algoritmo di rilevamento in pseudo code è:
fori i=QuadratiOrizzontali
for j=QuadratiVerticali
... quì calcoli se la coordinata del proiettile stà nel quadrato dove c'è del nero = 1 oppure bianco = 0. I quadrati della griglia li puoi fare piccoli piccoli e non si noterà nulla.
Avrai i punti di contatto nella griglia e li confronti con la posizione del proiettile.
Poi anche quì fai l'algoritmo per verificare la collisione.
In tutti e 2 i modi puoi ottimizzare i calcoli in questo modo:
E' inutile eseguire l'algoritmo per verificare se c'è collisione se la coordinata del proiettile non stà nel quadrato della griglia marcato a 0. Se il proiettile stà in un quadrato della griglia ovvero = 1 dove c'è il nero allora c'è collisione
Io l'immagine la leggo e la trasformo già in matrice di bit questo non è un problema. Quindi io ora ho già la matrice di bit.
Per il primo metodo non ho capito come esegue l'interpolazione, mi potresti spiegare un attimo?
Ti faccio un piccolo esempio in modo che tuo lo puoi usare per spigarmi se vuoi.
Questa è la matrice di bit(1=nero 0=bianco):
0 0 0 0 0 0 0 0 0 0 riga 0
0 0 0 0 0 0 0 0 0 0 riga 1
0 0 0 0 0 0 0 0 0 0 riga 2
0 0 0 0 0 0 0 0 0 0 riga 3
1 1 1 1 1 1 1 1 1 1 riga 4
1 1 1 1 1 1 1 1 1 1 riga 5
0 0 0 0 0 0 0 0 0 0 riga 6
0 0 0 0 0 0 0 0 0 0 riga 7
0 0 0 0 0 0 0 0 0 0 riga 8
0 0 0 0 0 0 0 0 0 0 riga 9
Come si può dedurre è presente un rettangolo nero al centro della figura, la matrice è terreno[10][10].
Prendiamo un proiettile che per semplificare è in caduta libera percorrendo la colonna 5, e si muove di 3 pixel alla volta, quindi ad un certo istante si trova nella colonna 5 e riga 3, qui non collide.
L'istante dopo si trova sempre nella colonna 5 ma riga 6, nemmeno qui collide quindi per lui il rettangolo nero non esiste...
In questo caso come uso l'interpolazione?
Il metodo 2 da quel che ho capito è un'ottimizzazione del tutto, prima controllo se si trova in una parte con del terreno, e solo in quel caso inizio con l'elaborazione vera e propria.
Non ho capito però l'elaborazione che intendi, penso sia quella del metodo 1.
Io in mente ho già un metodo, cioè quella di vedere se c'è terreno non solo alla cordinata del proiettile, ma lungo una retta che ha la stessa inclinazione della traiettoria del proiettile e lunga abbastanza da essere più lunga dello spazio percorso in un dt di elaborazione.
Per l'altro problema, cioè quella della visualizzazzione non ci sono soluzioni?
Nei giochi come fanno...quando ci sono oggetti molto veloci sembra sempre che si muovo con una certa continuità...come si ottiene quell'effetto?
Io l'immagine la leggo e la trasformo già in matrice di bit questo non è un problema. Quindi io ora ho già la matrice di bit.
Per il primo metodo non ho capito come esegue l'interpolazione, mi potresti spiegare un attimo?
Ti faccio un piccolo esempio in modo che tuo lo puoi usare per spigarmi se vuoi.
Questa è la matrice di bit(1=nero 0=bianco):
0 0 0 0 0 0 0 0 0 0 riga 0
0 0 0 0 0 0 0 0 0 0 riga 1
0 0 0 0 0 0 0 0 0 0 riga 2
0 0 0 0 0 0 0 0 0 0 riga 3
1 1 1 1 1 1 1 1 1 1 riga 4
1 1 1 1 1 1 1 1 1 1 riga 5
0 0 0 0 0 0 0 0 0 0 riga 6
0 0 0 0 0 0 0 0 0 0 riga 7
0 0 0 0 0 0 0 0 0 0 riga 8
0 0 0 0 0 0 0 0 0 0 riga 9
Come si può dedurre è presente un rettangolo nero al centro della figura, la matrice è terreno[10][10].
Prendiamo un proiettile che per semplificare è in caduta libera percorrendo la colonna 5, e si muove di 3 pixel alla volta, quindi ad un certo istante si trova nella colonna 5 e riga 3, qui non collide.
L'istante dopo si trova sempre nella colonna 5 ma riga 6, nemmeno qui collide quindi per lui il rettangolo nero non esiste...
In questo caso come uso l'interpolazione?
Il metodo 2 da quel che ho capito è un'ottimizzazione del tutto, prima controllo se si trova in una parte con del terreno, e solo in quel caso inizio con l'elaborazione vera e propria.
Non ho capito però l'elaborazione che intendi, penso sia quella del metodo 1.
- Per la fluifità dell'immagine si usa calcolare con l'fps FramePerSecondo di solito la performance giusta è usare 60 frame per un secondo cioè nel ciclo del render(); si fanno passare 60 Immagini(frame) per un secondo 60/1.
Si prende il tempo attuale in secondi e si sottrae al tempo precedente /1000 che corrisponde ad un secondo. In questo modo se su un pc datato 486 i cicli per l'fps sono di 150 al secondo mentre su un xp moderno i cicli sono1500 per secondo eseguendo il calcolo di far passare in un secondo 60 frame in un secondo avrai che su tutti e due i pc il gioco sarà identico come fluidità ovvero su tutti e 2 i pc passeranno 60 frame per secondo, si no come ti spieghi che un 486 e un xp possono giocare in rete senza questo accorgimento?? Se non si usasse questa tecnica dell'fps il missile sparato dall'xp il 486 neanche lo vedrebbe...
- per il quesito dei bit dici che ottieni la matrice con i 0 e 1 quindi lavori con i pixel impostati sulla matrice e la costruisci... perchè devi avere in memoria uesta matrice. Okay... ora non ti rimane che confrontare la posizione dei pixel del missile con la griglia degli 0 e 1.
if posPixelProiettile(x,z)==pos(x,z) && posPixelImmagine(x,z)==0 salta
if posPixelProiettile(x,z)==pos(x,z) && posPixelImmagine(x,z)==1 collidi
for(i=0; i<10; i++)
for(j=0; j<10; j++)
pos(i,j)=j;
- per il quesito dei bit dici che ottieni la matrice con i 0 e 1 quindi lavori con i pixel impostati sulla matrice e la costruisci... perchè devi avere in memoria uesta matrice. Okay... ora non ti rimane che confrontare la posizione dei pixel del missile con la griglia degli 0 e 1.
if posPixelProiettile(x,z)==pos(x,z) && posPixelImmagine(x,z)==0 salta
if posPixelProiettile(x,z)==pos(x,z) && posPixelImmagine(x,z)==1 collidi
for(i=0; i<10; i++)
for(j=0; j<10; j++)
pos(i,j)=j;
si ma io controllo già la posizione del proiettile con la griglia...il problema è che si sposta troppo velocemente e salta delle parti dove in realtà avrebbe colliso...
anziche farlo muovere e poi controllare, controlla e poi muovi: (pp = posizione proiettile)
pp=[50][0] //il proiettile viene sparato
controlli se tra 50-0 e 50-10 (il prossimo frame) c'è del terreno (con un for).
se c'è il terreno fai esplodere il proiettile dove c'è il terreno, altrimenti lo fai arrivare a destinazione. controlli e lo fai ripartire di nuovo.
si ma io controllo già la posizione del proiettile con la griglia...il problema è che si sposta troppo velocemente e salta delle parti dove in realtà avrebbe colliso...
per l'unità di movimento del proiettile ti sposti tramite pixel?? tipo:
pixel+=1; //un pixel alla volta
posProiettile=pixel;
prova invece a muoverti per float. come variabile globale metti
float pixelAvanti;
//per il movimento
pixelAvanti+=0.01; //se è ancora troppo veloce prova 0.001 e via
//0.0001 così via
// finchè non trovi la giusta velocità per il proiettile
posProiettile=pixelAvanti;
ciao
scusa ma se lo fai andare a 0.001 alla volta non è un po lento?..
scusa ma se lo fai andare a 0.001 alla volta non è un po lento?..
se non si usa l'fps (come descritto sopra) 0.001 non è uguale su tutti i pc ma su un xp con 3.ghz sarà ultraveloce mentre su un 486 sarebbe lentissimo.
dato che lui non usa l'fps sulla sua cpu deve addattare la velocità del suo proiettile.
Non ha ancora risposto ma presumo che faccia muovere il proiettile di int = 1;
come i pixel è naturale che il proiettile schizza esempio:
pixel 1 pixel 2 pixel 3
se lui fà pixel+=1;
a 3.ghz neanche lo vedo il proiettile dopo il 3 passaggio di rendere stà già a 4
mentre se usa il float e dosa la velocità farà:
pixel+=0.01;//ovvero ad ogni passaggio incrementa così
dopo 100 passaggi starà ora a 2 e dopo altri 100 passaggi starà a 3
se ha un xp veloce penso che 0.0001 sia buono per valutare la corsa del proiettile.
Se risponde c'è lo confermerà... oppure non ho capito!!
ahh ora ho capito...
ma lui non voleva cambiae la velocità, voleva un aiuto per aggiustare la funzione che valuta il pnto di collisione
ahh ora ho capito...
ma lui non voleva cambiae la velocità, voleva un aiuto per aggiustare la funzione che valuta il pnto di collisione
Se leggi il suo primo post egli sposta di 10 pixel alla volta ecco perchè salta
pixel+=10
significa che ad ogni passaggio si spota di 10 pixel quindi se sta a coordinate 3 e a 7 il bit 1 lui lo scavalca in quanto 3+10 = 13 in pratica scavalca il bit 7 in cui non può fare il confronto.
Nel modo che gli propongo io è di far camminare + lenatmente il proiettile per float come spiegato prima e poi fare un calcolo per le proporzioni al pixel/bit
Si ma il proiettile è un proiettile deve andare veloce! :D
se lo sposto di meno poi devo elaborare più volte la scena per ottenere la stessa velocità!
Ora io faccio l'update della situazione ogni 40ms per avere circa 25 fps, non voglio scendere sotto i 40 ms per non sovraccaricare troppo la cpu, in sostanza il mio gameLoop è controllato da un timer.
Leggendo in giro però ho scoperto che molti non temporizzono il ciclo ma lasciano che la cpu sfrutti tuutta la sua potenza, forse è quella che intendevi tu vero okay? in quel caso si penso che devo ridurre gli spostamenti, ma il mio problema era rivolto a come avevo progettato ora il gioco. Essendo temporizzato a 40ms, la scena la elaboro ogni 40ms ma per far andare veloce un'oggetto mi serve spostarlo di molti pixel alla volta! E' per questo che ho il problema.
Ora forse la soluzione è effettivamente quella tua okay, sto sbagliando il metodo.
Se ho capito bene te dici di lasciare la cpu al 100% e quindi di regolare lo spostamento considerando la grande velocità di esecuzione del codice.
Se un pc lento impiega 10 ms in + di uno veloce a renderizzare tutto lo spostamento nel pc lento sara x+=dx+10ms, è questo che intendi vero?
dimmi di si...o non ho capito nulla ancora :(
ahh ora ho capito...
ma lui non voleva cambiae la velocità, voleva un aiuto per aggiustare la funzione che valuta il pnto di collisione
:D esatto!!!
Ma se salta fuori che ho sbagliato proprio il metodo non posso che abbassare la testa e riscrivermi tutto...
Barbalbero
18-08-2006, 21:57
Io in mente ho già un metodo, cioè quella di vedere se c'è terreno non solo alla cordinata del proiettile, ma lungo una retta che ha la stessa inclinazione della traiettoria del proiettile e lunga abbastanza da essere più lunga dello spazio percorso in un dt di elaborazione.
Per l'altro problema, cioè quella della visualizzazzione non ci sono soluzioni?
Nei giochi come fanno...quando ci sono oggetti molto veloci sembra sempre che si muovo con una certa continuità...come si ottiene quell'effetto?
Io farei così...
Insieme alla sprite del proiettile, assocerei una shape invisibile, più lunga del proiettile. Le collisioni verranno poi calcolate in base alla shape invisibile.
:D esatto!!!
Ma se salta fuori che ho sbagliato proprio il metodo non posso che abbassare la testa e riscrivermi tutto...
esatto!!
Aiutati con il float e cmq usa l'fps a 60 ms come tutti i videogame che è il default.
ciao
non ho capito cosa centra l'fps a 60 con in problema in collision detect :mbe:
Si ma il proiettile è un proiettile deve andare veloce! :D
se lo sposto di meno poi devo elaborare più volte la scena per ottenere la stessa velocità!
Ora io faccio l'update della situazione ogni 40ms per avere circa 25 fps, non voglio scendere sotto i 40 ms per non sovraccaricare troppo la cpu, in sostanza il mio gameLoop è controllato da un timer.
Leggendo in giro però ho scoperto che molti non temporizzono il ciclo ma lasciano che la cpu sfrutti tuutta la sua potenza, forse è quella che intendevi tu vero okay? in quel caso si penso che devo ridurre gli spostamenti, ma il mio problema era rivolto a come avevo progettato ora il gioco. Essendo temporizzato a 40ms, la scena la elaboro ogni 40ms ma per far andare veloce un'oggetto mi serve spostarlo di molti pixel alla volta! E' per questo che ho il problema.
Ora forse la soluzione è effettivamente quella tua okay, sto sbagliando il metodo.
Se ho capito bene te dici di lasciare la cpu al 100% e quindi di regolare lo spostamento considerando la grande velocità di esecuzione del codice.
Se un pc lento impiega 10 ms in + di uno veloce a renderizzare tutto lo spostamento nel pc lento sara x+=dx+10ms, è questo che intendi vero?
dimmi di si...o non ho capito nulla ancora :(
Allora ricapitolando:
- la griglia 0 e 1 per determinare la collisione l'hai fatta
- il calcolo con il float per regolare la velocità te l'ho detto
ora rimane che sappi questa cosa:
Innanzitutto è sbagliato il metodo che usi per la velocità del proiettile aiutandoti con un timer... errata soluzione ed è questa che ti fà sballare il tutto.
quindi togli il timer e vedrai che il float come ti ho detto funzionerà a dovere.
Poi se vuoi usare l'fps cioè far passare tot immagini per secondo usa questo codice:
questa è una chicca che ti dò:
//Globals
float elapsedTime;
float currentTime;
int FrameRateDesiderato = 60;
//prototipo
BOOL Frame(int FrameRate);
//chiama l'fps
if(Frame(FrameRateDesiderato))
{
...codice del render eseguito se è TRUE
}
//routine dell'fps
BOOL Frame(int FrameRateDesiderato)
{
static float lastTime = 0.0f;
elapsedTime = 0.0;
// Prendi il tempo attuale in secondi (millisecondi * .001 = secondi)
currentTime = timeGetTime() * 0.001f;
// Sottrai il tempo attuale dal vecchio tempo rilevato
elapsedTime = currentTime - lastTime;
// Check if the time since we last checked is over (1 secondo / fps)
if( elapsedTime > (1.0f / FrameRateDesiderato) )
{
// Resetta il vecchio tempo
lastTime = currentTime;
// torna vero per animare i frames
return TRUE;
}
// torna falso nessuna animazione
return FALSE;
}
tienilo da conto e studialo e prova a variare FrameRateDesiderato con altri valori + bassi o + alti e guarda un pò cosa succede?
OT: (ringrazio cionci) se provassi il mio game mi farebbe molto piacere, in fase di betatesting:
http://www.twork.it/public/slidingedge/index.htm
c'è anche un forum dove linkarsi per qualsiasi cosa o problema.
La demo da provare è quella con il motore grafico in cui debbo ancora integrare il multiplayer.
Sotto c'è la demina con il multiplayer invece funzionante.
ciao
Grazie! in effetti il codice che mi hai suggerito l'ho trovato in varie salse per ottenere un frame rate costante! Ora ho capito finalmente, sbagliavo proprio tutto io mi ero convinto di tenere la cpu rilassata!
Ho solo un piccolo dubbio ancora, il mio gioco è in multithread in quanto è anche multiplayer, ho scritto dei servizi che sono dei thread, potrebbero essere in difficoltà facendo lavorare molto la cpu o ci sto dentro benissimo?
ps. ho provato a scaricare la demo ma mi dice che avete raggiunto il traffico massimo mensile per il vostro sito!
Un ultima cosa, solo la parte che renderizza la scena la devo inserire in un ciclo controllato dal framerate, o anche la parte che mi elbaora la fisica e tutto il resto?
Grazie! in effetti il codice che mi hai suggerito l'ho trovato in varie salse per ottenere un frame rate costante! Ora ho capito finalmente, sbagliavo proprio tutto io mi ero convinto di tenere la cpu rilassata!
Ho solo un piccolo dubbio ancora, il mio gioco è in multithread in quanto è anche multiplayer, ho scritto dei servizi che sono dei thread, potrebbero essere in difficoltà facendo lavorare molto la cpu o ci sto dentro benissimo?
ps. ho provato a scaricare la demo ma mi dice che avete raggiunto il traffico massimo mensile per il vostro sito!
- no nessun fastidio per il multi
- si ci stai ok
riprova per il download ricorda che devi installare i driver dell'AGENA come texture scarica quelle a bassa risoluzione per non avere problemi di fps
Un ultima cosa, solo la parte che renderizza la scena la devo inserire in un ciclo controllato dal framerate, o anche la parte che mi elbaora la fisica e tutto il resto?
se fai delle animazioni il codice va scritto nella routine. Per la fisica e tutto il resto può stare all'esterno.
Ti ringazio direi che ci siamo quasi e posso rimettermi al lavoro, un'altra cosina, volendo usare invece il metodo che lascia la cpu a lavorare al massimo utilizzando xò questa tecnica per gli spostamenti x+=dx*tempoTrascorso(è il TIME-BASED giusto?) ho capito che il frame rate è tanto più alto quanto è più veloce la macchina che esegue il codice, quello che resta costante è lo spostamento degli oggetti.
Siccome come ti ho già accennato il mio gioco è fatto per essere giocato in rete, ho bisogno che i client connessi al server siano in un certo modo sincronizzati giusto?
O con questo modo non c'è ne è bisogno?
Perdonami per la domanda banale ma è proprio il primo gioco che scrivo, non ho mai fatto nulla del genere!
Altra cosa, hai detto che l'elaborazione della fisica la posso anche togliere dalla routine, ma cosa intendi? intendi che la posso togliere dal conteggio del tempo?
Perchè io avevo intenzione di inserirla nello stesso ciclo, tipo qualcosa del genere:
while(gameLoop){
//elabora fisica(spostamenti ecc ecc) con il tempo trascorso
//renderizza
//prendo il tempo
}
Comunque quello più facile mi sembra quello a FPS costanti, solo che leggendo da altre parti sembra che sia considerato un "brutto" metodo...
Questo è quello che mi dice se provo a scaricare la demo:
Traffico temporaneamente bloccato
Il traffico verso questo sito web è stato temporaneamente bloccato perchè è stata superata la quota mensile assegnata all'account max2rbo pari a 10 GBytes, il sito sarà nuovamente accessibile a partire dal primo giorno del prossimo mese.
Nota: L'accesso al sito può essere ripristinato in qualunque momento accedendo al proprio pannello di controllo e aumentando la quota disponibile per l'account.
e poi mi rimanda ad altervista
Ti ringazio direi che ci siamo quasi e posso rimettermi al lavoro, un'altra cosina, volendo usare invece il metodo che lascia la cpu a lavorare al massimo utilizzando xò questa tecnica per gli spostamenti x+=dx*tempoTrascorso(è il TIME-BASED giusto?) ho capito che il frame rate è tanto più alto quanto è più veloce la macchina che esegue il codice, quello che resta costante è lo spostamento degli oggetti.
Siccome come ti ho già accennato il mio gioco è fatto per essere giocato in rete, ho bisogno che i client connessi al server siano in un certo modo sincronizzati giusto?
O con questo modo non c'è ne è bisogno?
Perdonami per la domanda banale ma è proprio il primo gioco che scrivo, non ho mai fatto nulla del genere!
Altra cosa, hai detto che l'elaborazione della fisica la posso anche togliere dalla routine, ma cosa intendi? intendi che la posso togliere dal conteggio del tempo?
Perchè io avevo intenzione di inserirla nello stesso ciclo, tipo qualcosa del genere:
while(gameLoop){
//elabora fisica(spostamenti ecc ecc) con il tempo trascorso
//renderizza
//prendo il tempo
}
Comunque quello più facile mi sembra quello a FPS costanti, solo che leggendo da altre parti sembra che sia considerato un "brutto" metodo...
Bravo MEMon...
Allora:
Del sito del mio collega... si me ne sono accorto adesso.
Ora è il momento delle ferie quando rientra e lo sento su msn lo avviso di questo problema... Se hai msn potrei passarti il game io ma non facciamo le cose di corsa aspettiamo che si rispristini il sito del mio collega senza andare di corsa.
E' invece interessante quello che hai fatto. C'è una cosa che mi interessa sapere:
Innanzitutto hai per caso msn in tal caso ci possiamo contattare su msn noi del team usiamo msn per dialogare e passarci i files.
Rispondo al tuo quesito ma sono curioso e interessato a come hai sviluppato il gameplay.
Ti spiego... forse sarò un pò prolisso:
Le mie domande:
come hai sviluppato il multiplayer?
1. Con il winsock in TCP?
2. Quale tecnica hai usato il modo asincrono non-bloccante tipo:
WSAAsyncSelect ((SOCKET)gSocketListen, hWnd, SERVER_EVENT,
(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE )); ??
3. Hai provato l'invio dei dati in modo continuo dei clients al server e smistamento dei dati da parte del server ai clients?? Se si come è la latenza del ping in ms??
4. puoi vedere come al server, magari aiutandoti con una listbox, arrivano i dati dei client??
Questo per me è importante saperlo...poi ti spiego meglio!!
Risposte al tuo quesito:
Lo spostamento del proiettile lo puoi fare con il tempo tipo:
// Velocità di movimento da un punto ad un altro compresa in un secondo
TimeWay += fElapsedTime;
position = Vel * TimeWay);
TimeWay=0;
//movimento del proiettile
proiettilePos=position;
per quanto riguarda il gameplay dove tu dici "i client devono essere sincronizzati" è errato pensare in questo modo.
Il server deve essere il meno possibile intasato il server deve essere strutturato così per un buon gameplay:
SERVER:
1. riceve i dati bytes dai client e li reinvia a tutti i client
2. Non gestisce la grafica la fisica il sound le collisioni tutto questo è gestito dal client
3. Il client invia le posizioni del proiettile e del giocatore al server e basta
4. Il client riceve i dati degli altri clients, (mandati dal server), e gestisce la fisica le collisioni ecc ecc.
solo i proiettili sul tuo pc si muovono con il tempo come sopra mentre la posizione dei proiettili degli altri client si muovo tramite la posizione inviata dai client.
speri di essermi spiegato.
Ancora per farti capire meglio: può essere (anzi succede spesso) che in un dato momento i pacchetti inviati di alcuni client si perdano nella rete e non giungono a destinazione per il tempo di timeout scaduto.
Quindi la posizione del proiettile sparato da un client sul tuo pc ha posizione 10,13 e al prossimo rendere rimane a 10,13 perchè il pacchetto è perso.
Poi però arriva dal client il pacchetto con naturalmente la nuova posizione sul tuo pc ora l'aggiorni stai tranquillo il tutto è talmente veloce che non si nota nulla alle volte si.
Le tecniche sono molte un'altro modo di operare, per non affaticare troppo il pc e il server prendere la posizione del proiettile ma anche la velocità e per approssimazione calcolare sul proprio pc una simulazione e far muovere il proiettile senza aspettare le posizione quindi per approssimazione lo fai andare.
In tutti e 2 i modi come sul tuo pc c'è collisione esegui l'esplosione.
Sull'altro client avviene la stessa cosa ma in piccolissimi tempi diversi.
mentre nel modo dello scambio continuo della posizione esso è sempre in tempo reale. Ovvero la collisione si ha negli stessi tempi su tutti i pc.
Ecco il mio quesito sul gameplay (ho copiato e incollato quì questo mio messaggio postato su un'altro forum)
Ho implementato, e scelto per fare un multiplayer con il winsock, il metodo asincrono usando WSAAsyncSelect ((SOCKET)gSocketListen, hWnd, SERVER_EVENT, (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE ));
Il server e il client sono strutturati senza usare thread anche perchè il metodo asincrono permette di comunicare appunto in modo non-bloccante sulle sock.
La struttura è avere un server che smista i messaggi a tutti i client. Ogni client invia un messaggio e il server smista il messaggio a tutti volendo meno a chi a spedito il messaggio.
In pratica è una chat che funziona sia in modalità chat ovvero il client invia il proprio nome e id al server e il server smista a tutti i clients il messaggio meno a chi l'ha spedito.
Oppure posso usare, checcando "modo continuo", che i clients in modo automatico inviano il proprio nome e id in modo continuo al server il quale smista a tutti i messaggi arrivati.
Tutto funziona alla grande in particolar modo in modalità chat ovvero modo non continuo cliccando appunto sul pulsante "Invia messaggio".
Il problema riscontrato è il "modo continuo" dove appunto si comporta come un multiplayer per game dove i clients inviano i propri dati, in questo caso, nome e id reinviati dal server a tutti.
La domanda per chi volesse rispondere:
A me interessa il modo multiplayer "invio dati in modo continuo" proprio per sviluppare un multiplayer con il winsock sotto win.
PREMESSA:
Ho creato dopo 3 anni di lavoro con directplay un multiplayer dove directplay ho riscontrato che è molto ma molto performante questo strato di DP è fatto molto bene e scritto con funzioni a basso livello davvero ben fatte secondo me.
In pratica questo mio motore posso usarlo in qualunque game.
L'ho testato con amici sul web, integrando il multiplayer nel motore grafico del nostro gioco di moto, e devo dire che si gioca che è una meraviglia. Le prestazioni migliori si hanno giocando con modem a 56k dove ho riscontrato un tempo di latenza di ping + basso a differenza delle linee veloci come l'adsl.
Cmq ho fatto un gran bel lavoro con Directplay.
Parlando con un amico tempo fà mi disse che non era daccordo in quanto directplay non è + sviluppata da microsoft in pratica nei prossimi sistemi non sarà + integrata quindi in futuro il programmatore dovrà sviluppare o con il winsock che è uno strato di comunicazione di default o altri metodi integrati per le nuove tecnologie di comunicazione.
Ebbene io non sono daccordo in quanto secondo me è si che microsoft non aggiorna + directplay ma saranno sempre integrate sui sistemi come per esempio è successo a directinput dove sono sempre integrate ma ferme alla versione 8.1 e non per questo non + utilizzate.
Finita questa considerazione torniamo al problema:
Ora i 2 aspetti del multiplayer confronto tra Directplay e il winsock che ho fatto:
Con directplay i clients inviano al server il messaggio stampato nella listbox i dati in arrivo sul server sono perfetti anche aumentando i clients l'aspetto della listbox è il seguente:
//dati in arrivo al server directplay dei clients
okay 0
ciao 1
amico 2
okay 0
ciao 1
amico 2
okay 0
ciao 1
amico 2
Ecco come vedi sopra se si logga un'altro client avrei:
okay 0
ciao 1
amico 2
mio 3
okay 0
ciao 1
amico 2
mio 3
okay 0
ciao 1
amico 2
mio 3
Da come puoi vedere il mio game play è perfetto sia come fluidità sia come latenza di ping molto performante l'abbiamo provato in 3 e ti devo dire che ci siamo divertiti alla grande....!!! Il Gameplay è ECCELLENTE. Ne sono molto contento.
Volendo migrare il tutto con il winsock ho buttato giù il progetto:
Ora provando il modo continuo con il winsock, i dati in arrivo sul server winsock è il seguente:
//dati in arrivo al server winsock
okay 0
okay 0
okay 0
okay 0
amico 2
okay 0
okay 0
okay 0
okay 0
okay 0
ciao 1
ciao 1
ciao 1
ecc ecc.
come puoi notare con il winsock strutturato nel modo che ho fatto asincrono come detto sopra i dati in arrivo al server non sono fluidi ed omogenei come con directplay i tempi di latenza di ping sono molto + alti.
Spero di aver chiarito il problema riscontrato.
Ho creato anche un server sempre con il winsock che lavora con CRITICAL_SECTION e thread e il risultato è analogo al test sopra con il winsock mentre con Directplay la fluidità e la velocità dei dati è imbarazzante.
Ecco perchè sono interessato a sapere come hai sviluppato il tuo gameplay.
Chissà che non riesca a risolvere il mio problema con il winsock.
ciao
Ciao, allora ti spiego come ho realizzato il netcode, sperando di essere il più chiaro possibile...non è niente di che comunque!
L'ho fatto tutto in UDP perchè dopo varie prove ho potuto verificare che in TCP le cose non erano come le volevo io.
Ogni giocatore al momento di doversi connettere fa una query al server, in pratica gli invia un oggetto che definisce lo stato del client, team e razza, nome, id,slot e anche un messaggio di testo.
Il server risponde al client rimandando indietro l'oggetto ma correttamente modificato.
Dopodichè il server aggiunge uno slot all'array di dati che spiegherò ora.
Ogni giocatore spedisce un oggetto al server che contiene informazioni sulla propria posizione, l'arma che impugna,se ha sparato o meno, e lo slot(serve per dire al server in quale slot dell'array inserire il dato che viene ricevuto).
Questo non è bloccante ovviamente essendo UDP.
Il server rimane sempre in ascolto appena riceve uno di questi oggetti lo inserisce in un array, questo array viene inviato a tutti i client con periodicità, anche questa è stata una scelta che ho effettuato dopo alcune prove, inizialmente usavo far sapedire dal server l'oggetto ricevuto a tutti i client senza impacchettarlo in un array, ma considerando che un server ha più tempo libero di un client nel smistare i dati ho pensato fosse meglio l'altra soluzione.
I client rimangono sempre in ascolto dell'array di dati, ogni volta che devono renderizzare la scena utilizzano questo array, in pratica per un client il numero di giocatori connessi è dato da quell'array! Non devono fare altro che utilizzare l'array già com'è senza preoccuparsi di sapere a chi appartiene ogni dato, ci ha già pensato il server ad organizzare tutto.
Poi ho scritto anche dei servizi che costruiscono un canale per le informazioni, lo uso sia per spedire messaggi di testo, sia per dire ad un client se si è connesso un altro client o se si è disconnesso.
Per i proiettili non spedisco la posizione di ogni singolo proiettile, diventerebbe troppo grosso il dato da spedire, in quanto ogni giocatore può sparare veramente troppi proiettili alla volta, pensa ad una machine gun :D.
Invio invece solo se ha sparato e con quale arma, in questo modo ogni client sa se qualche altro client ha sparato e con che arma, inserendo oppurtanemente il proiettile nell'ambiente.
L'ambiente è un qualcosa che ha della fisica e la applica a tutti gli oggetti che ne fanno parte.
In questo modo ogni client elabora i proiettili presente nell'ambiente, che in teoria dovrebbero essere gli stessi per tutti i client, quindi si avrà che ogni client vede la stessa scena, questo in teoria non l'ho ancora effettivamente provato.
L'importante è che lo spostamento degli oggetti nell'ambiente avviene alla stessa velocità su tutti i client!Penso che con i due metodi detti prima frame e time based si possa fare agevolmente.
Comunque io ho scritto prima il net code del resto, infatti per quanto riguarda l'aspetta grafico sono ancora indietro!
Ho ovviamente però provato il netcode scrivendo un programma di prova, che non era altro che una chat dove però ogni client connesso poteva anche spostare una pallina.
Ti devo dire che a me è sembrato molto fluido e veloce, pacchetti persi non ne abbiamo notati(anche perchè mi sono scritto un mio protocollo di comunicazione server client con domande e risposte, ma vale solo per la chat in quanto perdere un dato relativo alla posizione non è un danno come perdere un messaggio inviato).
Per il ping sinceramente non ti saprei dire, ho scritto tutto ùin java e non so per quale strano motivo ma java non può fare il ping, bisogna scriverselo da soli(almeno credo).
Mi sono quindi scritto un servizio che non fa altro che spedire una serie di paccheti molto piccoli, e ne aspetta il ritorno calcolando il tempo che ci mettono a ritornare, in questo modo so il tempo e il packet loss.
Utilizzando questo servizio il ping era tra due ADSL sui 100ms, ma comunque nella prova che abbiamo fatto gli spostamenti delle palliena era comunque molto fluido!
humm....
bhè ottimo.
dunque hai scelto UDP... sò che TCP è + affidabile ecco perchè ho scelto TCP. Con UDP si perdono purtroppo i pacchetti.
In quanto se perdi pacchetti cosa fai li perdi e basta oppure controlli che sono arrivati a destinazione completamente?? per poi inviare il prossimo pacchetto?? controllando ack di ritorno.
Ti dico questo perchè se è si il lavoro è molto dispendioso.
Visto che parlavi di c++ pensavo che il netcode era in c++ mentre mi dici che l'hai fatto in java?
i 100 ms è ottimo infatti la latenza del ping per le linee veloci (ADSL) è appunto intorno ai 100 ms. Mentre intorno ai 50/60 ms per i modem a 56k.
Le linee veloci non sono adatte per giocare in rete. cmq 100/150 ms può andar cmq bene.
Ottimo invece il discorso del'array che si definisce sul server e smista a tutti i clients.
in pratica sul server riempi un array (id(i), arma(i), spara(i), mess(i)) e lo smisti a tutti i clients.
Edit:
ma hai detto che inserisci nell'ambiente il proiettile sparato sui client ma deve avere una posizione di partenza questo proiettile cioè da dove è stato sparato cioè a che posizione iniziale è sparato quindi dovresti passare un true che il client n. 1 ha sparato e la posizione del proiettile se no come fai ha dare una posizione al proiettile sul client ricevente?
Non ho mai parlato del linguaggio :D
Ho scelto UDP perchè è molto più performante, avere una connessione diretta server-client rallenta le cose a mio avviso.
Si spiega anche il motivo del perchè i giochi multiplayer più conosciuto sono in UDP(vedi giochi tipo Quake).
Essendo in real time il gioco, perdere un pacchetto non è un danno molto grande, in quanto il pacchetto viene subito sostituito da quello dopo, reinviare un pacchetto perso è inutile, in quanto ogni pacchetto quando arriva è ormai obsoleto...
Il controllo del ritorno lo faccio solo per dati importanti, come lo stato dei client e i messaggi di testo, se perdo un messaggio della chat quello è un danno, e infatti lo rispedisco finchè il client non risponde che l'ha ricevuto!
L'oggetto dato che invia ogni client al server è diciamo fatto così:
id- non ancora utilizzato ma penso di utilizzarlo in fututo
slot- indica a quale indice dell'array il dato deve essere salvato
posizione- pos del giocatore
arma- arma impugnata
sparo- boolean true se ha sparato
Quando il server riceve uno di questi oggetti ne legge lo slot e lo salva nell'array così array[slot]=oggetto ricevuto;
Poi ogni 30 ms invia questo array a tutti i client.
Comunque ormai internet ha raggiunto uno stato di affidabilità abbastanza alto, perdere un pacchetto è cosa rara, certo succede ma è trascurabile per alcune applicazioni.
Si vedrà la cosidetta "laggata" ma è sopportabile.
EDIT: certo il proiettile parte dalla posizione del giocatore, più qualche piccola modifica per far si che parta dall'arma, che si trova ad un certo dx e dy dalla posizione del giocatore!
Non ho mai parlato del linguaggio :D
Ho scelto UDP perchè è molto più performante, avere una connessione diretta server-client rallenta le cose a mio avviso.
Si spiega anche il motivo del perchè i giochi multiplayer più conosciuto sono in UDP(vedi giochi tipo Quake).
Essendo in real time il gioco, perdere un pacchetto non è un danno molto grande, in quanto il pacchetto viene subito sostituito da quello dopo, reinviare un pacchetto perso è inutile, in quanto ogni pacchetto quando arriva è ormai obsoleto...
Il controllo del ritorno lo faccio solo per dati importanti, come lo stato dei client e i messaggi di testo, se perdo un messaggio della chat quello è un danno, e infatti lo rispedisco finchè il client non risponde che l'ha ricevuto!
L'oggetto dato che invia ogni client al server è diciamo fatto così:
id- non ancora utilizzato ma penso di utilizzarlo in fututo
slot- indica a quale indice dell'array il dato deve essere salvato
posizione- pos del giocatore
arma- arma impugnata
sparo- boolean true se ha sparato
Quando il server riceve uno di questi oggetti ne legge lo slot e lo salva nell'array così array[slot]=oggetto ricevuto;
Poi ogni 30 ms invia questo array a tutti i client.
Comunque ormai internet ha raggiunto uno stato di affidabilità abbastanza alto, perdere un pacchetto è cosa rara, certo succede ma è trascurabile per alcune applicazioni.
Si vedrà la cosidetta "laggata" ma è sopportabile.
EDIT: certo il proiettile parte dalla posizione del giocatore, più qualche piccola modifica per far si che parta dall'arma, che si trova ad un certo dx e dy dalla posizione del giocatore!
bhè... che dire ottima discussione!
Il bello del programmare è appunto ottenere la stessa cosa (raggiungere lo stesso obbiettivo) in modi diversi!
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.