Problema: Necesito pausar momentáneamente la ejecución de un archivo SWF, como por ejemplo la Pausa en los videojuegos.
Solución: Imaginemos que tengo un videojuego que deseo pausar en un momento determinado. Suponiendo que todo el código dependiera de un sólo enter frame (que se encargaría de llamar a la/s función/es de las distintas instancias) sería sólo cuestión de poner un if antes del resto de la función o de usar un puntero a función (que nos permitiría ejecutar sets distintos de acciones dependiendo de la situación, Mmmm, huelo otro quick tip).
Hasta aquí todo bien, pero ¿qué hacemos con las animaciones? Ahí se complica, podríamos optar por parar (con el método stop()) todos los MovieClips y "reanimarlos" con play() cuando queramos reanudar el juego, pero tendríamos que tener en cuenta que quizá no a todos debamos darles play(). Además si tenemos animaciones complejas con varios MovieClips anidados hacer esto es una absoluta pesadilla (se puede usar un método iterativo con un -pseudo código- for each child in this), pero eso sin siquiera considerar que ciertas animaciones deben detenerse en un momento determinado.
¿La solución más usada? Los programas no pausan las animaciones, limitándose a detener el update lógico. Cosa poco estética que al no-programador le da una especie de asquito y una sensación de producto no terminado.
Pero de repente, luego de lidiar por tanto tiempo con este problema encontré la solución perfecta. Es tan increíblemente simple que no puedo creer que a nadie se le haya ocurrido antes (lo que, lógicamente, me incluye a mí mismo) y mientras escribía la función en eclipse (con una sonrisa de oreja a oreja, babeando como chico de 12 años con una Playboy) no podía dejar de pensar:
HernanRivas completamente fuera de sí :
No puede funcionar, es demasiado simple, no te ilusiones, abandon all hope, ni lo pruebes, no lo hagas, te vas a desepcionar, pateá la computadora y olvidate del asunto, no lo hagas, nooooo......
La cosa es que, a pesar de todo, funcionó, motivo por el que grité "soy un genio" hasta quedar disfónico (aunque antes de hacer el ridículo, busqué en google para asegurarme que nadie había dado con eso antes).
La solución es ésta:
Código :
public function pause ():void
{
stage.framerate = 0;
}
public function resume ():void
{
stage.framerate = 30;
}
OMFG!!! ¿¡¿¡¿FUNCIONA?!?!? Si, y los problemas que esto origina son sólo 2 y fáciles de solucionar :
Flash refresca una vez por segundo cuando uso MOUSE_MOVE : Creo que actualiza cada un segundo (aprox) porque es en ese punto que el garbage collector hace su trabajo (mi teoría está fundamentada, pero no alcanza el paréntesis para explicarlo). En general eso no importa porque todo está detenido. Si lo que queremos es mover el cursor, simplemente agregamos un updateAfterEvent. Método que también existe para el timer event. En la ayuda de Flash está todo muy explicado.
Pero no quiero detener TODO : Esto es un poco más complicado, lo que tenemos que hacer es usar eventos que no dependan del framerate como el teclado, el mouse o el timer. Éste último nos permite que ciertos MovieClips continúen animados. Si quieren implementar ésto utilicen el tip para animar MovieClips a distintos framerates.
NOTA : Tengan en cuenta que si la función "pause" tiene más líneas de código, deberían ubicar la que setea el framerate al final. Para asegurarse un último refresh.
Por cierto, pueden ver la prueba de que prácticamente a nadie se le ocurrió (publicar) esta idea (6 resultados relevantes para google). Y no encontré ninguna mención a la pausa.
Valla!!! Sencillo, simplemente sencillo. Lastima que no funcione también con AS2 Por:JoH_blog
buen tip pero ... tengo un problema. hice un juego en AS 2 , si lo cambio a AS 3 el juego empieza a fallar ... hay alguna forma de poder hacer lo mismo de otra forma ??? Por:lea123456_blog
Otra forma relativamente sencilla sería volcar todo el contenido del root a un bitmapData y ponerlo pon encima de todo de lo que se quiere pausar (deteniendo la parte lógica con una condición en el onEnterFrame). Es más complicado, pero permite poner MCs encima de la imagen y no perder la interactividad. Por:Karacas_blog
Karacas, yo implemento las 2 al mismo tiempo. Detengo las animaciones y además creo un bitmapData para blurearlo (porque queda bien).
El problema es que por más bitmapData que use para tapar todo, si tengo eventos en la línea del tiempo estos se "dispatchean" igual. Otro problema es que si, por ejemplo, tengo un personaje que dispara y pauso mientras dispara, cuando despause el juego la animación ya finalizó y el paso del bitmap al juego es brusco. Por:HernanRivas (logout)_blog
¿Quién no ha pensado en esto al menos una vez en su vida?
Una solución realmente ingeniosa, muchas gracias!! Por:Juanlu_001
Te pasaste hernan , aunque te digo, esa parte de paralizar el disparo en el medio de la animacion y despues vuelva a como estaba, esta fuerte, creo que los caminos limpios escasean para esa solucion.!, estaria bueno lanzar una encuesta o un concurso a ver quien lo logra. ! que creen clabbers.!
salu2 Por:Zandy
Existen otros métodos, pero tan fino y elegante......... por ahora,creo que no. Excelente originalidad Hernan.
Un apunte: La documentación dice que el framerate menor posible es de .01. Como ese asunto parece ser un bug, si se implementa en un código es posible que lo reparen( no es nada difícil que lo hagan) y nuestro SWF fallará. Habrá que prever de algún modo eso. Por:Teseo
Es muy buena solución y bastante sencilla. Por:Carloz
Buenas, siento desilusionaros pero esto no es exactamente así. Teseo ha dado en el clavo:
Teseo :
La documentación dice que el framerate menor posible es de .01
Sólo que no es un bug, realmente funciona. Si pones el framerate a 0 el compilador lo pone a 0.01. Esto quiere decir que el motor del player se ejecuta cada 100 segundos. Aplicado a animación es virtualmente como si no se moviera, pero a nivel de código, obviamente, no es seguro utilizarlo.
Para muestra un botón. Crear un nuevo fla con el documentClass apuntando a esta clase:
Código :
package {
import flash.display.*;
import flash.events.*;
public class Main extends Sprite {
private var _cont:Number = 0;
function Main() {
stage.addEventListener(MouseEvent.CLICK, evClick);
stage.addEventListener(Event.ENTER_FRAME, evEnterFrame);
}
private function evEnterFrame(e:Event):void {
trace("Cont:", _cont);
_cont++;
}
private function evClick(e:MouseEvent):void {
trace("Framerate 0");
stage.frameRate = 0;
}
}
}
Dejarlo durante varios minutos y veréis como no deja de aumentar el contador.
Y para acabar, y a modo de fricky-charla, creo que hacer una pausa es tarea del programador. Aunque se pudiera, detener el motor de Flash no me parece correcto, ya que el flujo de un programa no debería poder interrumpirse nunca (de hecho, no se puede).
A pesar de ser una tarea tediosa (para todos los movieclips de un juego, por ejemplo), en AS3 se simplifica mucho gracias a la displayList y al módelo de eventos. Por ejemplo, agrupando todos los objetos gráficos en un contenedor y lanzando un único evento al mismo, podríamos recorrer toda la jerarquía de objetos visuales y detenerlos.
Anyway, el tip es muy interesante Hernán
pd: quizá estaría bien hacer un mini concurso como comenta Joris. Personalmente, me encataría ver las propuestas de muchos de vosotros. Por:llops
Una solucion poco Ortodoxa que yo utilizaba era el agregar una condicion simple... Si esta era True se reproducia todo dentro de esta a la Normalidad, en cambio si devolvia False las animaciones se detenian y el codigo no se ejecutaba... O bien recurrir a for this each in etc
Aun asi me agrada tu solucion, el unico problema es que aun asi se sigue ejecutando todo, solo que con un frameRate mucho menor... Por:M@U
Y si asignas a todas tus animaciones un evento de Timer, y cuando te convenga detienes el Timer? Por:Juanlu_001
y como hacemos con actionscript 2? no importa, formas violentas y poco elegantes son bienvenidas... Por:Luno-blog