Heilà !
Riguardo la
trigonometria applicata ad Actionscript 3.0, la volta scorsa abbiamo visto come controllare
collisioni e rimbalzi su superfici angolate.
Dato che l' esempio riportato era con una sola superficie, in questo tutorial vedremo come applicare le stesse formule trigonometriche applicate a più superfici angolate.
In sostanza non cambia molto, le formule utilizzate sono sempre le due che abbiamo visto:
rotazione delle coordinate del sistema:
Code:
x1=Math.cos(angle)*xx-Math.sin(angle)*yy;
y1=Math.cos(angle)*yy+Math.sin(angle)*xx;
riportare le coordinate allo stato iniziale:
Code:
x1=Math.cos(angle)*xx+Math.sin(angle)*yy;
y1=Math.cos(angle)*yy-Math.sin(angle)*xx;
Vediamo un esempio concreto...
Creo un FLA che salvo con nome ' trigonometria7.fla '.
Al suo interno disegno una linea orizzontale, la trasformo in MovieClip e la chiamo mc_line.
La istanzio 7 volte sullo stage, assegnando i rispettivi nomi istanza: line_0_mc, line_1_mc, line_2_mc, line_3_mc, line_4_mc, line_5_mc, line_6_mc .
Creo ora un' altra MovieClip con forma circolare come fosse una pallina e gli assegno nome istanza ball_mc.
Ora creo un altro livello, apro il pannello azioni e scrivo:
Code:
var lines_array:Array=new Array(line_0_mc,line_1_mc,line_2_mc,line_3_mc,line_4_mc,line_5_mc,line_6_mc);
lines_array[0].rotation=30;
lines_array[1].rotation=-20;
lines_array[2].rotation=-10;
lines_array[3].rotation=40;
lines_array[4].rotation=-30;
lines_array[6].rotation=30;
var vx:Number=0;
var vy:Number=0;
const GRAVITY:Number=.5;
const BOUNCE:Number=-.7;
addEventListener(Event.ENTER_FRAME,moveball);
function moveball(evt:Event):void
{
vy+=GRAVITY;
ball_mc.x+=vx;
ball_mc.y+=vy;
checkFloor();
for(var i:int=0;i < lines_array.length;i++)
{
checkCollisions(lines_array[i]);
}
}
function checkFloor():void
{
if(ball_mc.y+ball_mc.height/2>stage.stageHeight)
{
ball_mc.y=stage.stageHeight-ball_mc.height/2;
vy*=BOUNCE;
}
}
function checkCollisions(m:MovieClip):void
{
var bounds:Rectangle=m.getBounds(this);
if(ball_mc.x > bounds.left &&ball_mc.x < bounds.right)
{
var angle:Number=m.rotation*Math.PI/180;
var cosine:Number=Math.cos(angle);
var sine:Number=Math.sin(angle);
var x1:Number=ball_mc.x-m.x;
var y1:Number=ball_mc.y-m.y;
var y2:Number=cosine*y1-sine*x1;
var vy1:Number=cosine*vy-sine*vx;
if(y2 > -ball_mc.height/2&&y2 < vy1)
{
var x2:Number=cosine*x1+sine*y1;
var vx1:Number=cosine*vx+sine*vy;
y2=-ball_mc.height / 2;
vy1*=BOUNCE;
x1=cosine*x2-sine*y2;
y1=cosine*y2+sine*x2;
vx=cosine*vx1-sine*vy1;
vy=cosine*vy1+sine*vx1;
ball_mc.x=m.x+x1;
ball_mc.y=m.y+y1;
}
}
}
Analizziamo il codice
Creo un Array in cui inserisco ogni nome istanza delle MovieClip linea che ho sullo stage
var lines_array:Array=new Array(line_0_mc,line_1_mc,line_2_mc,line_3_mc,line _4_mc,line_5_mc,line_6_mc);
assegno una rotazione ad ogni linea
lines_array[0].rotation=30;
lines_array[1].rotation=-20;
lines_array[2].rotation=-10;
lines_array[3].rotation=40;
lines_array[4].rotation=-30;
lines_array[6].rotation=30;
creo due variabili in cui inserisco i valori delle velocità della x e della y
var vx:Number=0;
var vy:Number=0;
una costante che contiene il valore della gravità
const GRAVITY:Number=.5;
una costante che contiene il valore dell' altezza del rimbalzo
const BOUNCE:Number=-.7;
aggiungo un ENTER_FRAME che chiama la funzione moveBall
addEventListener(Event.ENTER_FRAME,moveBall);
Nella funzione moveBall:
aumento progressivamente la velocità sull' asse y di ball_mc aggiungendogli la costante GRAVITY
vy+=GRAVITY;
do in pasto alle proprietà x e y di ball_mc i valori delle velocità ( vx e vy )
ball_mc.x+=vx;
ball_mc.y+=vy;
chiamo continuamente la funzione checkFloor che controllerà se ball_mc collide con la massima altezza dello stage ( come fosse il pavimento )
checkFloor();
all' interno di un ciclo chiamo continuamente la funzione checkCollisions passandogli come parametro ognuna delle MovieClip contenute nell' array ( le linee )
for(var i:int=0;i < lines_array.length;i++)
{
checkCollisions(lines_array[i]);
}
Nella funzione checkFloor:
controllo continuamente se ball_mc collide con la parte più bassa dell' SWF ( chiamatela come vi pare, la massima altezza o il pavimento... ) utilizzando la stessa tecnica vista nel tutorial della
pallina che rimbalza.
if(ball_mc.y+ball_mc.height/2>stage.stageHeight)
{
ball_mc.y=stage.stageHeight-ball_mc.height/2;
vy*=BOUNCE;
}
Nella funzione checkCollisions eseguo la stessa identica tecnica utilizzata nel tutorial precedente a questo:
trigonometria 7 tranne che per 2 righe in cui utilizzo il metodo getBounds():
creo una variabile di tipo Rectangle e gli assegno il valore che restituisce il metodo getBounds applicato alla linea che sto controllando.
In pratica questo metodo restituisce un rettangolo che ha la x, y, width e height di m ( la linea che sto controllando ).
Poi, utilizzando un if, conrollo che la x di ball_mc sia maggiore della massima area sinistra del rettangolo della linea che sto controllando e che sia minore della massima area destra del rettangolo della linea che sto conrollando.
Se provate a togliere questo controllo capirete meglio il suo scopo.
Tutto il resto, come ho già detto, lo abbiamo già visto.
var bounds:Rectangle=m.getBounds(this);
if(ball_mc.x > bounds.left &&ball_mc.x < bounds.right)
{
var angle:Number=m.rotation*Math.PI/180;
var cosine:Number=Math.cos(angle);
var sine:Number=Math.sin(angle);
var x1:Number=ball_mc.x-m.x;
var y1:Number=ball_mc.y-m.y;
var y2:Number=cosine*y1-sine*x1;
var vy1:Number=cosine*vy-sine*vx;
if(y2 > -ball_mc.height/2&&y2 < vy1)
{
var x2:Number=cosine*x1+sine*y1;
var vx1:Number=cosine*vx+sine*vy;
y2=-ball_mc.height / 2;
vy1*=BOUNCE;
x1=cosine*x2-sine*y2;
y1=cosine*y2+sine*x2;
vx=cosine*vx1-sine*vy1;
vy=cosine*vy1+sine*vx1;
ball_mc.x=m.x+x1;
ball_mc.y=m.y+y1;
}
}
Alla prossima !