The Xna-Way: Tutorial 6: Orientare oggetto nella direzione in cui si muove e telecamera che lo insegue

Questa volta il compito che mi sono proposto è stato un po' più difficile:
avendo creato un decente MeteorManager questa volta volevo muovermi attraverso questo fitto campo di meteoriti con una navicella spaziale.

Sono partito col pensare a ciò:
- per ora non mi interessa calcolare le collisioni con i meteoriti
- la telecamera sarà in 3° persona, quindi ci troveremo alle spalle della nostra astronave (altrimenti avevamo già la telecamera in prima persona per muoverci)
- la telecamera dovrà seguire il nostro vascello spaziale
- dovremo far muovere nello spazio il nostro mezzo di trasporto

tutto questo ci porta a dover modificare la nostra telecamera per implementare "l'inseguimento" della nostra astronave. Avremo quella che chiamo Follow Camera.
Anche per il nostro vascello avremo il nostro bel da fare: non dovremmo solo farlo muovere e ruotare nel mondo 3D, ma dovremo farlo muovere nella direzione in cui "guarda", quindi movimenti e rotazioni dovranno essere fatti in modo particolare lavorando sulle direzioni, cosa un po' complicata e astrusa ma fattibile.

Per prima cosa è meglio fare la modifica alla classe Camera in modo da implementare l'inseguimento di un determinato bersaglio. In questo modo quando poi andremo a far muovere il nostro oggetto nello spazio la telecamera gli starà dietro e noi non avremo problemi ad osservarlo ^_^

Preso il progetto dell'ultimo post, andiamo nella classe Camesa.cs e sotto il metodo UpdateFreeCamera() andiamo a mettere il seguente metodo:

private void updateFollowCamera(GameTime gameTime)
{
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
//creo la matrice temporanea
Matrix tmp = Matrix.Identity;
//imposto la direzione di osservazione, la direzione dell'alto e la direzione della destra
tmp.Forward = direction;
tmp.Up = up;
tmp.Right = Vector3.Cross(up, direction); //questa è calcolata come prodotto tra due vettori

Vector3 t;
//trasformo la distanza (offset) dal punto di osservazione con la matrice calcolata
Vector3.Transform(ref offset, ref tmp, out t);

Vector3 positionTmp;
//calcolo la posizione che vogliamo far avere alla nostra telecamera sommando al punto che siamo osservando
//la posizione trasformata lungo la matrice
Vector3.Add(ref target, ref t, out positionTmp);
//aggiorno la posizione finale
position = positionTmp;
}


Per non avere errori dovremo aggiungere le seguenti variabili di classe:

//variabili per l'inseguimento del target
protected Vector3 offset = Vector3.Zero;
protected Vector3 direction = Vector3.Forward


Cosa fa il metodo?
Il metodo crea una matrice identità e ne imposta i valori per le direzioni che rappresentano il davanti, l'alto e la destra.
Direction e up da dove vengono? Sono dati e assegnati tramite l'oggetto che vogliamo inseguire: cioè direction rappresenta la direzione in cui si sta muoveno il nostro oggetto, mentre up è la direzione che il nostro bersaglio considera come l'alto. In questo modo potremmo mantenere costati le rotazioni!
La destra viene calcolata come prodotto tra i due vettori.

Dopo trasformo l'offest usando la matrice, e sommo questo offest alla posizione del punto osservato e assegno il risultato alla posizione.

Quello che manca da fare ora è la classe per gestire la nostra navicella spaziale.
Ecco il file Ship.cs, comunque presente nell'archivio allegato:
Ship.cs Show/Hide


Il file va inserito nel progetto Meteor e non nella libreria, dato che, come il MeteorManager, questo oggetto è specifico per questa applicazione.

Il pezzo saliente è il metodo Update, il resto è roba già vista!
Cosa fa questo benedetto metodo?
Prima di tutto riazzera il valore della rotazione per yaw e pitch, e anche val.
Val indica se la barra spaziatrice è premuta o meno, e quindi se dobbiamo muoverci o no.
Con la pressione delle frecce direzionali imposto i valori per le rotazioni, e con R riporto il tutto allo stato iniziale.

Con

if (up.Y < 0)
yaw = -yaw;

faccio in modo che se mi trovo a testa in giù e premo verso destra, continuo a girare ancora verso destra non verso sinitra.

Dopo di chè calcolola matrice di rotazione (nota: l'angolo per pitch è calcolato passando l'asse di rotazione), e uso tale matrice per trasformare la direzione e l'up.

Ho poi il calcolo della forza applicata all'oggeto.
Sono formule fisiche. Forza = massa * accellerazione.
So che la formula per calcolare la velocità è sbagliata (anche se quella giusta è riportata come commentata). Ma ora come ora non mi interessa la correttezza delle fisica.

Alla fine poi ho la creazione della world matrix per la nostra navicella, fatta in modo molto simile a come abbiamo costruito quella per la telecamera.

Cosa manca da fare per far funzionare il tutto?
Aggiungere il file per il modello 3D e la texture al progetto, creare la nostra astronave, aggiungerla ai components e disegnarla.
Poi dobbiamo modificare leggermente le impostazioni della telecamera.

Cominciamo: nel costruttore di Game1.cs modifichiamo il codice per la telecamera come segue

myCamera = new Camera(this);
myCamera.FarPlane = 100000;
myCamera.Offset = new Vector3(0, 100, 500);
myCamera.Mode = CameraMode.Follow;
Components.Add(myCamera);

Impostiamo la distanza dal punto di osservazione e cambiamo il tipo di telecamera.

Nel metodo LoadContent() aggiungiamo questo:

myShip = new Ship(this, @"Models\p2_wedge", @"Textures\wedge_p2_diff_v1", defaultEffect);
myShip.Scale = 0.1f;
Components.Add(myShip);

Dove myShip è l'oggetto per la nostra astronave, che dobbiamo aver definito nella classe. Lo scalo ad un fattore 0.1 perchè altrimenti sarebbe troppo grande.

Nel metodo Draw dopo il render per il meteorManager aggiungiamo questo:
myShip.Draw(gameTime);

E nel metodo Update questo:

if (myCamera.Mode == CameraMode.Follow)
{
myCamera.Target = myShip.Position;
myCamera.Up = myShip.Up;
myCamera.Direction = myShip.Direction;
}


In modo che se la telecamera è di tipo follow, si aggiorna il suo target alla posizione della nostra navicella (ma potrebbe essere benissimo qualsiasi cosa!), e settiamo up e direction con i valori provenienti dal nostro oggetto myShip.

Dovrebbe essere tutto! :D
Se qualcosa non va c'è sempre il file allegato!
E se trovate qualche errore fatemelo notare così correggo ^__^

XNA-tut6.rar

Argomenti trattati:
> muovere un oggetto lungo la direzione che sta osservando
> telecamera che insegue il nostro oggetto

Alla prossima!

0 commenti:

Donazioni

My Menu'