Apriamo un nuovo documento flash 550x250, 50 fps di frame rate. Creiamo i layer secondo questo schema:
Nel layer azioni settiamo 2 variabili che interpretano il limite destro e il limite inferiore dell'area in cui si muoverà la sfera.
s_width = 550;
s_height = 250;
stop ();
Nel layer sfera disegnamo un cerchio di dimensioni 16x16. Selezioniamo il cerchio e lo convertiamo in pulsante tramite F8 , come nome di libreria diamo "drag" e come coordinate di posizione diamo x, y = -8.0. Convertiamo nuovamente, stavolta in movieclip, sempre con F8, come nome di istanza diamo "sfera" e lo posizioniamo al centro-sinistra dello stage.
Editiamo con un doppio click il mc sfera e associamo al pulsante "drag" il seguente codice che serve a rendere trascinabile il mc sfera.
// alla pressione del mouse
on (press) {
// setta la variabile dragging come vera
dragging = true;
// rendiamo trascinabile questo movieclip
startDrag (this, true);
}
on (release, releaseOutside) {
// setta la variabile dragging come falsa
dragging = false;
// -fine trascinamento-
stopDrag();
}
A questo punto abbiamo sullo stage il movieclip sfera che contiene il pulsante drag. Creiamo, tramite il pulsante "+" nella libreria, un nuovo mc chiamato "smile_vuoto", che sarà composto da 17 frames contenenti l'animazione della gif "smile" che sfuma (coordinate x, y = -8.0). Inseriamo un nuovo livello che chiamiamo azioni: al frame 17 di questi associamo il seguente codice, (dove i è la variabile che gestisce il numero di mc duplicati e rimossi) :
// decrementa la i di una unità
_root.i--;
//eliminiamo il duplicato creato
removeMovieClip(this); (*)
Selezioniamo il mc sfera ed associamo le seguenti azioni:
onClipEvent (load) {
gravity = 12;
rimbalzo = .6;
raggio = this._width/2;
}
onClipEvent (enterFrame) {
vecchiaX = x;
vecchiaY = y;
x = this._x;
y = this._y;
if (dragging) {
Lx = (x - vecchiaX) * 10;
Ly = (y - vecchiaY) * 10;
} else {
Ly += gravity;
x += (Lx / 10);
y += (Ly / 10);
if (y < raggio) {
y = raggio;
Lx *= rimbalzo;
Ly *= -rimbalzo;
}
if(y > (_root.s_height - raggio)) {
y = _root.s_height - raggio;
Lx *= rimbalzo;
Ly *= -rimbalzo;
}
if (x < raggio) {
x = raggio;
Lx *= -rimbalzo;
Ly *= rimbalzo;
}
if (x > (_root.s_width - raggio)) {
x = _root.s_width - raggio;
Lx *= -rimbalzo;
Ly *= rimbalzo;
}
this._x = x;
this._y = y;
}
_root.i++;
duplicateMovieClip ("_root.smilevuoto", "sfera" +_root.i, _root.i);
_root["sfera" + _root.i]._x = x;
_root["sfera" + _root.i]._y = y;
}
Prima di entrare nel "vivo" dello script, faccio un breve (?) appunto sull'azione dinamica delle forze agenti.
La gravità
Sperimentalmente tutti i corpi assumono, se lasciati liberi, la stessa accelerazione, detta di "gravità", diretta verticalmente verso il suolo. Nella realtà il suo valore è g = 9.8 ms². Nel nostro caso settiamo una forza di gravità pari a 12 (gravity = 12).
Il lancio
Cosa accade quando lanciamo la sfera?
- La sfera si sposta da un punto A ad un punto B e, indicando con x_a e x_b le ascisse del punto (cioè il valore reale dei punti A e B), il suo spostamento ds è dato da x_b - x_a.
- Per lanciare la sfera le applichiamo una forza, cioè compiamo un lavoro pari alla forza applicata per lo spostamento compiuto: L = f * ds
Indicando con Lx e Ly il lavoro di ascissa x e y, con f = 10 il valore della forza e con ds = (x_b - x_a) lo spostamento, segue : Lx = (x_b - x_a) * 10; Ly = (y_b - y_a) * 10; (In questo modo "creiamo" la velocità della sfera).
Inoltre da L = f*ds risulta che lo spostamento compiuto è pari a: ds = L/f cioè: dx = Lx/10 e dy = Ly/10
L'urto
Cosa accade quando la sfera entra in contatto con un limite dell'area? ..."Ad ogni azione corrisponde una reazione uguale ed opposta ed agente sulla stessa retta di applicazione..."
Se lancio una sfera contro il soffitto con una certa forza f essa ricadrà con una forza -f opposta al suo asse di simmetria. L'urto modifica la quantità di moto del punto e nel nostro caso "quantità di moto" significa rimbalzo = 0.6.
I rimbalzi della sfera
La velocità (L = f * ds) con cui si muove la sfera dipende dallo spostamento AB quindi, quando (dopo l'urto) tocca il limite inferiore per la prima volta, la velocità con cui riparte varia al variare dello spostamento e quindi la sfera ha una perdita di velocità direttamente proporzionale alle coordinate.
Se invece lasciamo cadere la sfera, l'unica forza agente è la gravità (che spinge l'oggetto in basso), per cui incrementiamo il lavoro lungo la verticale y di un valore di gravità pari a 12: Ly += 12
Il raggio
Il centro della sfera rappresenta la sua posizione _x. Se portiamo questa sfera ai bordi dell'area di delimitazione essa oltrepasserà di metà della sua larghezza il limite , creando un effetto rimbalzo poco realistico ... Per ovviare a ciò creiamo una variabile raggio (raggio=larghezza_sfera/2 ) in modo che, ogni volta che la sfera raggiunge un bordo, aggiungiamo o sottraiamo il raggio alla sua posizione corrente come spiegato nei commenti dello script.
// al caricamento del mc
onClipEvent (load) {
// settiamo la gravità
gravity = 12;
// settiamo il rimbalzo
rimbalzo = .6;
// settiamo la variabile raggio
raggio = this._width/2;
}
// ad ogni riproduzione del movieclip
onClipEvent (enterFrame) {
// settiamo le variabili dello spostamento
vecchiaX = x;
vecchiaY = y;
// posizione attuale del movieclip sfera
x = this._x;
y = this._y;
// se la variabile dragging è vera ( vedi pulsante drag)
if (dragging) {
// calcoliamo il lavoro L = f * ds
// (che corrisponde alla velocità della sfera di coordinate (x, y))
Lx = (x - vecchiaX) * 10;
Ly = (y - vecchiaY) * 10;
// altrimenti, se lasciamo cadere la sfera
} else {
// sommiamo a Ly la gravità
Ly += gravity;
// definiamo lo spostamento corrente
x += (Lx / 10);
y += (Ly / 10);
// se y è minore di 8 ( ci troviamo oltre il limite superiore)
if (y < raggio) {
// facciamo rientrare y nel valore limite
y = raggio;
// definiamo il rimbalzo lungo l'ascissa x
Lx *= rimbalzo;
// definiamo il rimbalzo lungo y
// ... opposto alla direzione iniziale di y
Ly *= -rimbalzo;
// in modo analogo gestiamo la condizione y maggiore di 250 - 8 = 242
// cioè quando la sfera si trova oltre il limite inferiore
}
if(y > (_root.s_height - raggio)) {
y = _root.s_height - raggio;
Lx *= rimbalzo;
Ly *= -rimbalzo;
}
// se x < 8 (limite sinistro)
if (x < raggio) {
// facciamo rientrare x nel limite
x = raggio;
// definiamo il rimbalzo lungo x con direzione opposta
// alla retta di applicazione
Lx *= -rimbalzo;
// rimbalzo lungo y
Ly *= rimbalzo;
}
// se x è maggiore di 550 - 8 = 542 (limite destro)
if (x > (_root.s_width - raggio)) {
x = _root.s_width - raggio;
// gestione rimbalzo analoga alla suddetta
Lx *= -rimbalzo;
Ly *= rimbalzo;
}
// impostiamo la posizione di questo (sfera) mc e
// diamogli come valore il valore di x e di y
this._x = x;
this._y = y;
}
// aumentiamo la variabile i di una unità
_root.i++;
// duplichiamo il mc "smilevuoto" , diamogli il valore di
// "sfera[i]" come nome e diamogli profondità "i"
duplicateMovieClip ("_root.smilevuoto", "sfera" +_root.i, _root.i);
// impostiamo la posizione del mc "sfera[i] con il valore
// delle coordinate del mc "sferavuota"
_root["sfera" + _root.i]._x = x;
_root["sfera" + _root.i]._y = y;
}
La prima parte dello script, quella relativa al caricamento del mc, oltre ad assegnare un valore alle "forze" che agiscono sulla sfera, setta la variabile raggio che definisce anche il limite sinistro e il limite superiore dell'area di spostamento. Ogni volta che viene caricato il movieclip settiamo i valori delle coordinate, della velocità e a seconda dei casi, dello spostamento e del rimbalzo. Infine creiamo la "scia" duplicando il movieclip . Notiamo che l'azione usata duplica in continuazione il movieclip smile_vuoto e i vari duplicati vengono sostituiti dai nuovi scomparendo.( removeMovieClip (*))