Col·lisions i manipulació de coordenades entre clips de diferents jerarquies  
 
 
 

En aquesta pràctica, us iniciareu ja en col·lisions més complexes. Aquesta dificultat que trobareu al llarg del desenvolupament d'una aplicació consistent en una simulació interactiva de l'àrea de física, on, per mitjà de col·lisions i clips que es troben en diferents jerarquies, i per tant tenen diferents coordenades, veureu com les lleis de les màquines simples (palanques) poden mostrar la potència del Flash en aquest tipus d'aplicacions.

Podeu extrapolar aquesta potència del Flash a la majoria d'aplicacions de física, on tenen sentit l'aplicació de fórmules i moviments (cinemàtica, dinàmica...).

Com a continguts de programació d'aquesta pràctica, treballareu amb:

  • El mètode getBounds, que retorna les coordenades de les quatre cantonades d'un clip de pel·lícula (movie clip) respecte a un nivell.
  • La interrelació dinàmica entre el desplaçament i la rotació de clips que es troben en diferents nivells de jerarquia.
 
      
  Podeu esbrinar el que es vol aconseguir en aquesta pràctica experimentant amb l'aplicació que es mostra a continuació.  
      
 
      
  Es tracta que es puguin posar els pesos (d'un en un) sobre el plat vermell situat a l'extrem de la palanca. Aquesta es desequilibrarà i, movent el punt de suport de la palanca, podreu comprovar si la força que li apliqueu a l'altre extrem és la correcta perquè es compleixi la llei física de les palanques de primer gènere.  
      
Desenvolupament de la pràctica  
   
»      Recupereu l'arxiu pal1.zip, que conté la interfície de l'aplicació.
   
»      Primer, comenceu per crear la funció inicia() perquè els pesos es posin al seu lloc corresponent d'inici cada vegada que vulgueu variar el pes que s'aplica sobre el plat vermell de la palanca.  
      
El codi de la funció és aquest:
      
 

function inicia() {

// Primer bloc

_root.m1._x = 32.6;
_root.m1._y = 35.4;
_root.m2._x = 32.2;
_root.m2._y = 67.5;
_root.m3._x = 32.2;
_root.m3._y = 109.8;
_root.m4._x = 32.5;
_root.m4._y = 160.3;
_root.m5._x = 33.5;
_root.m5._y = 219.5;

// Segon Bloc

_root.lin1._rotation = 0;
_root.lin1.punt._rotation = 0;
_root.lin1.base._rotation = 0;

// Tercer bloc

_root.t2="";
_root.t4="";
_root.t5="";
_root.t6="";
_root.t7="";
_root.t8="";
}

 
  
        
 

En el primer bloc de codi de la funció, es posen les coordenades de cada clip de pel·lícula que corresponen al pes, els valors d'inici de les seves coordenades X, Y.

Al segon bloc, es determina l'estat inicial de rotació a 0 (en repòs) dels clips de pel·lícula organitzats en jerarquia que formen la palanca i el suport. Avançada la pràctica, se us anirà explicant la creació i el funcionament d'aquest clip tan especial.

  • Al tercer bloc, es buida el contingut dels quadres de text, que corresponen a:
  • pes situat sobre la palanca (t2)
  • resultat per esbrinar (t4)
  • resultat possible per escollir (t5,t6,t7,t8)
 
      
  » Inicialitzeu, també, les variables següents:  
      
 

m=0; // per al valor del pes escollit

s=0; // per tenir solament un pes sobre el plat de la palanca

total=0; // per incloure el resultat final dels càlculs

escollir=0; // per emmagatzemar el nom de la instància que correspon al pes que l'usuari/ària ha escollit

 
 

  

 
  »      Escriureu, també, el codi corresponent a la funció resultats(), on li passareu el paràmetre total, que correspon a la variable del mateix nom i que conté el valor correcte de les operacions fetes seguint la llei de la palanca.  
      
 

function resultats(total) {

if(Number(_root.t2)>0) {

var z=random(4);
if(z==0) {
_root.t5=_root.total;_root.t6=_root.total-1.5;_root.t7=_root.total+0.9;_root.t8=_root.total-1.2; }

if(z==1) { _root.t5=_root.total-1;_root.t6=_root.total;_root.t7=_root.total+1.3;_root.t8=_root.total+3; };

if(z==2) { _root.t5=_root.total-1.5;_root.t6=_root.total+2;_root.t7=_root.total;_root.t8=_root.total-2; };

if(z==3) { _root.t5=_root.total+1.5;_root.t6=_root.total-3;_root.t7=_root.total+0.8;_root.t8=_root.total; };

}
else {_root.t5="";_root.t6="";_root.t7="";_root.t8="";}

}

 
 

 

 
  Aquesta funció rebrà el resultat correcte com a paràmetre, i una vegada emmagatzemat en la seva variable total, farà una primera comprovació de veure si, dins el quadre de text dinàmic t2, hi ha alguna quantitat. Els programadors en altres llenguatges tenen el bon costum de convertir a nombre el contingut d'un quadre de text (aquí expressat per la funció Number() encara que amb Flash no és necessari).  
 

  

 
 

En el cas afirmatiu d'haver una quantitat en el quadre de text t2 (això indica que s'ha escollit un pes i s'ha col·locat sobre el plat de la palanca), escolliu un nombre a l'atzar entre 0 i 3 expressat per la funció random().

Depenent del nombre que l'ordinador escull a l'atzar, poseu en els quadres de text (t5, t6, t7, t8) el valor real total en un d'ells i uns valors modificats i no correctes en els altres tres quadres de text. La finalitat d'això és que l'usuari/ària no pugui conèixer el lloc on estarà la resposta correcta. En el cas que el quadre de text no tingui cap valor (l'usuari/ària no ha escollit el pes), es buidarà el contingut dels quadres de text que resten de l'experimentació anterior.

 
 

  

 
  »      Per últim, afegiu, també, el codi de la funció situa() que, per la seva complexitat i novetat, s'explica ara línia a línia.  
      
 

