1.- CARACTERISTICAS DEL ESCENARIO
- Tamaño: 550px de ancho por 400 px de alto (pueden usar cualquier tamaño)
- Velocidad: 30 fps (pueden usar cualquier velocidad, pero si influirá en el resultado final)
- 3 capas: en la primera el AS3, la segunda para un texto dinámico con nombre de instancia
puntos, la ultima para el fondo, en mi caso solo use un borde color negro de 3 pts. de ancho

- 3 movieclips: despues de crearlos, los exportamos y vinculamos para poder usarlos desde la biblioteca, y los borramos del escenario.
el primero seria un objeto (yo use un circulo, pero pueden usar cualquier otra forma) de 50 px con una flechita en el borde superior, alineado al centro del escenario, exportamos como MiObjeto

el segundo seria un movieclip (yo use un circulo) de 20 px alineado al centro del escenario (pueden usar cualquier otra forma o imagen png, pero su tamaño afecta su gravedad ya que usaremos su tamaño como referencia de su peso) , exportamos como MiClip

el ultimo una flecha de 52 de ancho por 30 de largo aprox. alineada al centro a la izquierda como en la imagen, exportamos como FlechaPower

2.- OK, una vez realizado estos pasos, vamos a con el AS3, ya tengo preparado un código explicado y se los voy a pegar tal cual, posteriormente les comparto el archivo fla para que lo puedan evaluar y mejorar.
Si alguien tiene alguna duda pregunten, igual no lo se todo y pienso que con la retroalimentacion nos podemos ayudar entre todos y a mejorar lo que hacemos, un saludo afectuoso!!
Código ActionScript :
//importamos un tween y easing que utilizaremos mas adelante
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.*;
/* Creamos 3 movieclips para usar desde la biblioteca asignandole una clase y nombre de instancia: */
//circulo de 50px convertido a movie clip, punto registro al centro, con una flechita en borde superior
var miobjeto:MiObjeto = new MiObjeto();
//circulo de 20px convertido a movie clip, punto registro al centro
var miclip:MiClip = new MiClip();
//flecha de 53px ancho por 30px alto convertido a movie clip, punto registro al centro a la izquierda
var powerDir:FlechaPower = new FlechaPower();
//variable tipo array con la que se creara un nuevo objeto
var objetos:Array = new Array();
//y otra variable "i" con la que le daremos un valor inicial de 0 al array
var i:int=0;
//variables con las que almacenaremos el ancho y alto de nuestro escenario
var stageW:Number = stage.stageWidth;
var stageH:Number = stage.stageHeight;
//variables solo declaradas (mas adelante le daremos un valor)
var peso:Number;//peso del clip a lanzar
var fuerza:Number;//fuerza con que se lanza al clip
var angulo:Number;//angulo de disparo
var angulo_rad:Number;//convertir angulos a radianes
var vx:Number;//velocidad x del clip
var vy:Number;//velocidad y del clip
var rumboX:Number;//rumbo x de la flechaPower
var rumboY:Number;//rumbo y de la flechaPower
var randomObjetoX:Number;//posicion x objeto
var randomObjetoY:Number;//posicion y objeto
//variable que vale la mitad de ancho y alto en pixeles del clip
var radioW:Number = miclip.width/2;
var radioH:Number = miclip.height/2;
//variable para el valor de la friccion constante que sufre la aceleracion
var friccion:Number = .99;
//valor de la gravedad terrestre (redondeado)
var gravedad:Number=10;
var randomNum:Number;//numero random para rotacion de objeto
var randomVel:Number;//velocidad de desplazamiento random del objeto
var randomTime:Number;//tiempo random en milseg que dura el objeto en escena
var anguloObj:Number;//angulo de desplazamiento del objeto
var anguloObj_rad:Number;//conversion a radianes del angulo de desplazamiento del objeto
var vxObj:Number;//velocidad exponencial x del objeto
var vyObj:Number;//velocidad exponencial y del objeto
var tiempo:Timer;//clase timer para la duracion de desplazamiento del objeto
var objetoTw:Tween;//clase tween para ease in u out del objeto
var miClip:MovieClip = MovieClip(miclip);//clase movieclip para colision compleja de clip
var miObjeto:MovieClip = MovieClip(miobjeto);//clase movieclip para colision compleja de objeto
var miclipRect:Rectangle;//clase rectangle para colision de clip
var miclipOffset:Matrix;//clase matrix para colision de clip
var miclipBmpData:BitmapData;//clase bitmapdata para colision de clip
var objetoRect:Rectangle;//clase rectangle para colision de objeto
var objetoOffset:Matrix;//clase matrix para colision de objeto
var miobjetoBmpData:BitmapData;//clase bitmapdata para colision de objeto
var objetoLoc:Point;//punto de colision de objeto
var miclipLoc:Point;//punto de colision de clip
//marcador inicial en 0 dentro del texto dinamico puntos
var score:int = 0;//variable score que inicialmente empieza con 0 de valor y sirve para los puntos
puntos.text = ""+score;//sumamos la variable score al campo de texto dinamico puntos
addChild(powerDir);//agregamos al escenario flechaPower
addChild(miclip);//agregamos al escenario clip
miclip.x = stageW / 2;//acomodamos miclip en medio del escenario
miclip.y = stageH - miclip.height / 2;//acomodamos miclip en el borde de la parte baja
powerDir.scaleX = powerDir.scaleY = .7;//bajamos la escala de la flechaPower
//funcion que mueve angulo de la flecha segun la posicion del raton
function flechaPos(e:Event){
powerDir.x = miclip.x;//centramos la flecha en el centro del clip
powerDir.y = miclip.y;//centramos la flecha en el centro del clip
powerDir.visible = true;//la flecha es visible
rumboX = mouseX - powerDir.x;//valor variable rumboX segun mouseX respecto a posicion flecha x
rumboY = mouseY - powerDir.y;//valor variable rumboY segun mouseY respecto a posicion flecha y
//traducimos el rumbo xy de radianes a grados para rotar flecha, redondeamos la ecuación
powerDir.rotation = int(Math.atan2(rumboY,rumboX) * 180 / Math.PI);
angulo = -powerDir.rotation;//usamos rotacion de flecha para dar valor a angulo de trayecto de clip
angulo_rad = angulo*Math.PI/180;//convertimos angulos a radianes para dar rumbo xy a trayecto de clip
}
//funcion se dispara al presionar boton de raton izq, la flecha da angulo y rumbo segun su ancho
function chekPower(e:Event){
peso = ((miclip.width + miclip.height) / 2) / 100;//usamos las dimensiones de miClip para dar el peso
//incrementamos exponencialmente la escala de la flechaPower mientras el boton izq del raton este DOWN
powerDir.scaleX += .05;
//usamos la escala de la flechaPower para darle un valor a la fuerza (igual pueden usar otro valor)
fuerza = (powerDir.scaleX * powerDir.scaleX) * 15;
//usamos formula newton para calcular velocidad y rumbo xy a la q viajara clip segun peso y fuerza
vx = (fuerza/peso)*Math.cos(angulo_rad);// velocidad = fuerza/peso
vy = (-fuerza/peso)*Math.sin(angulo_rad);//invertimos Y ya que plano cartesiano no corresponde al escenario
//si la escala de la flecha excede cierto tamaño, la regresamos al tamaño que estamos usando
if(powerDir.scaleX >= 2){
powerDir.scaleX = .7;
}
}
//funcion que se ejecuta continuamente cuando soltamos el boton izquierdo del mouse
//con esta funcion haremos el efecto de parabola en miclip
function moverMc(e:Event){
//vamos a redondear todas las operaciones a 2 decimales: Math.round(()*100)/100
//lo haremos asi por que usaremos estas cifras para detener algunos eventos incluyendo este
powerDir.visible = false;//la flecha es NO visible
//esta operacion nos da la gravedad, obviamente la gravedad solo afecta la posicion Y de miClip
vy = Math.round((vy + gravedad)*100)/100;
//como en la funcion flechaPos ya dijimos q vx y vy equivalen al seno y coseno del angulo de rotacion de
//flechaPower, entonces solo redondeamos el valor ya establecido
vy = Math.round((vy)*100)/100;
vx = Math.round((vx)*100)/100;
//ahora usaremos la friccion para darle un efecto mas realista tanto a la parabola como al rebote de miClip
//tambien podemos multiplicar el valor por algun decimal no mayor a 1 para afectar el rebote/friccion de miClip
vx = Math.round((vx*friccion*.8)*100)/100;
vy = Math.round((vy*friccion*.8)*100)/100;
//la posicion x Y de miClip la establecemos asi, para evitar que el movimiento se vea interrumpido por
//la repeticion del evento, aparte si no le damos un valor de posicion x y a miClip este no se movera
miclip.x = miclip.x + vx;
miclip.y = miclip.y + vy;
//detenemos este evento, el valor de 4.4 puede variar si cambiamos cualquier valor de gravedad o friccion
if(vy == 4.4){
miclip.removeEventListener(Event.ENTER_FRAME,moverMc);//miClip deja de moverse
stage.addEventListener(MouseEvent.MOUSE_UP,upBtn);//add evento Mouse UP
stage.addEventListener(MouseEvent.MOUSE_DOWN,downBtn);//add evento Mouse DOWN
addEventListener(Event.ENTER_FRAME,flechaPos);//add evento flechaPos
powerDir.scaleX = .7;//regresamos la flecha a la escala inicial
}
//con este trace podemos saber los valores de Y que se repiten cuando deja de botar el miClip
//asi usamos este valor en un if == para poder detener el evento
trace("velocidadY:"+vy);
//con esta serie de if elseif registramos los bordes del escenario donde rebotara miClip
if(miclip.y+radioH > stageH){
miclip.y=stageH-radioH;
vy=vy*-1;
}
else if(miclip.y-radioH<0){
miclip.y=radioH;
vy=vy*-1;
}
if(miclip.x+radioW>stageW){
miclip.x=stageW-radioW;
vx=vx*-1;
}
else if(miclip.x-radioW<0){
miclip.x=radioW;
vx=vx*-1;
}
cheka();//funcion que evalua constantemente si miClip y el objeto chocan mientras miClip se mueve
}
//funciones que usaremos para dar un valor mínimo y máximo para conseguir varios valores aleatorios
//posición X aleatoria del objeto
function minmaxObjetoX( min:Number, max:Number ):Number {
return int(min + (max - min) * Math.random());
}
//posición Y aleatoria del objeto
function minmaxObjetoY( min:Number, max:Number ):Number {
return int(min + (max - min) * Math.random());
}
//rotación aleatoria del objeto
function minmaxNum( min:Number, max:Number ):Number {
return int(min + (max - min) * Math.random());
}
//velocidad aleatoria del objeto
function minmaxVel( min:Number, max:Number ):Number {
return int(min + (max - min) * Math.random());
}
//tiempo aleatorio que dura el objeto en escena entre uno y otro objeto
function minmaxTime( min:Number, max:Number ):Number {
return int(min + (max - min) * Math.random());
}
//con esta función haremos que el objeto aparezca en un lugar XY aleatorio con una velocidad aleatoria //y con una trayectoria, por supuesto también aleatoria cada determinado //tiempo también aleatorio, //igual podrían determinar los valores como fijos, yo preferí hacerlo así
clonar();
function clonar():void{
randomNum = minmaxNum(-179,179);//el valor de rotación rad de un objeto es de -179 a 179 no de 0 a 360
randomVel = minmaxNum(10,20);//el valor de velocidad tiene que ver con los pixeles, de 10 a 20 px en mi caso
randomTime = minmaxNum(2000,5000);// la velocidad es en milisegundos, 1000 mlseg equivalen a 1 segundo
anguloObj = -randomNum;//invertimos valor de angulo de rotación para que corresponda a la del objeto
anguloObj_rad = anguloObj*Math.PI/180;//convertimos ángulos a radianes para trayecto de objeto
//usamos los radianes para darle rumbo y velocidad x y al objeto
vxObj = randomVel * Math.cos(anguloObj_rad);
vyObj = randomVel * Math.sin(anguloObj_rad);
addChild(miobjeto);//agregamos el objeto al escenario
objetos.push(miobjeto);//disparamos el array para que haga un objeto nuevo
//damos valor a las variables de posicion x y del objeto, de tal manera que el objeto no quede fuera
//de los bordes del escenario
randomObjetoX = minmaxObjetoX(miobjeto.width,stageW - miobjeto.width);
randomObjetoY = minmaxObjetoY(miobjeto.height,stageH - miobjeto.height);
//usamos la variable de tipo timer para crear un tiempo con el que cambiaremos de manera aleatoria
//la posicion y trayectoria x y del objeto cada cierto tiempo, tambien aleatorio
tiempo = new Timer(randomTime, 1);//el timer tiene tiempo aleatorio, solo se usa una vez
tiempo.start();//empezamos el timer
tiempo.addEventListener(TimerEvent.TIMER_COMPLETE,cambiar);//cuando timer termina cambiar
//con este for creamos una cantidad infinita de objetos ya q i siempre es menor a longitud de los objetos
for(i=0; i<objetos.length; ++i){
objetos[i].x = randomObjetoX;//la posicion x del objeto es aleatoria
objetos[i].y = randomObjetoY;//la posicion y del objeto es aleatoria
//tween IN de alpha cada que se cree un objeto nuevo
objetoTw = new Tween(objetos[i], "alpha", Strong.easeInOut, 0, 1, 1, true);
addEventListener(Event.ENTER_FRAME,siempre);
}
}
//funcion que continuamente cheka que el objeto no pase de los bordes del escenario, y cuando lo hace
//rebota en trayectoria proporcionalmente inversa
function siempre (e:Event):void{
//la trayectoria x y del objeto corresponde a su angulo de rotacion
miobjeto.x = miobjeto.x + vxObj;
miobjeto.y = miobjeto.y + vyObj;
//el objeto tambien rota con respecto a su trayectoria
miobjeto.rotation = int(Math.atan2(vxObj,-vyObj) * 180 / Math.PI);
//con esta serie de if elseif registramos los bordes del escenario donde rebotara el objeto
if(miobjeto.y+(miobjeto.height/2) > stageH){
miobjeto.y=stageH-(miobjeto.height/2);
vyObj=vyObj*-1;
}
else if(miobjeto.y-(miobjeto.height/2)<0){
miobjeto.y=miobjeto.height/2;
vyObj=vyObj*-1;
}
if(miobjeto.x+(miobjeto.width/2)>stageW){
miobjeto.x=stageW-(miobjeto.width/2);
vxObj=vxObj*-1;
}
else if(miobjeto.x-(miobjeto.width/2)<0){
miobjeto.x=miobjeto.width/2;
vxObj=vxObj*-1;
}
}
// funcion de tipo timer que se ejecuta cuando se termina el timer, dispara un easeOUT del objeto
function cambiar (e:TimerEvent):void{
objetoTw = new Tween(miobjeto, "alpha", Strong.easeInOut, 1, 0, 1, true);
//cuando se termine el easeOUT se ejecuta vadenuez
objetoTw.addEventListener(TweenEvent.MOTION_FINISH,vadenuez);
}
//funcion de tipo tween con la que detenemos el listener del timer y clonamos un nuevo objeto
function vadenuez(e:TweenEvent):void{
tiempo.reset();//damos reset al timer
tiempo.removeEventListener(TimerEvent.TIMER_COMPLETE,cambiar);//borramos listener de timer
removeEventListener(Event.ENTER_FRAME,siempre);//borramos evento siempre
clonar();//funcion clonar
}
//funcion con la que registraremos las colisiones entre miClip y el objeto
function cheka ():void{
puntos.text = ""+score;//el marcador siempre se actualizara con el valor del score
miclipRect = miClip.getBounds(this);//obtener limites del rectangulo delimitado de miClip
miclipOffset = miclip.transform.matrix;//transformar la matriz de miClip
miclipOffset.tx = miclip.x - miclipRect.x;//offset de transfX de miClip menos su rect delimitador
miclipOffset.ty = miclip.y - miclipRect.y; //offset de transfY de miClip menos su rect delimitador
//la colision compleja requiere parametros de bitmapdata, con esto pasamos del cuadro delimitador
//a los bordes de miClip
miclipBmpData = new BitmapData(miclipRect.width, miclipRect.height, true, 0);
miclipBmpData.draw(miclip, miclipOffset);
//hacemos igual para el objeto
objetoRect = miobjeto.getBounds(this);
miobjetoBmpData = new BitmapData(objetoRect.width, objetoRect.height, true, 0);
objetoOffset = miobjeto.transform.matrix;
objetoOffset.tx = miobjeto.x - objetoRect.x;
objetoOffset.ty = miobjeto.y - objetoRect.y;
miobjetoBmpData.draw(miobjeto, objetoOffset);
//con estas variables registramos la colision entre dos puntos
objetoLoc = new Point(objetoRect.x, objetoRect.y);
miclipLoc = new Point(miclipRect.x, miclipRect.y);
//usamos if para chekar las condiciones de la colision de la siguiente manera
if(miobjetoBmpData.hitTest(objetoLoc,255,miclipBmpData,miclipLoc,255)){
//use un filtro glow en ambos clips, si dejamos vacios los parametros nos da valores default
miclip.filters = [new GlowFilter()];
miobjeto.filters = [new GlowFilter()];
miobjeto.scaleX = miobjeto.scaleY = 1.2;//ademas escalamos el objeto para apreciar mejor la colision
score = fuerza+score;
}
//mientras no se produzca colision alguna, vaciamos los clips de los filtros usados y devolvemos al objeto
//su escala original
else
{
miclip.filters = [];
miobjeto.filters = [];
miobjeto.scaleX = miobjeto.scaleY = 1;
}
miclipBmpData.dispose();//deshechamos bitmap para que no ocupe memoria de mas
miobjetoBmpData.dispose();//deshechamos bitmap para que no ocupe memoria de mas
}
//agregamos funciones de boton al escenario o stage
//funcion del boton izquierdo del mouse cuando esta DOWN
function downBtn(e:Event){
//mientras el botón izq. del mouse este abajo, se va a ejecutar el evento chekPower
powerDir.addEventListener(Event.ENTER_FRAME,chekPower);
}
//funcion del boton izquierdo del mouse cuando esta UP
function upBtn(e:Event){
/* al soltar el botón izq. del mouse eliminaremos el evento que cheka la posición de la flecha así como el evento que se ejecuto al estar el botón izq. del mouse abajo que cheka la fuerza, ademas eliminamos los eventos de los botones mouse UP o DOWN para que no interfieran durante la trayectoria de miClip, solo quedara entonces agregar el listener que permita el movimiento de miClip
*/
removeEventListener(Event.ENTER_FRAME,flechaPos);
powerDir.removeEventListener(Event.ENTER_FRAME,chekPower);
stage.removeEventListener(MouseEvent.MOUSE_DOWN,downBtn);
stage.removeEventListener(MouseEvent.MOUSE_UP,upBtn);
miclip.addEventListener(Event.ENTER_FRAME,moverMc);
}
//por ultimo los listeners que se van a ejecutar al inicar la pelicula
addEventListener(Event.ENTER_FRAME,flechaPos);
stage.addEventListener(MouseEvent.MOUSE_UP,upBtn);
stage.addEventListener(MouseEvent.MOUSE_DOWN,downBtn);Archivo Flash (CS4)
Archivo FLA
Ya al final pueden cambiar los objetos por imágenes png y verán el resultado de la colisión compleja, lo único que falto agregar seria que la piedra también rotara según donde rebote y su fuerza.
