Gracias a la genial as3isolib podemos crear entornos isométricos con ActionScript 3 en Flash o Flex. La Perspectiva Isométrica – conocida por todos gracias a videojuegos clásico como Los Sims – pese a no ser un 3d real, es una manera muy efectiva de representar un mundo en tres dimensiones, lo cual es una herramienta muy útil para videojuegos o representaciones.
Durante este post vamos a aprender los inicios de crear un entorno isométrico con esta librería mediante un ejemplo práctico 😉
Perspectiva isométrica del videojuego Los Sims
as3isolib
as3isolib, una librería open-source para ActionScript 3 desarrollada para (en palabras de su autor) «asistir en la creación de contenido en proyección isométrica». Aunque está en desarrollo la nueva versión (v2) de la librería con bastantes jugosas novedades, por lo visto ésta dejará de ser open-source. En este ejemplo hemos utilizado la versión estable actual (v1) totalmente gratuita.
Ejemplo en funcionamiento: Añade elementos, selecciona, draguea y rota
Vamos a ver paso a paso cómo hemos construido este ejemplo. El código es relativamente simple pero contiene ciertos elementos de complejidad debidos al uso de la librería, como por ejemplo creación de elementos gráficos en isométrico a partir de assets (imágenes), y posteriormente aplicarles efectos y manipularlos utilizando coordenadas isométricas.
Elementos Gráficos: IsoSimpleAsset
Por comodidad y para una mejor encapsulación del código, en este ejemplo hemos creado una clase IsoSilla que heredará de una clase IsoSimpleAsset que a su vez extienda sobre IsoSprite, que es la clase base de los elementos gráficos en as3isolib. Esta clase IsoSimpleAsset será la base de todos nuestros elementos, si quisiéramos tener otros elementos cualquiera distintos por ejemplo mesas o más mobiliario con comportamiento similar pero cuyo aspecto gráfico sea diferente tan sólo tendríamos que crear nuevas clases que extiendan sobre ésta.
import as3isolib.display.IsoSprite; public class IsoSimpleAsset extends IsoSprite
Para el aspecto de nuestro elemento gráfico tenemos que fijarnos en la propiedad sprites de IsoSprite, teniendo en cuenta que es un Array con lo cual tenemos que asignarle un objeto del tipo Array. Dentro de este array incluiremos todos los DisplayObject que queramos que conformen su aspecto gráfico. Normalmente, tan sólo será un elemento, en nuestro caso el dibujo de la silla en una orientación concreta. Por ejemplo:
//mc con los elementos gráficos var mcDibujo:MovieClip; //miAsset es un objeto de la case IsoSimpleAsset //que hereda de IsoSprite miAsset.sprites = new Array(mcDibujo);
Para conformar la ilusión de que rotamos la silla girando en perspectiva isométrica, simplemente reasignamos esta propiedad sprites a otro dibujo de la silla en otra orientación. Es muy importante el posicionamiento de los elementos gráficos para el correcto funcionamiento del motor de profundidades de as3isolib. Los gráficos deben de posicionarse de forma que el punto de origen del MovieClip se sitúe sobre la esquina superior de una «base» imaginaria en isométrico sobre la que se sitúa el elemento. En este tutorial de la propia web de as3isolib se explica más detalladamente. Por ejemplo, en el caso de las cuatro vistas que van a formar los sprites gráficos de nuestra silla, fijaos en el origen de coordenadas de cada uno de los MovieClips:
Para marcar el elemento seleccionado hemos utilizado simplemente uno de los filtros nativos de Flash, un GlowFilter. Para añadir este efecto a nuestro elemento isométrco debemos ir a la propiedad container de IsoSprite, que es un objeto del tipo Sprite de toda la vidaque contiene todos sus elementos gráficos. Al igual que la propiedad sprites, los filtros se almacenan en un Array para poder aplicar más de un filtro sobre el elemento gráfico. Para desactivar el brillo simplemente le asignamos null o un array vacío .
//Brillo verde var glow:GlowFilter = new GlowFilter(0x00FF00, 1, 5, 5, 5); //activamos glow miSimpleIsoAsset.container.filters = new Array(glow); //desactivamos glow miSimpleIsoAsset.container.filters = null;
En nuestro ejemplo, hemos encapsulado estos comportamientos en métodos dentro de la clase IsoSimpleAsset, podéis ver el código entero de la clase si descargáis el código fuente del ejemplo.
public function select():void { //... } public function unselect():void { //... } public function changeView():void { //... }
La Escena Isométrica
Para «inicializar» el motor isométrico, creamos una variable del tipo IsoView que será la vista que controle todo nuestros elementos isométricos. Esta variable hereda de DisplayObject, con lo que se añade mediante addChild a nuestra escena principal. Sobre la vista añadimos una escena IsoScene, que será la que contenga los elementos isométricos en sí. Para que se muestren los elementos isométricos la escena debe renderizarlos mediante el método render, puesto que normalmente nuestra escena no es estática este método conviene situarlo dentro de un EnterFrame para que se ejecute continuamente.
private var viewPort:IsoView; private var scene:IsoScene; private function setIso():void { //creamos vista y la configuramos viewPort = new IsoView(); viewPort.showBorder=false; viewPort.setSize(539, 400); addChild(viewPort); //creamos escena scene = new IsoScene(); //y la añadimos a la vista viewPort.addScene(scene); //creamos un grid y lo añadimos a la escena //para referencia var grid:IsoGrid = new IsoGrid(); grid.setGridSize(5,5,0); grid.cellSize = 35; grid.showOrigin=true; grid.stroke = new Stroke(1,0x999999,1); scene.addChild(grid); //enterframe principal addEventListener( Event.ENTER_FRAME, enterFrame_handler); } private function enterFrame_handler(e:Event):void { //renderizamos escena scene.render(); }
Añadimos elementos isométrico a la escena simplemente con addChild, por ejemplo en nuestro caso queremos que el manejador del evento CLICK del botón añada un elemento silla a la escena, y a continuación lo seleccione para que quede marcado:
public function add_click_handler(e:MouseEvent):void { var o:IsoSimpleAsset = new IsoSilla(); addObject(o); selectObject(o); } public function addObject(o:IsoSimpleAsset):void { //añadimos elemento a la escena scene.addChild(o); //lo vamos a situar sobre el grid //en el centro de la pantalla o.moveTo(170,170,100); //añadimos interactividad o.addEventListener( MouseEvent.MOUSE_DOWN, pickup_handler); } private var selectedObject:IsoSimpleAsset=null; public function selectObject(o:IsoSimpleAsset):void { if(selectedObject!=null) selectedObject.unselect(); o.select(); selectedObject = o; }
Para dragear el objeto isométrico, la clave es el método localToIso de la clase IsoView que convierte las coordenadas locales de Flash a coordenadas isométricas. Este método recibe como parámetro (y posteriormente devuelve) un objeto de la case Pt, que no es más que un punto con tres coordenadas x, y, z necesarias para simular las 3 dimensiones de la vista isométrica.
/** * DRAG OBJECT */ private var dragPt:Pt; private var dragObject:IsoSimpleAsset; private function pickup_handler(e:Event):void { //almacenamos el elemento dragObject = IsoSimpleAsset(e.target); //marcamos el elemento como seleccionado selectObject(dragObject); //almacenamos el punto //en coordenadas isométricas dragPt = viewPort.localToIso( new Pt(stage.mouseX, stage.mouseY) ); //ajustamos punto //según la posición del elemento dragPt.x -= dragObject.x; dragPt.y -= dragObject.y; dragPt.z -= dragObject.z; //cleanup listener dragObject.removeEventListener(MouseEvent.MOUSE_DOWN, pickup_handler); //añadimos listeners necesarios //mouse up en el stage "por si" stage.addEventListener(MouseEvent.MOUSE_UP, drop_handler); //al mover el mouse viewPort.addEventListener(MouseEvent.MOUSE_MOVE, drag_handler); } private function drop_handler(e:Event):void { //clean up events stage.removeEventListener(MouseEvent.MOUSE_UP, drop_handler); viewPort.removeEventListener(MouseEvent.MOUSE_MOVE, drag_handler); //resetear drag dragObject.addEventListener(MouseEvent.MOUSE_DOWN, pickup_handler); } private function drag_handler(e:MouseEvent):void { //convertimos coordenadas del mouse a isométricas var pt:Pt = viewPort.localToIso( new Pt(stage.mouseX, stage.mouseY) ); //calcular punto al que nos hemos desplazado var x_to:Number = Math.round(pt.x - dragPt.x); var y_to:Number = Math.round(pt.y - dragPt.y); //mover elemento dragObject.moveTo(x_to, y_to, dragObject.z); } /** * END DRAG */
Para seguir profundizando en esta librería podemos ver un ejemplo bastante similar (en inglés) en active tuts+, aunque está un poco outdated. También por supuesto todos los tutoriales «oficiales» en la propia página de la librería que aunque son muy básicos, son bastante completos y detallados, y pueden servir como para servir de punto de partida para cualquier proyecto que queramos hacer en isométrico.
Utilizado en: Helados Alacant. Heladería IsoBuilder
Éstos fueron los inicios de nuestro último proyecto para la conocida marca de helados Helados Alacant. El motor de elementos y mobiliario está basado en este código que os hemos presentado.
Gracias por este gran aporte, es una gran ayuda para quien apenas esta aprendiendo a manejar esta libreria, me gustaria saber si saben donde puedo encontrar mas ayuda acerca de este tema?
Gracias por todo!
Buenas Camilo y gracias por el comentario! Mira, aparte de los tutoriales oficiales (que están bastante bien) http://code.google.com/p/as3isolib/w/list los archivos del propio blog de la librería son una excelente fuente de información: http://as3isolib.wordpress.com/ y también tienes el user group: http://tech.groups.yahoo.com/group/as3isolib/ donde podrás obtener ayuda más personalizada.
Suerte!
Hola estoy siguiendo este ejemplo para realizar algo similar, pero tengo problemas para agregar otro elemento, se como generar los .swc pero que movieclip deben incluir y como o cuando se hace referencia a este archivo. Gracias esta es muy buena informacion.
Por favor, necesito saber como puedo eliminar un objeto que inserte anteriormente y que no quiero que aparezca.
Gracias
Hola ya puedo agregar todos los objetos que quiero, solo tengo un problema, el primer objeto que inserto siempre esta por encima de los de todos los demas, el codigo no marca error pero no esta funcionando, este es el codigo:
var children:Array=scene.displayListChildren;///trae todos los elementos
var maxChildrens:uint = children.length;//total de elemetos
if(selectedObject) //si hay un elemeto seleccionado
{
selectObject(selectedObject);//objeto seleccionado
var objetIndex:Number=scene.getChildIndex(selectedObject);//el index del objeto seleccionado
for(var i:uint=0; i < maxChildrens; i++){//recorro los elementos dentro de la scena
var objA:IsoDisplayObject=children[i];
//si el objeto actual es el mismo al seleccionado
if(scene.getChildIndex(objA)==objetIndex){
scene.setChildIndex(objA, maxChildrens-1);//cambia el index del objeto
}
}
}