function situa () {
_root.x = _root.lin1.base.getBounds(_root);
_root.mx = _root.x.xMin;
_root.my = _root.x.yMin;
eval(_root.escollir)._x = _root.mx+15;
eval(_root.escollir)._y = _root.my;
}

 
      
 

A la primera línia de la funció situa(), us trobeu el mètode getBounds(). Aquest mètode retorna les coordenades de les quatre cantonades del quadre que limita al clip de pel·lícula en relació a l'espai de coordenades que s'especifica com a paràmetre i que, en el vostre cas, correspon a les coordenades de la pel·lícula principal.

Aquest mètode retorna un objecte amb quatre propietats xmin, xmax, ymin, ymax. El primer (xmin) representa el punt més allunyat a l'esquerra d'on apareix contingut en el clip de pel·lícula. El segon (xmax), el punt més allunyat de la dreta, ymin retorna el punt més allunyat de la part superior d'on apareix contingut el clip de pel·lícula i, finalment, ymax retorna la coordenada Y més baixa.

En el vostre cas, getBounds() és molt útil perquè esteu unint diversos clips de pel·lícula (un a dintre d'un altre), i podríeu tenir problemes per seguir la pista d'on s'ubiquen realment. L'ús d'aquest mètode us permet determinar exactament quins límits d'aquests objectes es troben a l'escenari independentment dels punts de registres respectius.

Quan s'ha creat el clip de pel·lícula lin1 i s'ha inserit un altre clip de pel·lícula anomenat base, aquest últim clip té unes coordenades pròpies i relatives al seu clip pare lin1. En el vostre cas, com que està situat a la part esquerra del punt d'inserció del clip de pel·lícula lin1, tindrà coordenades negatives que no corresponen a les de l'escenari principal, i com que heu de posar un pes (un altre clip de pel·lícula), que té les coordenades relatives a la pel·lícula principal, heu de convertir les coordenades del clip base a les coordenades de la pel·lícula principal perquè una vegada se situa el pes a sobre del plat (base), si es modifica la posició del plat, el pes ha d'anar adquirint aquestes coordenades perquè es moguin junts.

 
 

  

 
  Amb això s'aconseguirà que el plat i el pes facin la simulació que es pretén.  
 

  

 
  Per finalitzar el comentari d'aquesta funció, recordeu que la variable escollir conté el nom de la instància que correspon al pes escollit (m1, m2, m3, m4, m5), i situeu el clip 15 píxels més a la dreta de la seva coordenada X perquè quedi situada al lloc adient.  
 

  

 
  »      Ara escriviu el codi que tindrà cada instància que correspon a cada pes, però observeu que la instància conté un botó perquè sigui sensible a les incidències del ratolí. Aquest codi l'heu d'incloure dins les accions del botó corresponent.  
 

  

 
 

Se us dóna el codi que correspon al botó de la primera instància m1 (pes de 50).

» Observeu que, en el codi, hi ha dues incidències: una en prémer el ratolí on li assigneu l'acció d'arrossegar, i una altra incidència que correspon a alliberar el ratolí fora o dins la instància.

Comentari d'aquest codi:

 
 

  

 
 

// Primer evento

on (press) {startDrag ("");}

// Segon evento

on (release, releaseOutside) {

this.stopDrag("");
if (this.hitTest(_root.lin1.base)) {
_root.lin1._rotation = _root.lin1._rotation-10;
_root.lin1.punt._rotation = _root.lin1.punt._rotation+10;
_root.lin1.base._rotation += 10;
_root.t2 = 50;
_root.escollir = this._name;
this._x = _root.lin1._x+_root.lin1.base._x;
this._y = _root.lin1._y-_root.lin1.base._y-5;
_root.situa();
_root.total = Number(_root.t1)*Number(_root.t2)/Number(_root.t3);
_root.Resultats(_root.total);
_root.so.gotoAndPlay(2);
} else {
_root.inicia();
}

}

 
  

Passem a explicar ja directament el codi de la segona incidència.

Quan allibereu el ratolí, el primer que feu és desactivar l'acció d'arrossegament d'aquest clip (this).

Si hi ha col·lisió d'aquest clip (el pes) amb el clip base, que és fill del clip lin1, feu que hi hagi una rotació en sentit contrari de les agulles del rellotge de -10 del clip pare lin1.

Si gira el clip pare lin1, que conté els clips de pel·lícula base (plat) i punt (suport), aquests clips de pel·lícula fills també giraran, i per aconseguir l'efecte visual en què només es mogui la palanca, s'hauran de girar aquests dos clips en sentit contrari (en el sentit de les agulles del rellotge) la mateixa quantitat de gir, però en positiu.

Una vegada aconseguit el moviment de la palanca simulant el desequilibri en posar el pes, s'haurà de posar el valor d'aquest pes en el quadre de text corresponent (t2). Aquesta quantitat de 50 variarà en el codi corresponent que haureu d'incloure a cada pes.

» Ara feu que la variable escollir agafi el nom de la instància que heu situat sobre la palanca (m1, m2, m3...).

Les dues línies de codi següents situen, per primera vegada, el pes en el lloc adient sobre el plat (5 píxels per sobre de la instància línia).
  

Com que l'usuari/ària pot variar la rotació de la palanca, feu una crida a la funció situa(), ja explicada al començament d'aquesta pràctica, per anar variant la situació del pes també.

Per finalitzar aquesta condició, es fan els càlculs de la llei de la palanca i es posen en la variable total.

» A continuació, feu una crida a la funció resultats(), ja explicada, per distribuir els resultats en els quadres de text, i doteu la simulació de desequilibri amb un so.

En el cas de no haver-hi detecció de col·lisió, vol dir que no s'ha situat cap pes sobre la palanca i l'aplicació ha de tenir un estat inicial, i a tal efecte, feu una crida a la funció inicia(), que s'encarregarà que l'aplicació comenci amb el seu estat inicial.

  

Recordeu que aquest codi s'ha d'introduir al botó de cada instància dels pesos respectius variant les quantitats, i que línies repetides es podrien incloure en una funció a part per evitar repeticions; però, com que es tracta d'explicar el funcionament del codi d'un clip, es creu més fàcil copiar i enganxar i després depurar i optimitzar el codi.

 

Els botons que hi ha a la dreta (zona vermella) tenen com a objectiu el fet de posar el resultat del quadre de text adjunt a la resposta que desitgi l'usuari/ària, i per poder complir les lleis de la palanca, s'ha de posar en el quadre de text dinàmic t4.

» Per aconseguir això, l'única acció que ha de fer el botó quan s'alliberi el ratolí és:

on (release) {_root.t4=_root.t5;}

   

» Recordeu incloure aquest codi a les incidències dels altres tres botons, però canviant la variable t5 per t6, t7 i t8, respectivament.

» Ara programeu el codi corresponent a les accions que ha d'executar el botó que té la funció de desplaçar el punt de suport a l'esquerra (botó mouse suport direcció esquerra).

     

on (press, releaseOutside) {

if(br>=0.20) {

// Primer bloc
_root.br=_root.br-0.10;
_root.bp=_root.bp+0.10;
_root.t1=br;
_root.t3=bp;

// Segon bloc
_root.lin1.lin2._x = _root.lin1.lin2._x+10;

_root.punt._x=_root.punt._x+10;

_root.lin1._x=_root.lin1._x-10;

_root.lin1.base._x+=10;

// Tercer bloc
if(_root.t2>0) {_root.situa();}
_root.total=Number(_root.t1)*Number(_root.t2)/Number(_root.t3);
_root.Resultats(_root.total);

}

}

       

Com que el treball que ha d'executar el botó és desplaçar el punt de suport a l'esquerra, cada vegada que es faci clic sobre el botó, es desplaçarà de forma infinita i aquest punt de suport podria sortir dels extrems de la barra. Per evitar-ho, es posa la condició que només farà l'acció si la variable que correspon a br (part esquerra de la palanca o braç de la resistència) sigui superior a 0.20 m.

El primer bloc de la condició estableix que, si s'ha fet clic al botó, la variable br disminueix en 0.10, però la variable bp (part dreta de la palanca (braç de la potència) ha d'augmentar aquesta distància en 0.10). Es fa que la variable t1, que correspon al primer quadre de text, prengui el valor del seu braç i la variable t3 prengui el corresponent de l'altre braç.

