Autore Topic: Algoritmo gestione movimento  (Letto 1654 volte)

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Algoritmo gestione movimento
« il: 12 Dicembre 2011, 18:54:04 »
Sto creando una serie di librerie per semplificarmi la vita quando rimetterò mano ad AMC, ma avrei intenzione di implementare librerie generiche che mi coprano una serie di situazioni abbastanza vaste cosi che possa riutilizzarle anche per altri progetti.

Attualmente stavo pensando ad una libreria per gestire il movimento degli oggetti (2d), ma qui è necessario un piccolo aiutimo da parte dei più esperti, va bene anche un link dove vengano spiegati chiaramente come gestire correttamente questo problema.

Ho buttato giù alcune cose che vorrei gestire per l'oggetto che deve muoversi, in particolare:
- Spostamento verso un punto
- Spostamento verso un'altro oggetto (che poi è come il primo solo che potrebbe cambiare posizione ad ogni ciclo)
- Spostamento seguendo un path (questo è semplice perchè devo seguire una tabella di coordinate o check-point, in quest'ultimo caso non è altro che la gestione della prima situazione)

Quello in cui ho maggiori difficoltà è la gestione della velocità, non ho idea da dove cominciare.
La più semplice ovviamente è la velocità costante, ma io vorrei gestire anche:

- Accelerazione in avvicinamento (attrazione)
- Decelerazione in avvicinamento fino a fermarsi
- Decelerazione in avvicinamento fino a deviare il mio oggetto (repulsione)

In entrambi i casi per fare le cose per mene devo mettere di mezzo la massa dell'oggetto da spostare e quello dell'oggetto di destinazione ma qua le mie conoscenze si fermano.

Mi date qualche dritta? Qualche link per approfondire o qualche consiglio su come avvicinarmi al risultato senza implementare algortmi di calcolo troppo pesanti, anche perchè non devo simulare la legge gravitazionale ma replicare qualcosa di simile.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re: Algoritmo gestione movimento
« Risposta #1 il: 12 Dicembre 2011, 21:49:59 »
Potresti strutturare la cosa in questo modo:

- Definisci delle funzioni che determinano la posizione P(k, x0, y0, x1, y1) partendo da (x0, y0) fino a (x1, y1) in funzione di un parametro generico k compreso nell'intervallo chiuso [0.0, 1.0]
- Definisci una funzione di interpolazione temporale F(t, t0, t1) che prende in input un parametro t in [t0, t1], e da in output un parametro k in [0.0, 1.0]

le animazioni 2D più semplici si possono pensare come la composizione (x, y) = P( F(t, t0, t1), x0, y0, x1, y1), dove:

(x,y) sono le coordinate correnti dell'oggetto
t è il tempo corrente in secondi
t0 è il tempo in cui inizierà l'animazione (costante)
t1 è il tempo in cui finirà l'animazione (costante)
(x0,y0) è la posizione di partenza (costante)
(x1,y1) è la posizione di arrivo (costante)

Quelle che ho indicato come costanti potrebbero in realtà variare ad ogni passo, ma complicheresti solamente l'utilizzo della libreria senza un reale vantaggio (potrebbe essere utile nei giochi, ma non in una semplice GUI).

Ecco un esempio concreto:

Voglio far muovere un oggetto in linea retta da A = (3, 5) a B = (12, -4), a velocità costante, in un tempo di 3 secondi con un'attesa iniziale di 5 secondi.
La funzione di interpolazione temporale dovrà avere un primo tratto orizzontale, lungo 5 secondi, poi un segmento di retta lungo 3 secondi in cui sale da 0.0 fino a 1.0 e poi un altro tratto orizzontale infinitamente lungo.
Quindi:
k = F(t, t0, t1) =
if (t < t0) return 0.0;
else if (t>t1) return 1.0;
else return (t - t0) / (t1 - t0);

La funzione geometrica P invece sarà invece una semplice retta parametrica in [0.0, 1.0], del tipo:
(x,y) = P( k, x0, x1, y0, y1) =
return (x = (x0 * k) + x1 * (1.0 - k) ; y = (y0 * k) + y1 * (1.0 - k)

Se vuoi ottenere un moto che parte lento e poi accelera, devi semplicemente sostituire nella F() la formula dell'ultimo ramo, inserendo una parabola parametrica invece di una retta, cioè basta banalmente elevare al quadrato quella piccola formuletta.
Se vuoi farla decelerare basta scambiare di posto t0 con t1, creando quindi una parabola a testa in giù.
Se vuoi farla rimbalzare potresti usare il valore assoluto di una funzione seno che moltiplica a sua volta un'esponenziale negativa, e così via.

Analogamente puoi sostituire la funzione P con l'equazione parametrica di un arco di cerchio, un'ellisse, una parabola, una spirale, o quello che vuoi (per spirali e archi ti consiglio di convertire le coordinate in forma polare).

Se crei delle classi che derivano da un paio di classi astratte chiamate Traiettoria e Interpolatore, puoi implementare questi algoritmi ed esporre solo i parametri necessari nei costruttori (se vuoi farli costanti) oppure predisporre dei metodi per cambiarli al volo durante l'animazione.

Ovviamente, essendo basate sul tempo reale, se chiami la funzione 100 volte in un secondo avrai 100 piccoli incrementi, mentre se la chiami 1 volta in 3 secondi (l'esempio durava 3 secondi) ti farà un unico grande balzo, mantenendo comunque la velocità dell'animazione del tutto indipendente dalla quantità di chiamate di update, e quindi indipendente dalla velocità della macchina. Chiaramente dovrai fornire a queste funzioni un parametro temporale letto dal clock di sistema per funzionare correttamente.

Se hai difficoltà a scrivere le funzioni matematiche necessarie, puoi sperimentare con questo sito http://www.wolframalpha.com/ oppure procurarti un buon testo di geometria analitica :-)

Buon divertimento  :ugeek:
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: Algoritmo gestione movimento
« Risposta #2 il: 12 Dicembre 2011, 22:05:23 »
Muoaaaaaa! Grazie! Mi hai dato un sacco di materiale su cui lavorare/riflettere!
Cmq si, tutto a classi e metodi abbestia!

 :D  :D  :D
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: Algoritmo gestione movimento
« Risposta #3 il: 26 Gennaio 2012, 18:07:30 »
Tutto a posto! Adesso ho tutto ciò che mi occorre, ho implementato una classe chiamata <Mover> che posso abbinare a un brush, un  layer o ad uno sprite.

Posso aggiungere un task di spostamento con la funzione:
Codice: [Seleziona]
AFX.Mover:Add(ObjType, ObjName, StartingPos, EndingPos, MoveType, Timing, OnEnd, OnUpdate, Userdata, Name)

ObjType -> #BRUSH, #LAYER, #SPRITE
ObjName -> nome oggetto collegato oppure il suo id restituito alla creazione
StartingPos -> { x=n, y=n }, se non specificato prende la posizione corrente dell'oggetto
EndingPos -> { x=n, y=n }
MoveType -> #MOVETYPE_LINEAR, #MOVETYPE_ACCELERATION, #MOVETYPE_DECELERATION
Timing -> Durata dello spostamento espresso in millisecondi
OnEnd -> Eventuale funzione da eseguire quando lo spostamento termina
OnUpdate -> Eventuale funzione da eseguire dopo ogni aggiornamento
UserData -> Dati aggiuntivi da passare alle funzioni OnEnd e OnUpdate assieme all'oggetto stesso
Name -> Nome opzionale da dare a questo nuovo task

Questi sono gli altri metodi:
MoverObj:Update() -> Richiamata automaticamente ogni tot millisecondi (dipende da come si inizializza la libreria), è prevista anche una gestione manuale
MoverObj:Cancel() -> Interrompe il task
MoverObj:Finish() -> Termina il task portando l'oggetto collegato alla posizione finale ed esegue l'eventuale funzione <OnEnd>
MoverObj:Pause() -> Mette in pausa lo spostamento
MoverObj:Resume() -> Ripristina il task da una pausa
MoverObj:Remove() -> Elimina il task previa chiamata del metodo :Cancel()

L'eliminazione del task avviene automaticamente una colta raggiunta la posizione finale
YEAH! Grazie Antonio per gli hints!
 :D
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Tags: