Se acabaron mis vacaciones, empieza una nueva etapa Porque no sólo de webs vive Flash…
jul 11

Leyendo un post de EzeQl, me animé a postear una clase para la creación de botones que desarrolle hace tiempo, y que uso tropecientas veces en todos mis proyectos. Creo que es bastante completa y escalable. Casi siempre la uso tal cuál, pero es muy fácil extender su funcionalidad en caso de necesitarlo.

Características:

  • Estados basados en línea de tiempo (aunque también se pueden implementar con código). Se diseña la animación en un solo sentido, que se recorre en el estado “over”. Al hacer un “out” automáticamente la animación se reproducirá hacia atrás.
  • Solo hay que configurar dos estados. Estado out y over. Cuando tengo una botonera y quiero que uno se quede pulsado lo dejo en “over”. De esta manera me libro del estado “pressed” o “down”.
  • Soporte para sonidos de alguna o todas las acciones de botón: click, over, out (se pasan por parámetro en el constructor)
  • Se puede habilitar y deshabilitar el botón
  • Complétamente integrado con la clase Menú (mi clase menú que postearé otro día)
  • Aspecto gráfico y animación (asset) totalmente separado de la lógica del botón (se pasa un MovieClip por parámetro en el constructor)
  • Eventos: este botón avisa de todo lo que hace mediante eventos (OVER, RELEASE, OUT, SELECTED, UNSELECTED, ENABLED, DISABLED, NOSTATE).

Ejemplo de diseño de línea de tiempo:

Solo hace falta hacer una animación en un solo sentido y con un stop() en las acciones del primer fotograma. Todo ello metido dentro de un MovieClip que tendrémos vinculado en la biblioteca o simplemente con un nombre de instancia en el escenario. En estas imágenes se ven los fotogramas clave de la animación. Solo tiene una simple animación de “tinta” de azul a verde:

Para un ejemplo simple nos sirve con esto. Simplemente un “asset” (movieClip) que utilizará nuestra clase botón. Supongamos que lo tenemos vinculado en la biblioteca:

Ahora nos podemos cargar el botón del escenario, ya que solo necesitamos usar su vinculación.

De esta forma separamos el código del gráfico o “asset” que representará nuestro botón. Creo que es una buena manera de hacerlo, y aquí va la clase botón que he llamado de forma genérica “ItemButton”, puede parecer compleja pero es muy simple, fijaros simplemente en los métodos públicos para haceros una idea, creo que hablan por sí solos:

package net.xinterface.items
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.media.Sound;
 
	public class ItemButton extends Sprite
	{
		public static const OVER:String = "over";
		public static const RELEASE:String = "release";
		public static const OUT:String = "out";
		public static const SELECTED:String = "selected";
		public static const UNSELECTED:String = "unselected";
		public static const ENABLED:String = "enabled";
		public static const DISABLED:String = "disabled";
		public static const NOSTATE:String = "nostate";
 
		private var id:String;
 
		protected var hit_mc:MovieClip;
		public var asset:MovieClip;
 
		private var volume:Number = 1;
		private var sClick:Sound;
		private var sOver:Sound;
		private var sOut:Sound;
 
		private var state:String;
 
		// constructor
		public function ItemButton(_asset:MovieClip, soundClick:Sound=null, soundOver:Sound=null, soundOut:Sound=null)
		{
			asset = _asset;
			addChild(asset);
 
			if(MovieClip(asset.hit_mc) != null)
			{
				hit_mc = MovieClip(asset.hit_mc);
 
			}else
			{
				hit_mc = new MovieClip;
				hit_mc.graphics.beginFill(0x000000,0);
				hit_mc.graphics.drawRect(0,0,asset.width, asset.height);
 
				asset.addChild(hit_mc);
			}
 
			hit_mc.buttonMode = true;
			sClick = soundClick;
			sOver = soundOver;
			sOut = soundOut;
 
			state = NOSTATE;
 
			Enable();
		}
		// Habilita el botón (se puede pulsar)
		public function Enable():void
		{
			hit_mc.enabled = true;
			hit_mc.mouseEnabled = true;
			hit_mc.addEventListener(MouseEvent.CLICK, Click);
			hit_mc.addEventListener(MouseEvent.MOUSE_OVER, Over);
			hit_mc.addEventListener(MouseEvent.MOUSE_OUT, Out);
			asset.alpha = 1;
			state = ENABLED;
		}
		// Deshabilita el botón ( no se puede pulsar )
		/** @param setAlpha true para bajar el alpha al deshabilitarlo, false para dejarlo tal cuál
		 * @param keepClick true para que el botón siga funcionando incluso al deshabilitarlo, false para un comportamiento normal (esto me ha servido el alguna ocasión
		 * */
		public function Disable(setAlpha:Boolean=true, keepClick:Boolean=false):void
		{
			hit_mc.enabled = false;
			//hit_mc.mouseChildren = false;
			hit_mc.mouseEnabled = false;
 
			if(keepClick==true) hit_mc.mouseEnabled = true;
			else hit_mc.removeEventListener(MouseEvent.CLICK, Click);
 
			hit_mc.removeEventListener(MouseEvent.MOUSE_OVER, Over);
			hit_mc.removeEventListener(MouseEvent.MOUSE_OUT, Out);
 
			if(setAlpha) SetDisableView();
			state = DISABLED;
		}
		protected function SetDisableView():void
		{
			asset.alpha = 0.3;
		}
		// Esto es público por si acaso queremos presionar un botón manualmente. "boton.Click(null);"
		public function Click(evt:MouseEvent=null):void
		{
			var event:Event = new Event(RELEASE);
			dispatchEvent(event);
			if(sClick!=null) sClick.play().soundTransform.volume = volume;
			state = RELEASE;
		}
		protected function Over(evt:MouseEvent=null):void
		{
			//trace("over");
			dispatchEvent(new Event(OVER));
			asset.removeEventListener(Event.ENTER_FRAME, TimelineBackard);
			asset.addEventListener(Event.ENTER_FRAME, TimelineFordward);
			if(sOver!=null) sOver.play().soundTransform.volume = volume;
			state = OVER;
		}
		protected function Out(evt:MouseEvent=null):void
		{
			//trace("out");
			dispatchEvent(new Event(OUT));
			asset.removeEventListener(Event.ENTER_FRAME, TimelineFordward);
			asset.addEventListener(Event.ENTER_FRAME, TimelineBackard);
			if(sOut!=null) sOut.play().soundTransform.volume = volume;
			state = OUT;
		}
		// Este método es perfecto para botoneras, al llamarlo, el botón de quedará en el estado "over",
		// y no se podrá pulsar hasta después de llamar al método "Unselect();"
		public function Select():void
		{
			if(state == SELECTED) return;
 
			Disable(false);
			dispatchEvent(new Event(SELECTED));
			Over();
			state = SELECTED;
			//trace("selected");
		}
		// vuelve a dejar el botón como estaba
		public function Unselect():void
		{
			if(state == UNSELECTED) return;
 
			Enable();
			dispatchEvent(new Event(UNSELECTED));
			Out();
			state = UNSELECTED;
			//trace("unselected");
		}
		// Timeline
		// Hace correr la línea de tiempo del "asset" hasta el último frame
		private function TimelineFordward(evt:Event):void
		{
			asset.gotoAndStop(asset.currentFrame + 1);
			if(asset.currentFrame == asset.totalFrames) asset.removeEventListener(Event.ENTER_FRAME, TimelineFordward);
		}
		// Hace correr hacia el frame 1, la línea de tiempo del "asset"
		private function TimelineBackard(evt:Event):void
		{
			asset.gotoAndStop(asset.currentFrame - 1);
			if(asset.currentFrame == 1) asset.removeEventListener(Event.ENTER_FRAME, TimelineBackard);
		}
 
		// getters y setters
		public function get State():String
		{
			return state;
		}
		public function set Volume(value:Number):void
		{
			volume = value;
		}
		public function get Volume():Number
		{
			return volume;
		}
		public function get Id():String
		{
			return id;
		}
		public function set Id(pId:String):void
		{
			id = pId;
		}
	}
}

Podéis descargar la clase ItemButton aquí

Para usar esta clase con el ejemplo de asset mostrado anteriormente:

// Pillamos el asset vinculado en la librería
var assetGrafico:MovieClip = new asset() as MovieClip;
 
// Creamos el botón y lo añadimos al displayList, fíjate que no añadimos el asset al displayList
// puesto que el botón lo hace automáticamente.
var boton:ItemButton = new ItemButton(assetGrafico);
addChild(boton);
 
// Nos subscribimos a los eventos
boton.addEventListener(ItemButton.RELEASE, HandleRelease);
boton.addEventListener(ItemButton.OVER, HandleOver);
boton.addEventListener(ItemButton.OUT, HandleOut);
 
// Administramos eventos
private function HandleRelease(e:Event):void
{
	trace("hemos hecho click en la instancia de botón", e.target);
}
 
private function HandleOver(e:Event):void
{
	trace("hemos hecho over en la instancia de botón", e.target);
}
 
private function HandleOut(e:Event):void
{
	trace("hemos hecho out en la instancia de botón", e.target);
}

Y ya solo queda probar la clase con distintos assets gráficos, que pueden ser completamente distintos al que habéis visto, siempre que mantegan su estructura. No olvidéis que también funcionan los sonidos para los estados over, out, y release.

También comentar que como instrumento fundamental y control de cualquier aplicación, necesitamos un menú, que no es más que un controlador de una lista o array de botones. En mi caso tengo una clase “Menu” que hace uso de la clase “ItemButton”, y se encarga de gestionar cuándo los botones de activan o desactivan, según en cuál de ellos pinche el usuario. Tal vez me anime y lo postee, pero eso será después de la publicidad.

Un saludo

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • E-mail this story to a friend!
  • LinkedIn
  • Meneame
  • MySpace
  • Netvibes
  • Ping.fm
  • Print this article!
  • Technorati
  • TwitThis

2 Responses to “AS3: clase botón”

  1. renton Says:

    Hola, me parece que no esta muy bien explicado este tutorial…

  2. Jona Says:

    Gracias por el aporte!.. te comento que apenas estoy comenzando con as3, y
    tengo dudas en como trabajar con clases, como mandar a llamar una en otra … quizas eso es lo que hallas utilizado para formar la clase menu ¿Como hiciste la clase menu que gestione esta de butomItem?

Leave a Reply