Per poder entendre el codi del segon bloc, seria convenient que observéssiu la jerarquia dels clips de pel·lícula que formen tota la palanca i suport, així com els seus noms d'instància.

En aquest segon bloc, es mou el braç (lin2) 10 píxels a la dreta. A continuació, es mou el clip punt (suport) també 10 píxels a la dreta. A la tercera línia d'aquest bloc, es mou tot el clip de pel·lícula 10 píxels a l'esquerra per fer tota la simulació, i només queda moure el clip base, que correspon al plat, deu píxels a la dreta perquè estigui a l'extrem de la barra.

Passem ara ja a explicar el tercer bloc. S'inicia aquest bloc amb la condició que només utilitzarà la funció situa() si, en el segon quadre de text (variable t2), hi ha una quantitat, cosa que vol dir que hi ha un pes en plat de la palanca, i per finalitzar, es posa a la variable total el resultat d'aplicar la fórmula per calcular la força mínima que s'hauria de fer per moure la palanca. Seguidament, es crida a la funció resultats() perquè posi el resultat correcte de la variable total en un dels quadres de text t5, t6, t,7, t,8, segons determini la funció.

» Heu de programar el mateix codi per al botó de moure suport a la dreta amb les modificacions corresponents perquè faci l'acció d'anar cap a la dreta.

 

