Salve a tutti!
In questa lezione modificheremo l’esempio della lezione precedente ( la casa in 3D) , introducendo anche una gestione primitiva dei suoni.

Agiremo su tre punti principali:
-Azioni di movimento dell’utente
-Limitazione degli spazi
-Introduzione ai suoni

1) azioni di movimento
Introdurremo alcune azioni basilari che avevamo tralasciato nell’esempio precedente per mancanza di tempo: la possibilità di saltare ed abbassarsi. Contemporaneamente modificheremo lo spostamento base per renderlo più veritiero.

CROUCHING & JUMPING:


var excursion_y=0.02 ; //massima escursione nel movimento
var iscrouching=0;
var isjumping=0;
var PosY0=0.5; //altezza telecamera in condizioni normali ( in piedi)
var PosY0C=0.2; // altezza telecamera quando abbassata
function KeyPressed()
{
...
//cliccato C
if (currentPressedKey[67] && iscrouching==0 )
{

if ( PosY<=PosY0+excursion_y && PosY>PosY0-excursion_y )
iscrouching=1;
if(PosY< PosY0C+excursion_y )iscrouching=2; } //cliccato space if (currentPressedKey[32] && isjumping==0) { isjumping=1; } }

Come possiamo notare dal codice, se l'utente clicca C ( il pulsante utilizzato per abbassarsi ed alzarsi), viene fatto un controllo sull'altezza: se la telecamera è già abbassata , la variabile iscrouching assume il valore 2 ( telecamera ascendente), altrimenti 1 (telecamera discendente).
Con un metodo altrettanto semplice viene rilevato il click sul pulsante space adibito al salto . Queste variabili verrano poi utilizzate nella funzione animate() per calcolare la variazioni sull'altezza.

N.B. i valori controllati nelle condizioni if sono sfasati di una quantità excursion_y: tale valore viene introdotto perchè nel prossimo paragrafo introdurremo uno spostamento più realistico della telecamera mentre cammina , il quale inevitabilmente varia quelli che sono i range di valori assumibili dalla telecamera.


var excursion_jump=0.3;
function animate()
{
...
if(isjumping==1)
{
if(ang<180){ ang=ang+5; PosY=Approx(PosY0+excursion_jump*Math.sin(degToRad(ang)),100); } else { PosY=PosY0; ang=0; isjumping=0; } } if(iscrouching==1) { if (PosY>PosY0C)
PosY=Approx(PosY-0.05,100);
else
iscrouching=0;

}
if(iscrouching==2)
{
if (PosY

Nella funzione animate() , a seconda del valore di iscrouching, viene cambiato il valore dell'altezza PosY (fino ad un valore predefinito : PosY0C se si abbassa e PosY0 se si alza).
Approx() è semplicemente una funzione per approssimare il valore al secondo decimale.
Da notare che per calcolare l'altezza durante il salto si usa il seno di un angolo tra tra 0 e 180 , in questo modo il movimento sarà realisticamente parabolico.

MOVIMENTO REALISTICO:
Il movimento della telecamera avanti ed indietro per la stanza appare troppo lineare e perfettamente parallelo al terreno: una buona tecnica è quello di muovere leggermente la camera lungo l'altezza per simulare il movimento delle gambe.

function animate()
{
...
if (isjumping==0 && iscrouching==0 && PosY>PosY0C)
{

PosY=Approx(PosY0+excursion_y*Math.sin(degToRad(ang_walking)),100);
ang_walking+=8;
if(ang_walking>360) {ang_walking=ang_walking-360;}

}

...
}

Questo movimento viene eseguito solo se il soggetto è in piedi e non sta eseguendo altre operazioni come il salto e l'abbassamento. Tale spostamento viene calcolato anch'esso tramite la funzione seno, mentre excursion_y rappresenta la massima escursione possibile durante tale spostamento .

LIMITAZIONE DEGLI SPAZI:
Nel precedentemente esempio la telecamera si poteva spostare ovunque, attraversare le pareti e muoversi all'infinito.
Vi sono svariati metodi per risolvere tale problema: contando che esiste un solo livello possibile, nessun elemento distruttibile ed addirittura una sola stanza, sarà sufficiente introdurre un controllo delle coordinate ammissibili.

Mappa della stanza:


var dist_min_muro=0.15; // distanza minima tra la telecamera e il muro.
function CheckPositions(incrx,incrz)
{
temp1=PosX-incrx;
temp2=PosZ-incrz;
//se la telecamera è dentro uno dei due C
if ((temp2>-0.5+dist_min_muro && temp2<0.5-dist_min_muro) && ((temp1<-2.0+dist_min_muro && temp1>-3.0) ||(temp1<3.0 && temp1>2.0-dist_min_muro) ) )
{
PosZ=temp2;PosX=temp1;
}
//se la telecamera è dentro uno delle due B
if ( (temp1>-0.5+dist_min_muro && temp1<0.5-dist_min_muro) && ((temp2<3.0 && temp2>2.0-dist_min_muro) || (temp2>-3.0 && temp2<-2.0+dist_min_muro) )) { PosZ=temp2;PosX=temp1; } //se la telecamera è dentro uno delle due A if (temp1>-2+dist_min_muro && temp1<2-dist_min_muro && temp2>-2+dist_min_muro && temp2<2-dist_min_muro ) { PosZ=temp2;PosX=temp1; } }

Vengono analizzate se le coordinate appartengono alla tre aree ammissibili: in caso negativo, la telecamera rimane nell'uultima posizione possibile ( rimane ferma).
dist_min_muro è , come dice il termine, la distanza minima tra utente e muro: questo per evitare che in qualche modo ci fossero posizioni collisioni e la telecamera in qualche inquadratura riuscisse ad oltrepassare il muro.

SOUND:
Iniziamo ora a trattare la gestione del sonoro; per dare maggiore realismo, bisogna che anche alla nostra applicazione sia affiancato un solido comparto sonoro oppure si ha il rischio che il tutto risulti "poco sensato e convolgente".
Per tale motivo abbiamo necessità di caricare e gestire file sonori , specie quando il soggetto esegue determinate azioni:


function InitSounds()
{
jump_sound=new Audio("bjump.wav");
jump_sound.volume = 0.2;
walking_sound= new Audio("footsteps.mp3");
walking_sound.loop=true;
walking_sound.volume = 0.2;
}

function Start() {
var canvas = document.getElementById("Mycanvas");
...
InitSounds();
...
}

L'inizializzazione è veramente semplice: è sufficiente passare al costruttore Audio() il percorso del file; volume è ovviamente l'attributo che regola il volume ( da 0.0 minimo a 1.0 massimo ) . Loop è invece l'attributo booleano che setta l'eventuale ciclicità dell'esecuzione di tale file: nel nostro esempio quando la telecamera si muoverà, noi vorremo sentire il suono dei suoi passi continui fino a che l'utente non si fermerà.


function KeyPressed(){
...
if (currentPressedKey[32] && isjumping==0)
{
isjumping=1;
jump_sound.play();
}

...
}

var iswalking=false;
function animate()
{
...
if (speed != 0)
{

...
if (!iswalking)
{
walking_sound.play();
iswalking=true;
}
}
else
{
iswalking=false;
walking_sound.pause();
}

Come potete vedere nel caso del salto, facciamo partire il suono solo una volta ( il rumore del respiro per lo sforzo) ,mentre nella camminata, visto che deve essere continuamente ripetuto, facciamo una sola volta play() se la velocità è diversa da 0. Essendo in loop continuo, continuerà a ripetersi il suono fino a che l'utente non si ferma ( invocando la relativa funzione pause() ).

Come potete vedere con pochi accorgimenti, siamo riusciti a rendere il nostro esempio della casa più realistico ed interessante: nella prossima lezione vedremo un metodo "grezzo" per importare qualche modello 3D più complesso per arricchire il nostro gioco.

Per potere vedere l'esempio appena mostrato ( lo trovate come lesson09) e scaricare il codice che è stato presentato nell'articolo, collegarsi al solito repository Lab .

Grazie per l’attenzione,

Andrea