En este tutorial, haremos un temporizador de cuenta regresiva reutilizable con una fecha objetivo dinámica que se puede configurar a través de XML. Animaremos los números que se mueven hacia abajo al estilo de un antiguo aeropuerto o tabla de estado de la estación de tren. Cubriremos código, creación de gráficos y animación..
Tutorial republicadoCada pocas semanas, revisamos algunas de las publicaciones favoritas de nuestros lectores de toda la historia del sitio. Este tutorial se publicó por primera vez en mayo de 2010..
Cree un nuevo archivo Flash (Actionscript 3) con estos ajustes: 500x300, fondo negro y 30 fps.
Cree un nuevo clip de película llamado 'digit_bottom' y dibuje un rectángulo redondeado en su interior de aproximadamente 36px de ancho por 50px de alto. (Una forma rápida de dibujar un rectángulo con dimensiones precisas es seleccionar la herramienta Rectángulo y hacer clic con la tecla Alt presionada en el escenario).
Dale al rectángulo un relleno degradado de # 111111 (arriba) a # 333333 (abajo) y un contorno de 2 px de color # 333333.
Coloque el rectángulo de modo que el punto de registro de MovieClip (el pequeño '+') esté exactamente a medio camino entre el borde superior e inferior y el borde izquierdo. Si hiciste tu rectángulo 50px de altura, entonces el valor de y debería ser -25.
Cree una nueva capa y agregue un campo de texto dinámico llamado 't_num'. Elija una fuente que tenga la sensación de una estación de tren o aeropuerto (como Helvetica, DIN o Interstate). Estoy usando Helvetica Bold.
Establezca el Formato de párrafo en centrado y recuerde incrustar las fuentes para los números 0-9.
Posiciona el campo de texto para que esté centrado en el rectángulo de fondo..
Vamos a utilizar este MovieClip como base para otro gráfico, así que tómate un momento para asegurarte de que se vea bien.
Crear una nueva capa en la línea de tiempo del digit_bottom MovieClip y llamarlo 'máscara'. Copie el rectángulo redondeado y pegue en su lugar en la máscara capa (Edición> Pegar en lugar, o Comando-Shift-V).
Seleccione la mitad superior del rectángulo de la máscara y elimínelo.
Haga clic derecho en el máscara capa, elija Máscara y asegúrese de que esté enmascarando todas las capas debajo de ella.
Ve a la biblioteca, duplica la digit_bottom MovieClip y el nombre de la nueva copia 'digit_top'.
Este MovieClip será virtualmente idéntico al digit_bottom clip, excepto que la máscara mostrará la mitad superior de los gráficos en lugar de la parte inferior.
Eliminar los gráficos actualmente en la máscara capa. Copie el rectángulo redondeado y vuelva a pegar en el lugar máscara capa. Esta vez selecciona la mitad inferior y elimínala..
El único otro ajuste que podría querer hacer aquí es ajustar el color del texto y el sombreado del rectángulo redondeado de fondo. Hice los gráficos en mi digit_top Clip un poco más oscuro para simular la luz que viene de la parte superior.
Crea un nuevo clip de película llamado 'Dígito'. Arrastrar en el digit_top y digit_bottom MovieClips y posicionarlos a los 0,0. Dales los nombres de instancia 'top1' y 'bottom1'.
Ahora copia ambos MovieClips (digit_top y digit_bottom), cree una nueva capa y pegue en lugar una copia de cada uno. Nombra las nuevas copias 'top2' y 'bottom2'.
Ahora deberías tener 4 MovieClips dentro de tu Dígito Clip de película: 2 copias de digit_top y 2 copias de digit_bottom. Explicaré por qué lo estamos configurando así en el próximo paso..
Tenemos que hacer un poco de trucos de animación para obtener el efecto de números que queremos. Eche un vistazo al siguiente diagrama de nuestra Dígito MovieClip (lo estoy renderizando en 3D solo para que puedas ver las capas más fácilmente):
Comenzamos con el bottom2 clip volteado boca abajo (usando la propiedad scaleY) y colocado detrás del top2 acortar. En este punto los 2 clips que son visibles son top2 y bottom1. Los números en estos dos clips se corresponden entre sí, por lo que forman un dígito completo.
Ahora damos vuelta la top2 clip al centro del dígito. En este punto, scaleY será cero, por lo que el clip no será visible. Al mismo tiempo, también estamos volteando hacia abajo la bottom2 clip, pero este vamos a voltear todo el camino hacia el fondo. Ya que esta detras top2, no se mostrará hasta que pase el punto medio. Ahora los 2 clips visibles son top1 y bottom1. Los números en estos dos clips no coinciden, pero está bien porque este paso solo dura un breve momento.
los top2 clip permanece en el centro como bottom2 Sigue cayendo hasta el fondo. Una vez que está en su lugar los números en los clips visibles (top1 y bottom2) de nuevo coincide para formar un dígito completo.
En este punto, vamos a relayer y restablecer las posiciones de los 2 clips ocultos para prepararnos para el próximo giro. Observe cómo los clips están en las mismas posiciones que en el Paso 1, solo invertido.
Ahora que tenemos el individuo Dígito MovieClip configurado, vamos a construir el reloj.
Cree un nuevo MovieClip en el escenario llamado 'Reloj' con el nombre de instancia 'reloj'. Dentro del nuevo MovieClip coloca 9 copias de tu Dígito MovieClip; 2 para segundos, 2 para minutos, 2 para horas y 3 para días. Dale a cada dígito un nombre de instancia. De izquierda a derecha, nómbrelos 'dígitos0', 'dígitos1', 'dígitos2', etc..
Agregue algunos dos puntos para separar los MovieClips y las etiquetas de cada sección. El diseño depende de ti. Agregué un rectángulo redondeado oscuro como fondo para mi reloj.
Por último, agregue un campo de texto dinámico llamado 't_date'. Aquí es donde mostraremos la fecha objetivo en la que el reloj está contando. Recuerde incrustar la fuente para este campo de texto si no está utilizando una fuente del sistema.
Cree un nuevo archivo de Actionscript llamado 'Digit.as' y agregue este código para crear el shell vacío para la clase:
paquete import flash.display.MovieClip; clase pública Dígito extiende MovieClip private const TOP: int = 0; const privado BOTTOM: int = 1; private var _currentDigit: Array; private var _nextDigit: Array; private var _number: String = "0"; // CONSTRUCTOR public function Digit () _currentDigit = new Array (top1, bottom1); _nextDigit = new Array (top2, bottom2);
Esto no hace mucho todavía. Tenemos un par de matrices para mantener los 2 conjuntos de digit_top y digit_bottom MovieClips. He configurado 2 constantes, TOP y BOTTOM para ayudar a mantener un registro de los clips superior e inferior dentro de esos arreglos. los _número La variable mantendrá el dígito que se muestra en un momento dado..
(Nota: estoy usando el guión bajo en los nombres de mis variables para indicar variables privadas).
Encuentra tu Dígito MovieClip en la biblioteca y asígnele esta clase en la configuración de vinculación.
Vamos a utilizar la biblioteca TweenLite para animar nuestra Dígito Clip de película.
Descargue la versión AS3 de la biblioteca TweenLite aquí.
Coloque la carpeta 'com' en el mismo directorio que su archivo Flash principal (o en su ruta de origen, si ha configurado una ruta de clase diferente).
Agrega estas dos líneas en la parte superior de tu Dígito clase, justo debajo de la importación MovieClip:
import com.greensock. * import com.greensock.easing. *
Apenas vamos a arañar la superficie de lo que TweenLite puede hacer en este tutorial. Para más información revisa la documentación de TweenLite..
Agrega esta función a tu Dígito clase:
función pública flipTo (num: String): void _number = num; _nextDigit [TOP] .t_num.text = num; _nextDigit [BOTTOM] .t_num.text = num; // desplácese hacia abajo la parte superior del dígito hasta la mitad del punto TweenLite.to (_currentDigit [TOP], .15, scaleY: 0, ease: Linear.easeNone); // voltear el siguiente dígito de abajo hacia abajo TweenLite.to (_nextDigit [BOTTOM], .3, scaleY: 1, onComplete: flipComplete, ease: Bounce.easeOut);
Esto es lo que está sucediendo, línea por línea:
Mire de nuevo el diagrama del Paso 8 si está confundido acerca de la animación aquí.
Añade esta función a la Dígito clase justo debajo de la flipTo función:
función privada flipComplete (): void // swap digit var siguiente: Array = _currentDigit; _currentDigit = _nextDigit; _nextDigit = siguiente; // reiniciar la capa reset ();
Una vez que se complete la animación flip, ejecutaremos esta función. Se intercambia el _currentDigit y _siguienteDigito matrices Una vez hecho esto, llama a una función llamada 'reiniciar' para restablecer la estratificación del clip y las posiciones para el siguiente giro. Vamos a escribir esa función ahora.
Añade esta función a la Dígito clase:
función privada reset (): void addChild (_nextDigit [BOTTOM]); addChild (_currentDigit [TOP]); // voltea la siguiente parte inferior para estar detrás de la parte superior actual _nextDigit [BOTTOM] .scaleY = -1; _nextDigit [TOP] .scaleY = 1;
Las dos primeras líneas de esta función hacen estallar el _siguienteDigito ABAJO y luego el _currentDigit ARRIBA en la parte superior de la lista de visualización. Usualmente solo uso addChild () para hacer esto porque requiere menos escritura que usar setChildIndex ().
Una vez que los clips se vuelven a colocar en capas, establecemos las propiedades de escala Y para que estén listos para el siguiente giro. Esto significa cambiar _nextDigit [BOTTOM] de 1 a -1 y _nextDigit [TOP] de 0 a 1.
Nuevamente, revise el diagrama en el Paso 8 si se está perdiendo.
Una cosa que olvidamos hacer es colocar los clips correctamente para la primera animación de flip. Podemos hacerlo fácilmente agregando una llamada al Reiniciar Funcionar correctamente en el constructor de la clase Digit:
// CONSTRUCTOR public function Digit () _currentDigit = new Array (top1, bottom1); _nextDigit = new Array (top2, bottom2); Reiniciar();
Una última cosa que necesitaremos en nuestra clase de Dígitos es una forma de acceder a la privada _número Variable desde fuera de la clase. Agregaremos una función de acceso simple:
función pública obtener número (): String return _number;
Cree un nuevo archivo de ActionScript llamado 'Clock.as'. Pega en este código:
paquete import flash.display.MovieClip; import flash.events.TimerEvent; import flash.media.Sound; import flash.utils.Timer; La clase pública Clock extiende MovieClip private var _clockTimer: Timer; private var _targetDate: Date; // CONSTRUCTOR public function Clock ()
No mucho aquí todavía. Solo importando algunas de las clases que necesitaremos. También tengo un par de variables privadas.. _clockTimer contará los segundos para nosotros, y _Fecha objetivo mantendrá la fecha en que estamos contando para.
Agregue esta función a la clase Reloj justo debajo del constructor:
// establecer la fecha objetivo e iniciar el conjunto de funciones públicas del temporizador de cuenta regresiva (fecha: Fecha): void _targetDate = fecha; _clockTimer = new Timer (1000) // marca cada segundo (1000 milisegundos) _clockTimer.addEventListener (TimerEvent.TIMER, actualizar); _clockTimer.start (); // muestra la fecha de destino arriba del reloj t_date.text = _targetDate.toLocaleString (). toUpperCase (); // actualizar el reloj una vez aquí para que comience con la actualización de la hora correcta ();
Esta es la función que utilizaremos para establecer la fecha objetivo para el reloj. Acepta una fecha (por supuesto) y la asigna a la _Fecha objetivo variable. A continuación, crea una instancia de nuestra _clockTimer. los _clockTimer llamará al actualizar Funciona una vez por segundo para actualizar los dígitos..
Después de iniciar el temporizador, la función configura fecha Texto con la fecha de destino. La función toLocaleString () garantiza que la fecha se muestra en la zona horaria local del usuario.
La última línea de esta función llama. actualizar una vez para ajustar el reloj a la hora adecuada. De lo contrario, se mostraría "000 00:00:00" durante un segundo hasta el primer evento del temporizador.
Esta función es un poco larga porque es donde se realiza la mayor parte del trabajo. Agrégalo a tu clase de Reloj:
actualización de la función privada (e: TimerEvent = null): void var now: Date = new Date (); // obtener la hora actual // buscar la diferencia (en ms) entre el objetivo y ahora var diff: Number = _targetDate.valueOf () - now.valueOf (); si (dif <=0) // TIME'S UP! // do something cool here _clockTimer.stop(); _clockTimer.removeEventListener(TimerEvent.TIMER, update); diff = 0; // convert to seconds diff = Math.round(diff/1000); // number of days var days:int = Math.floor(diff/ (24 * 60 * 60)); diff -= days*(24 * 60 * 60 ); // number of hours var hours:int = Math.floor(diff / (60 * 60)) diff -= hours*60 * 60; // number of minutes var min:int = Math.floor(diff/ 60); diff -= min*60; // seconds are all that remain var sec:int = diff; // create an array of strings to hold the number for each value var diffArr:Array = new Array(String(days), String(hours), String(min), String(sec)); var diffString:String = "" var len:int = 3; // the first value (days) has 3 digits. All the rest have 2 for each(var s:String in diffArr) // pad the string with a leading zero if needed while(s.length < len) s = "0"+s; len = 2; // all the other values are 2 digits in length diffString += s; // add the padded string to the diffString // go through each character in the diffString and set the corresponding digit for(var i:int = 0; i< diffString.length; i++) if(diffString.substr(i, 1) != this["digit"+i].number) this["digit"+i].flipTo(diffString.substr(i, 1));
Esta función acepta un TimerEvent como su parámetro. El valor predeterminado para este parámetro es nulo. Esto nos permite llamar a la función sin enviar un parámetro, como lo estamos haciendo en el conjunto función.
La primera línea de esta función obtiene la fecha y hora actuales como un objeto Fecha. A continuación, encontramos la diferencia entre la fecha actual y la fecha objetivo (línea 37). Si la diferencia es 0 o menos, entonces es más allá de la fecha prevista, por lo que detendremos _clockTimer (líneas 38-44).
Dado que la diferencia en el tiempo entre ahora y el objetivo se calcula en milisegundos, debemos convertirlo en una buena visualización legible de días, horas, minutos y segundos (líneas 46-62). Los cálculos aquí son bastante simples, siempre y cuando sepas que hay 1000 milisegundos en un segundo, 60 segundos en un minuto, 60 minutos en una hora y 24 horas en un día..
En la línea 65 almacenamos todos esos valores como elementos en una matriz. Comenzando en la línea 68, recorramos cada elemento y lo agregamos a una cadena de caracteres llamada 'diffString'. Al hacer esto, también agregamos ceros iniciales cuando sea necesario (línea 71). Entonces, si nuestros valores para el reloj fueran 30 días, 5 horas, 56 minutos y 6 segundos, diferenciación se vería así: "030055606".
Lo último que hace esta función es recorrer los caracteres en el diferenciación (utilizando el método charAt ()). Para cada carácter de la cadena, verificamos si es diferente del número que se muestra actualmente en el dígito correspondiente. Esto es fácil debido a la forma en que nombramos nuestras instancias de dígitos. Si el número no es el mismo que el que se muestra actualmente, le indicamos a ese dígito que pase al número que se encuentra en el diferenciación.
Encuentre (o cree) un buen sonido de tictac que se reproducirá cada vez que se actualice el reloj. Importa en la biblioteca de tu archivo Flash y configura el nombre de la clase como 'TickSound' en la configuración de Enlace.
Añade el _tickSound variable en la parte superior de su clase Reloj justo debajo de las otras dos variables:
private var _clockTimer: Timer; private var _targetDate: Date; private var _tickSound: Sound = new TickSound ();
Y reproduce el sonido dentro de la actualizar función:
_tickSound.play ();
Nuestro temporizador de cuenta regresiva está completo, solo necesitamos alguna forma de establecer la fecha objetivo. Crea un nuevo archivo de Actionscript llamado 'Main.as' con este código:
paquete import flash.display.MovieClip; public class Main extiende MovieClip public function Main () // establece la fecha objetivo para el reloj var targetDate: Date = new Date (); targetDate.setTime (Date.UTC (2010, 4, 28, 20, 00)); clock.set (targetDate);
Todo lo que hace es establecer la fecha de destino para la instancia del Reloj en el escenario. Estoy usando setTime () y Date.UTC () para convertir la fecha a Universal Timecode. De esta manera, la fecha será correcta cuando se convierta nuevamente a la hora local en la computadora del usuario. Además, recuerde que los meses se basan en cero. Entonces, el mes 4 es en realidad mayo, no abril..
En su archivo Flash, establezca la clase de documento en 'Principal'.
Si necesita una actualización sobre el uso de la Clase de documentos, consulte este Consejo rápido.
Prueba tu película ahora y todo debería funcionar. Intente cambiar la fecha objetivo en la clase Principal y vea cómo cambia la cuenta regresiva.
Una desventaja potencial de cómo hemos configurado esto es que la fecha prevista está codificada en nuestro SWF. Está bien, pero sería genial si pudiéramos cargar dinámicamente la fecha para poder reutilizar la cuenta regresiva para diferentes cosas..
Veamos que podemos hacer al respecto ...
Cree un nuevo archivo XML en la misma carpeta que su archivo Flash llamado 'targetDate.xml' (un archivo XML es solo un archivo de texto simple). Agregue esto al archivo XML:
2011 3 25 20 21
El uso de este formato para nuestra fecha objetivo está bastante hinchado (hay más marcas que datos reales), pero mantendrá las cosas muy claras para los fines de este tutorial..
Ahora hagamos algunos cambios en nuestra clase de documento principal. Reemplace todo en ese archivo con este código:
paquete import flash.display.MovieClip; importar flash.net.URLLoader; importar flash.net.URLRequest; import flash.events.Event; public class Main extiende MovieClip // CONSTRUCTOR public function Main () // load the XML var xmlLoader: URLLoader = new URLLoader (); xmlLoader.addEventListener (Event.COMPLETE, onDataLoaded); xmlLoader.load (new URLRequest ("targetDate.xml"));
Notará que hemos importado algunas clases adicionales para ayudarnos a cargar el archivo XML. En la función de constructor, estamos creando una nueva instancia de URLLoader para cargar el archivo por nosotros. Adjuntamos un detector de eventos que llamará a una función llamada 'onDataLoaded' cuando el archivo haya terminado de cargarse..
Agregue esta función a la clase principal:
función privada onDataLoaded (e: Event): void var xml: XML = new XML (e.target.data); var targetDate: Date = new Date (); targetDate.setTime (Date.UTC (int (xml.year), int (xml.month), int (xml.day), int (xml.hour), int (xml.minute)))); clock.set (targetDate);
Esta función crea un nuevo objeto XML del archivo que cargamos. Luego creamos un nuevo objeto Fecha a partir de los valores en el XML. Nuevamente estamos usando setTime () y Date.UTC () para convertir la fecha a Universal Timecode. La última línea es la misma que antes, simplemente envía la fecha objetivo a nuestra instancia de Reloj..
Eso es bastante para este. Sin embargo, hay algunas mejoras que le gustaría hacer:
¡Buena suerte! Como siempre, publica un comentario y hazme saber lo que piensas..