3rd person, telecamere, collisioni & eventi da tastiera (4)

Attenzione: il tutorial pubblicato sul sito è stato suddiviso in 5 parti. Linee di codice troppo lunghe potrebbero essere tagliate dal browser. Per la completezza e l'affidabilità del codice fate riferimento al tutorial completo in pdf.

scarica il seguente tutorial in formato pdf (161 kb)

scarica il codice completo in formato testo (.cpp, 10.6 Kb)

 

MUOVITIPA, OVVERO: DATTI UNA MOSSA SIDNEY!

Vediamo il sorgente completo della procedura MuoviTipa(), che si incarica di far effettuare i vari movimenti al nostro player e di gestire tutto quanto abbiamo detto precedentemente (vedi la parte di spiegazione sulla rilevazione dei tasti), nonche di effettuare il salto:

bool MuoviTipa() {

bool IsFalling;

IsFalling=Player->TheCollisionAnimator->isFalling();

if (Player->Jump>0)

{

 

irr::core::vector3df v = Player->TheNode->getPosition();

v.Y += Player->Jump*0.3f;

Player->TheNode->setPosition(v);

Player->Jump–;

/* wchar_t tmp[1024];

swprintf(tmp, 1024, L"Jump value: [%d]", Jump);

device->setWindowCaption(tmp);

*/

}

if ((tasti[irr::KEY_SPACE]) && (!IsFalling) && (Player->Jump==0))

{

if (Player->WhatIDo!=4) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=4;

Player->Jump=40;

return true;

}

 

if(tasti[irr::KEY_KEY_W])

{

if (Player->WhatIDo!=2) Player->TheNode->setMD2Animation("run");

Player->WhatIDo=2;

irr::core::vector3df facing( sin( (Player->TheNode->getRotation().Y+90) * PI/180.0f ), 0, cos( (Player->TheNode->getRotation().Y+90) * PI/180.0f ));

facing.normalize();

irr::core::vector3df newPos = (facing*2.3f) + Player->TheNode->getPosition();

Player->TheNode->setPosition( newPos );

return true;

}

 

if(tasti[irr::KEY_KEY_S])

{

if (Player->WhatIDo!=2) Player->TheNode->setMD2Animation("run");

Player->WhatIDo=2;

irr::core::vector3df facing( sin( (Player->TheNode->getRotation().Y+90) * PI/180.0f ), 0, cos( (Player->TheNode->getRotation().Y+90) * PI/180.0f ));

facing.normalize();

irr::core::vector3df newPos = Player->TheNode->getPosition()-(facing*2.3f);

Player->TheNode->setPosition( newPos );

return true;

}

 

if(tasti[irr::KEY_KEY_A])

{

if (Player->WhatIDo!=1) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=1;

Player->TheNode->setRotation( irr::core::vector3df(0, Player->TheNode->getRotation().Y - 3.8f, 0) );

return true;

}

 

if(tasti[irr::KEY_KEY_D])

{

if (Player->WhatIDo!=1) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=1;

Player->TheNode->setRotation( irr::core::vector3df(0, Player->TheNode->getRotation().Y + 3.8f, 0) );

return true;

}

 

// Se non fa nulla, fa Stand"

 

if ((Player->WhatIDo!=3) && (!IsFalling) && (Player->Jump==0))

{

Player->TheNode->setFrameLoop(1, 319);

Player->WhatIDo=3;

}

return false;

}

Faccio notare che l’ordine delle varie “IF” è importante… al fine della spiegazione, però, non andrò per ordine ma bensì per logica. D’altronde, la scelta dell’ordine è frutto di prove per rendere il controllo migliore… tutto è migliorabile comunque!!!

Viene inizialmente testato se il nostro personaggio sta… beh… cadendo! Perché? Perché è difficile saltare poggiando i piedi nel vuoto ( a meno che non si abbiano dei super poteri…).

Per tanto la funzione isFalling() del CollisionAnimator del nostro Player ci dirà se siamo… “tipi con i piedi per terra”!!!

bool IsFalling;

IsFalling=Player->TheCollisionAnimator->isFalling();

Più avanti, testiamo se la barra spaziatrice è stata premuta, se NON stiamo cadendo e se non stiamo già saltando:

if ((tasti[irr::KEY_SPACE]) && (!IsFalling) && (Player->Jump==0))

{

if (Player->WhatIDo!=4) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=4;

Player->Jump=40;

return true;

}

Da notare la variabile “WhatIDo” che comunica al programma cosa si sta facendo. È una comodità mia… si potrebbe ricavare l’animazione in corso direttamente dal nodo in questione, ma sono pigro!!!

Viene controllata in qualsiasi “cambio di animazione”. In questo modo, se non si preme ad esempio il tasto “avanti” (vedi in seguito) si attiva l’animazione “run”. Ma se si sta già correndo, è inutile riprendere l’animazione da capo…anche perché sennò non si avanzerebbe mai con i vari frame! Provate a toglier il controllo per vedere cosa succede.

Torniamo al nostro salto.

Principalmente,oltre a settare l’animazione, questa parte non fa altro che “caricare” l’energia del salto (nel nostro caso di 40 “unità”).

Il salto vero e proprio (a livello di spostamento) è effettuato qui:

if (Player->Jump>0)

{

 

irr::core::vector3df v = Player->TheNode->getPosition();

v.Y += Player->Jump*0.3f;

Player->TheNode->setPosition(v);

Player->Jump–;

/* wchar_t tmp[1024];

swprintf(tmp, 1024, L"Jump value: [%d]", Jump);

device->setWindowCaption(tmp);

*/

}

Se il mio salto ha “energia”, faccio in pratica le seguenti azioni:

  • memorizzo il vettore corrispondente alla posizione odierna del personaggio

  • sommo all’asse Y (verticale) una quantità pari a Jump*0.3f

  • setto la nuova posizione del personaggio

  • (opzionale e in fase di test per evitare scombussolamenti della telecamera) aggiorno la following camera

  • Decremento jump (l’energia del salto)

Spero sia abbastanza chiaro, anche se rimango dell’idea che il modo migliore per imparare sia… modificare! E vedere cosa succede!

Osserviamo ora il resto dei movimenti:

if(tasti[irr::KEY_KEY_W])

{

if (Player->WhatIDo!=2) Player->TheNode->setMD2Animation("run");

Player->WhatIDo=2;

irr::core::vector3df facing( sin( (Player->TheNode->getRotation().Y+90) * PI/180.0f ), 0, cos( (Player->TheNode->getRotation().Y+90) * PI/180.0f ));

facing.normalize();

irr::core::vector3df newPos = (facing*2.3f) + Player->TheNode->getPosition();

Player->TheNode->setPosition( newPos );

return true;

}

 

if(tasti[irr::KEY_KEY_S])

{

if (Player->WhatIDo!=2) Player->TheNode->setMD2Animation("run");

Player->WhatIDo=2;

irr::core::vector3df facing( sin( (Player->TheNode->getRotation().Y+90) * PI/180.0f ), 0, cos( (Player->TheNode->getRotation().Y+90) * PI/180.0f ));

facing.normalize();

irr::core::vector3df newPos = Player->TheNode->getPosition()-(facing*2.3f);

Player->TheNode->setPosition( newPos );

return true;

}

 

if(tasti[irr::KEY_KEY_A])

{

if (Player->WhatIDo!=1) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=1;

Player->TheNode->setRotation( irr::core::vector3df(0, Player->TheNode->getRotation().Y - 3.8f, 0) );

return true;

}

 

if(tasti[irr::KEY_KEY_D])

{

if (Player->WhatIDo!=1) Player->TheNode->setMD2Animation("jump");

Player->WhatIDo=1;

Player->TheNode->setRotation( irr::core::vector3df(0, Player->TheNode->getRotation().Y + 3.8f, 0) );

return true;

}

 

// Se non fa nulla, fa Stand"

 

if ((Player->WhatIDo!=3) && (!IsFalling) && (Player->Jump==0))

{

Player->TheNode->setFrameLoop(1, 319);

Player->WhatIDo=3;

}

return false;

}

Come vedete è tutto piuttosto ripetitivo.

Soffermiamoci perciò più che sui controlli su come vengono calcolate le nuove posizioni a seconda del tasto premuto, premettendo che:

W e S: avanzamento e indietreggiamento del Player secondo il suo orientamento

A e D: rotazione del Player

Per tanto, trattandosi di 3d (!?!),premendo W oppure S faremo:

X=sin( (Player->TheNode->getRotation().Y+90) * PI/180.0f ),

Y=0

Z=cos( (Player->TheNode->getRotation().Y+90) * PI/180.0f ));

Sì, lo so, è “noiosissima matematica trigonometrica”. La cosa forse più “atipica” è quel “+90”… beh, essendo che il personaggio di Sidney è “ruotato” (a livello di mesh) di 90° rispetto alle coordinate base di Irrlicht ho optato per “raddrizzare la rotta” del nostro personaggio.

Per capirci meglio… provate a togliere il +90 e vedrete cosa succede :D .

Infine, una volta normalizzato il vettore, si calcola la nuova posizione con:

irr::core::vector3df newPos = Player->TheNode->getPosition()+(facing*2.3f);

Già, possiamo dire che “2,3f” è la velocità di avanzamento del personaggio. Naturalmente, il + ( o il -) indicano il verso di avanzamento del personaggio.

Leggermente diverso il discorso per la rotazione (tasti A e D):

Player->TheNode->setRotation( irr::core::vector3df(0, Player->TheNode->getRotation().Y - 3.8f, 0) );

In pratica si varia semplicemente la rotazione del nodo di un determinato valore… tutto qui! Anche qui il “+ 3.8f” o il “-3.8f“ individuano il verso (o, meglio, il senso di rotazione) e la sua “velocità”.


Lascia un commento