Entornos isométricos en Flash con as3isolib

danii . Domingo 25 de marzo de 2012. a las 20:30

entornos-isometricos-flash-as3isolib

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
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.

as3isolib

Ejemplo en funcionamiento: Añade elementos, selecciona, draguea y rota

Get Adobe Flash player

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:

Posicionamiento gráficos en IsoAsset

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.

Helados Alacant Heladería IsoBuilder as3lib isométrica

Etiquetas: , , , ,

5 Comentarios
» Feed RSS de los Comentarios

  1. Camilo dice:

    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!

  2. danii dice:

    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!

  3. nes dice:

    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.

  4. Roberto dice:

    Por favor, necesito saber como puedo eliminar un objeto que inserte anteriormente y que no quiero que aparezca.

    Gracias

  5. nes dice:

    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
    }

    }
    }

Enviar comentario