» Ara heu de programar les accions que ha de fer el botó Provar. Només haurà de fer les accions de girar els braços de la palanca si la resposta escollida és la correcta, i és per això que comenceu el codi amb la condició que al quadre de text dinàmic t4, hi ha un resultat igual al correcte que correspon a la variable total.

Després de fer aquesta comprovació, es dota de gir a la palanca (lin1) en el sentit del moviment de la palanca, però feu que es mogui en el sentit contrari de rotació el punt de suport (punt) i el plat (base).

» Per últim, feu la crida a la funció situa() ja explicada.

El codi seria aquest:

  

on (release) {

if (_root.total == _root.t4) {
_root.lin1._rotation = _root.lin1._rotation+1;
_root.lin1.punt._rotation = _root.lin1.punt._rotation-1;
_root.lin1.base._rotation -= 1;
_root.situa();
}

}

  

» Per finaltzar l'aplicació d'aquesta pràctica, doteu de codi el botó Iniciar joc, que consisteix, només, a cridar la funció inicia() que s'ha explicat al principi:

on (release) {_root.inicia();}

Aquesta aplicació es podria depurar, millorar a gust del programador treballant en nombres sense decimals per facilitar els càlculs mentals, evitant amb les proteccions corresponents que pugui haver dos clips de pel·lícules (pesos) coincidents en el plat. Com a exercici curiós, si s'aplica una força superior a la mínima corresponent per moure la palanca que el pes situat sobre la palanca, salta disparat amunt indicant que us heu passat.

    

Comproveu que l'aplicació funciona correctament i deseu-lo amb el nom pal2.fla.