Lanzar objetos creando una clase PanAndThrow

En este tutorial nos burlaremos y terminaremos una clase de paneo y lanzamiento que nos permitirá agregar este efecto a cualquier elemento que queramos. Para lograr esto, crearemos un visor de imágenes, pero no su visor promedio. Aquí tendremos zoom, lanzar, panorámica ... Casi suena como una aplicación ninja, ¿eh??


Paso 1: Introducción

La clase Pan y Throw le permitirá agregar la funcionalidad pan y lanzar a cualquier objeto ActionScript que desee. Aunque este tutorial es específicamente para Flex, la clase en sí puede usarse en cualquier lugar donde se encuentre ActionScript. Había visto este efecto en varios sitios web, luego en Photoshop CS4 y decidí que también quería esto en mis proyectos.

Hay muchas aplicaciones para este efecto; El que vamos a usar para este tutorial es un visor de imágenes que te permite acercar y alejar la imagen de la mañana y cambiar la fricción que utiliza el efecto de proyección. Sin embargo, este tutorial no se trata realmente del visor de imágenes, se trata de hacer una clase de panorámica y lanzamiento. Así que empecemos con eso. Abre tu editor de Flex favorito y pon en marcha un proyecto; Para obtener información sobre cómo hacer esto en Flex Builder, consulte Adobe LiveDocs. Una vez creado tu proyecto, abre el archivo MXML. Necesitamos agregar algo de código a esto antes de crear nuestra clase.


Paso 2: Nuestro MXML

Como esta no es la parte principal del tutorial, no voy a pasar mucho tiempo aquí. Si tiene alguna pregunta sobre esta sección que no esté cubierta, puede formularla en los comentarios a continuación. En primer lugar, aquí están los objetos MXML para poner en la aplicación:

            

Notará las cuatro funciones llamadas en las etiquetas: init (), changeDecay (), smoothImage () y zoom (). Necesitamos escribir esas funciones. Este es el código entre el etiquetas:

 importar mx.states.SetStyle; importar mx.effects.Move; importar mx.containers.HBox; importar mx.containers.Box; private var imageWidth: Number = 0; privada var imageHeight: Number = 0; variable privada: Move = new Move (); // se llamará cuando la aplicación cargue la función privada init (): void // Este evento agregará la capacidad de ocultar y mostrar nuestros controles con un clic. control.addEventListener (MouseEvent.CLICK, controlClick); mover.target = control;  // esta función acercará y alejará nuestra imagen según el valor de nuestro control deslizante de zoom. función privada zoom (): void inside.width = (imageWidth * hSlider.value) / 100; inside.height = (imageHeight * hSlider.value) / 100;  // esto se llama cuando nuestra imagen cambia de tamaño. función privada smoothImage (ev: Event): void // establece el suavizado de la imagen para que la imagen se vea mejor cuando se transforma. var bmp: Bitmap = ev.target.content como Bitmap; bmp.smoothing = true; imageWidth = inside.width; imageHeight = inside.height;  // no usaremos esta función de cambio aún privada. Día de cambio (): void // esto cambiará el valor de caída (fricción) de nuestra clase cuando lleguemos allí.  función privada controlClick (e: MouseEvent): void mover.play (); // esta función oculta / muestra los controles al hacer clic si (control.y! = -5) mover.stop (); mover.yTo = -5; mover.play ();  else if (e.target == control) mover.stop (); mover.yTo = (control.height - 10) * -1; mover.play (); 

Una vez que tenga su MXML, necesita crear una carpeta llamada "clases" en la misma carpeta que su archivo MXML. (Si usa Flash, la carpeta debe estar en el mismo directorio que su archivo FLA). Este es nuestro paquete de clases y es donde irá el archivo PanAndThrow.as. En Flex Builder, cree una nueva clase, colóquela en el paquete de clases y llámela PanAndThrow; esto creará tu clase - estilo por defecto.


Paso 3: Los Hechos de una Clase

Aquí está nuestra clase básica de PanAndThrow. Guárdelo como PanAndThrow.as en su nueva carpeta de "clases".

 // clases de paquete de declaración de espacio de nombres // declaración de clase clase pública PanAndThrow / * esto se denomina constructor, este método / función se llamará cuando cree * una instancia de su objeto, o cree una instancia de su objeto. * para esta clase no hacemos nada porque vamos a hacer todo * en la función Init * / función pública PanAndThrow () 

¿Qué variables y funciones necesitamos en nuestra clase de PanAndThrow? Para obtener eso, puedes preguntarte "¿qué necesita hacer mi clase, qué necesita saber y qué necesita para poder hacerlo?" Así que vamos a crear algunos pseudo-código.

Nota rápida

Cuando desarrollé esta clase por primera vez, puse todo en el constructor, pero eso me llevó a un problema cuando creé los métodos de inicio y detención debido al alcance. No pude crear una instancia de esta clase en un ámbito global con toda la información requerida. Por lo tanto, hice una función init (), por lo que la instancia podría iniciarse y detenerse desde fuera de la clase.


Paso 4: Nuestro Pseudo-Código

"Pseudo-código" solo significa código falso, que podemos usar para ayudarnos a pensar qué código real necesitaremos.

 clases de paquetes clase pública PanAndThrow / * Estas serán las variables que creamos. Entonces, ¿qué necesitamos saber? * anObjectToThrow; * anObjectToThrowItIn; * ObjectLocation; * PreviousObjectLocation; * Decaimiento; // para la física * estos son los más obvios, pero esta lista se volverá mucho más grande * ya que vemos exactamente lo que necesitamos en nuestras funciones * / función pública PanAndThrow ()  / * Entonces, ¿qué va a hacer nuestra clase? ? * en eso(); // necesita iniciar * stop (); // Queremos poder detenerlo de alguna manera. * comienzo(); // si nos detenemos necesitamos poder iniciarlo de nuevo. * pan (); * lanzar(); * /

Ahora que tenemos un pseudo-código podemos comenzar a construir la clase. Vamos a empezar con la función init (). Esto también nos llevará a uno de los principios de Programación Orientada a Objetos llamado encapsulamiento, Que se ocupa del acceso de las piezas del código..

Este código debe ir en la clase de PanAndThrow que acabamos de comenzar. (¿No está seguro de dónde? Consulte el Consejo rápido de Document Class).

 // gracias a OOP, se puede usar una clase de nivel inferior y una clase de nivel superior (una que se extiende // la clase de nivel inferior). Como aquí, casi todos los objetos que utilizarás amplían la clase // Sprite. Así que solo tengo que pedir un objeto Sprite y puedes dar una Caja o un Botón. private var targetObject: Sprite = new Sprite (); private var eventObject: Sprite = new Sprite (); privado var originalDecay: Number = .9; privado var buttonDown: Boolean = false; private var moveY: Boolean = true; private var moveX: Boolean = true; private var TargetClick: Boolean = true; // Usaremos esto para verificar cuánto tiempo ha estado tu mouse sobre un objeto sin moverse. var v privado: temporizador; variable var timerInterval: int = 100; función pública init (ObjectToMove: Sprite, ObjectToEventise: Sprite, DecayAmout: Number = .9, isMoveY: Boolean = true, isMoveX: Boolean = true, OnlyMoveOnTargetClick: Boolean = true): void targetObject = ObjectToMove; eventObject = ObjectToEventise; originalDecay = DecayAmount; moveX = isMoveX; moveY = isMoveY; TargetClick = OnlyMoveOnTargetClick; t = nuevo Timer (timerInterval); comienzo(); 

Sólo un par de cosas que quiero señalar. En la función para init, he establecido algunos de los argumentos para que sean iguales a un valor. Eso significa que les estoy dando un valor predeterminado, por lo que son opcionales. Cuando se configuran valores predeterminados para los argumentos de una función, tienen que ser los últimos parámetros; no se puede tener una variable requerida después de una opcional. La razón por la que agregué variables predeterminadas es para acortar la llamada si usamos la configuración predeterminada. Puedo llamar a PanAndThrow (mover, eventer); y se hará, en lugar de PanAndThrow (mover, enventer, decayer, yVal, ...) y así sucesivamente.

¿Alguna vez se ha preguntado qué significa "privado" o "público" frente a funciones y variables? Esa es la exposición del objeto. Un objeto "público" puede ser accedido por cualquier otra clase; un objeto "privado" solo puede ser visto por los otros miembros de esta clase; un objeto "protegido" está oculto para todo excepto para las clases que están en el mismo paquete.

Queremos poder cambiar la descomposición de nuestro MXML, por lo que necesitamos un enlace público para llegar a nuestra variable privada; aquí es donde entran las funciones getter y setter:

 privado var originalDecay: Number = .9; función pública get decay (): Number return originalDecay; 

Esa es una función "getter". Significa que, para las clases externas, parece que la clase PanAndThrow tiene una variable pública llamada "decaimiento". Cuando intenten acceder a él, les devolveremos el valor de nuestra variable originalDecay (privada).

Las funciones de Setter son casi iguales, pero permiten que las clases externas cambien el valor de nuestra variable pública "falsa":

 función pública decaimiento del conjunto (valor: número): void originalDecay = value; 

Estos son útiles porque puede poner la lógica en un setter para restringir lo que entra en su var privado. Por ejemplo, si coloca un Número en la etiqueta MXML para un cuadro, obtendrá una altura establecida; si pones un% (haciendo que el número sea una cadena) obtendrás una altura porcentual. Eso está incorporado en el código para el ajustador de altura de la caja. Ahora que tenemos nuestro getter y setter, puedes acceder a la variable decay como esta desde fuera de la clase:

 var pt: PanAndThrow = nuevo PanAndThrow (); pt.init (objetivo, padre); pt.decay = .7;

Paso 5: Comenzar, escuchar, detener

Tenemos nuestra clase, algunas variables locales y una función init (). Hagamos algo ahora. Al final de la función init () llamamos "start ();" así que vamos a hacer la función de inicio. Sobre todo es solo un grupo de oyentes:

 public function start (): void // Con el mouse hacia abajo, buscamos iniciar nuestra acción de paneo, pero debemos poder // verificar nuestro OnlyMoveOnTargetClick que asignamos a nuestro campo global TargetClick targetObject.addEventListener (MouseEvent. MOUSE_DOWN, handleOverTarget); eventObject.addEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); // Cuando llamamos a nuestra bandeja, utiliza un detector de movimiento del mouse, lo que significa que se llama cada vez que se mueve el // mouse, por lo que necesitamos ver cómo limitar cuándo se mueve el objeto de destino. eventObject.addEventListener (MouseEvent.MOUSE_MOVE, moveIt); // esto es lanzar el objeto después de una panorámica, esto es un poco complicado porque la función throwIt () llama a otro oyente. targetObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); // el método throwItOut hace que nuestro objeto actúe como si soltáramos el botón del mouse, pero se activa cuando // el mouse abandona el objeto primario targetObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); // este es el escucha del temporizador, esto comprobará si has estado manteniendo presionado el mouse por un momento, // explicaré la necesidad de esto cuando lleguemos a la función t.addEventListener (TimerEvent) de timerOut (). TIMER, timerOut); t.start (); 

La función stop () es casi la misma, pero estamos eliminando a los oyentes.

 stop de la función pública (): void targetObject.removeEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); eventObject.removeEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); eventObject.removeEventListener (MouseEvent.MOUSE_MOVE, moveIt); targetObject.removeEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.removeEventListener (MouseEvent.MOUSE_UP, throwIt); targetObject.removeEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.removeEventListener (MouseEvent.MOUSE_OUT, throwItOut); t.removeEventListener (TimerEvent.TIMER, timerOut); t.stop (); 

Ahora podemos escuchar lo que está pasando, repasemos cada una de estas funciones de escucha.


Paso 6: MouseEvent.MOUSE_DOWN

Vamos a ver el controlador de eventos handleOverTarget.

 Función privada handleOverTarget (e: MouseEvent): void buttonDown = true; arMousePrevX = MousePrevX = MouseCurrX = eventObject.mouseX; arMousePrevY = MousePrevY = MouseCurrY = eventObject.mouseY; if (e.currentTarget == targetObject ||! TargetClick) overTarget = true;  else if (e.target.toString (). search (targetObject.toString ()) < 0)  overTarget = false;  

Se llamará a esta función cuando haya un evento MOUSE_DOWN en el objeto de evento o en el objeto de destino. Es muy importante tener en cuenta que si pongo un detector en un objeto principal, incluso se llamará al controlador cuando ocurra el evento en un elemento secundario. En este caso, mi objeto de destino es un elemento secundario del objeto de evento. Cuando haga clic en el objeto de destino, este método se llamará dos veces: primero para el mouse que está sobre el niño y luego para el ratón sobre el padre. Eso es muy importante para esto porque vamos a decidir si el mouse hacia abajo podrá mover nuestro objeto objetivo, por lo que realmente necesitamos saber si el mouse estaba sobre el niño o no..

La primera afirmación es bastante sencilla: establece nuestra variable de clase buttonDown en true.

Los dos siguientes también son bastante fáciles, excepto que he introducido un par de variables nuevas que deberán incluirse en nuestra lista de variables de clase: MousePrevX, MousePrevY, arMousePrevX, arMousePrevY, MouseCurrX y MouseCurrY. Se usarán mucho en las funciones de arrastrar y desplazar, así que esperaré para hablar de ellas hasta entonces..

La instrucción if comprueba si el objeto seleccionado es el objeto de destino. Recuerde, TargetClick se estableció en el argumento que pasamos a init (), OnlyMoveOnTargetClick; si esto es falso, queremos tratar cada objeto secundario como el objeto de destino cuando se hace clic. Es por eso que tenemos la comprobación "||! TargetClick".

Esa es la parte fácil. La siguiente parte es un poco más complicada..

El e.currentTarget devuelve el objeto que desencadenó el evento. El e.target devolverá el objeto que era el objetivo real. Así que podría decir esto, ¿verdad??

 if (e.target == targetObject ||! TargetClick) overTarget = true;  else overTarget = false; 

Eso es bastante simple, pero está mal. ¿Qué pasa si mi objeto objetivo tiene hijos? Entonces mi e.currentTarget puede ser targetObject pero el e.target es el hijo de targetObject y no coincidirá. Queremos que esto se mueva incluso si estamos moviendo el mouse sobre un objeto secundario.

Así que aquí viene String.search al rescate. Si nuestro objetivo actual no es nuestro targetObject, usamos "else if" para ver si podemos encontrar nuestro objeto objetivo en el destino. e.target.toString () producirá algo como esto: "application2.eventobject3.targetobject2.targetchild4" para nuestro objeto de destino donde targetObject.toString () producirá algo como esto "application2.eventobject3.targetobject2" todo lo que tengo que hacer para Averigüe si nuestro objetivo es un hijo de nuestro targetObject es por esto:

 e.target.toString (). search (targetObject.toString ())

Si hay una coincidencia, devolverá el primer índice de la coincidencia, o si no hay una coincidencia, devolverá un -1, por lo que solo podemos ver si es mayor que -1 y viola, hemos encontrado si el objeto hacer clic en es un hijo de nuestro targetObject.

(Podríamos verificar los elementos secundarios o los elementos principales del objeto a través de la función getChildAt () y la propiedad principal, pero esta es una buena alternativa).


Paso 7: TimerOut y Pan

La función del temporizador también es bastante fácil, especialmente porque hemos hecho esto antes. Bueno, casi he hecho esto antes. Cuando hemos arrastrado alrededor de nuestro pequeño targetObject un poco y decidimos que no queremos dejarlo ir, simplemente lo amamos demasiado y detenemos bruscamente el mouse, ¿qué pasaría si soltara el botón del mouse en ese momento? Bueno, ¿qué crees que pasaría? No voy a responder eso por ti, solo te ayudaré con el código para evitar que suceda. En el código final, comenta estas tres líneas. Esto debería parecer realmente familiar, solo usamos esto en el controlador de botones, excepto por una variable, MouseDragged. Vamos a usar eso cuando llamemos a nuestra otra función:

 función privada timerOut (e: TimerEvent): void MouseDragged = false; arMousePrevX = MousePrevX = MouseCurrX = eventObject.mouseX; arMousePrevY = MousePrevY = MouseCurrY = eventObject.mouseY; 

Entonces, si está preguntando por qué necesitamos este evento de temporizador, es probable que no haya intentado sacarlo para ver qué sucedía. Entonces haz eso.

Esta siguiente función es una de nuestras principales funciones; Es la función pan. Hay mucho involucrado, así que vamos a sumergirnos en nuestro pseudo-código:

 Función privada moveIt (e: MouseEvent): void / * ok, entonces, ¿para qué necesitamos esta función? * Necesita panear nuestro objeto objetivo. * así que veamos si estamos sobre nuestro objeto de destino * / // si (estamos sobre nuestro objeto de destino) // // ¿qué herramientas vamos a necesitar para desplazarnos? // bueno, tal vez deberíamos revisar si el botón está abajo // si (botón está abajo) // // podríamos necesitar establecer la variable botón abajo. buttonDown = true; // y si estamos en esta función en este punto, nuestro botón está presionado y // el mouse se ha movido, eso es un arrastre: así MouseDragged = true; // si estamos moviendo el objeto de acuerdo con el movimiento del mouse, entonces deberíamos // probablemente saber dónde está nuestro mouse: MouseCurrX, Y = current MouseX, Y; // esta es una introducción a nuestro ratón artificial prev, que se explicará // en la siguiente función. El ar significa 'artificial' o 'after release', // lo que prefiera. Eso debe establecerse en nuestra posición real del mouse anterior. // arMousePrevX = MousePrevX; // arMousePrevY = MousePrevY; // entonces necesitamos mover el targetObject, // pero recordar nuestras variables, moveX y moveY, entonces: // si moveX mover x; // si mueveY mueve y; // necesitamos restablecer nuestro Decaimiento (fricción) al estado original: // Decay = originalDecay; // eso debería terminar el if // // ¿qué más? // // establecemos nuestro buttonDown en true antes, así que configurémoslo en false aquí. // buttonDown = false; // si este no es un clic de destino, deberíamos establecer nuestro overTarget en false, por lo tanto: // if (! TargetClick) // overTarget = false; // Eso es. // // hay algunas cosas que queremos que ocurran, independientemente de las condiciones. // primero, debemos configurar nuestro mousePrevX, Y variable - ANTES de que el mouse se // vuelva a mover! // MousePrevX = eventObject.mouseX; // MousePrevY = eventObject.mouseY; // Aquí hay dos variables más para realizar un seguimiento de: xOpposideEdge y yOppositeEdge // estamos probando para ver cuál es el tamaño de nuestro objeto objetivo en relación con // nuestro objeto de evento; Si uno es más grande tenemos que cambiar el comportamiento del rebote. // if (targetObject.width> eventObject.width) xOppositeEdge = true; // else xOppositeEdge = false; // if (targetObject.height> eventObject.height) yOppositeEdge = true; // else yOppositeEdge = falso; // y finalmente debemos detener y reiniciar nuestro temporizador. //t.stop (); //t.start (); //

Admito que esto es un poco más psuedo-y que el anterior; eso es por dos razones: una, no sabes lo que se avecina, y dos, estoy realmente emocionada de obtener el código:

 Función privada moveIt (e: MouseEvent): void // en nuestro pseudo-código, esto fue dos condiciones, pero podemos combinarlas en una, // probamos para ver si nuestro evento fue un botón pulsado, y si estamos sobre nuestro target, // si estamos, movamos el objeto target. if (e.buttonDown && overTarget) buttonDown = true; MouseDragged = true; MouseCurrX = eventObject.mouseX; MouseCurrY = eventObject.mouseY; // Aquí está la versión artificial / después de la primera. una vez más, bien llegar a eso. arMousePrevX = MousePrevX; arMousePrevY = MousePrevY; / * este es el importante, en nuestro pseudo fue "mover el objeto de destino", * por lo que necesitamos traducir eso. Para ayudarnos, crearemos una variable local * Topper para la parte superior y Sider para el lado. * Así que echemos un vistazo a Topper (lo mismo se aplicará a Sider). * eventObject.mouseY mira dónde está nuestro mouse dentro del eventObject. * Alejamos a nuestro MousePrev de eso, y eso nos dará cuánto debe viajar el objeto *, por lo que la Y podría viajar 2 píxeles, o -2 píxeles según la dirección *, por lo que tomamos ese cambio y lo agregamos al objetivo posición actual *, pero eso no está sucediendo todavía, esto es solo una var. * / var Topper: int = (eventObject.mouseY - MousePrevY) + targetObject.y; var Sider: int = (eventObject.mouseX - MousePrevX) + targetObject.x; // aquí es donde sucede, si se mueve Y (recuerda del pseudo-código) entonces // podemos establecer la posición del objetivo. if (moveY) targetObject.y = Topper; if (moveX) targetObject.x = Sider; // así que en realidad solo estamos usando Topper y Sider para almacenar temporalmente donde // el objeto objetivo debe moverse a Decay = originalDecay ;  else buttonDown = false; if (! TargetClick) overTarget = false;  MousePrevX = eventObject.mouseX; MousePrevY = eventObject.mouseY; if (targetObject.width> eventObject.width) xOppositeEdge = true; else xOppositeEdge = false; if (targetObject.height> eventObject.height) yOppositeEdge = true; else yOppositeEdge = false; t. ); t.start (); 

Y ahora estamos paneando.


Paso 8: Tirar, Lo, Fuera, Repetidor!

¡Esta es la segunda gran función y con esto tendremos nuestra clase construida! Listo para desplazarse y lanzar cualquier objeto que creas conveniente Hay dos funciones que debemos abordar primero: throwIt (), que configuramos como controlador para el evento MOUSE_UP, y throwItOut (), que configuramos como controlador para el evento MOUSE_OUT.

 función privada throwIt (e: MouseEvent): void buttonDown = false; if (MouseDragged) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater);  función privada throwItOut (e: MouseEvent): void buttonDown = false; if (e.relatedObject == null || e.relatedObject == eventObject.parent) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater); 

Estas dos funciones son casi iguales (después de todo, están haciendo lo mismo en momentos diferentes). En ellos establecimos el botón Abajo en falso, porque se trata de un evento de mouse up, y verificamos si el mouse fue arrastrado, usando MouseDragged (que configuramos en la última función) o marcando "e.relatedObject"; El objeto que el mouse acaba de mover..

Si fue arrastrado agregamos otro oyente. El evento ENTER_FRAME es realmente genial. Esta es la base de nuestra animación; Cada vez que ingresamos un nuevo marco, se ejecutará la función throw (). Eso es lo que nos permite simular un arrastre del mouse después de la liberación (¿recuerda la variable arMousePrevX, Y? Para eso es). Y eso es todo lo que el lanzamiento está haciendo realmente, simulando un arrastre del mouse, sin un mouse, por supuesto. Así que ya casi tenemos la función que necesitamos, excepto que necesitamos reemplazar las llamadas a la posición actual del mouse a nuestra posición artificial del mouse.

Casi me adelanté un poco. Así que con estas dos funciones de evento, throwIt y throwItOut, están haciendo lo mismo pero eso Si En la segunda función vale la pena mencionar. Luché un rato tratando de obtener esta funcionalidad, hasta que observé el evento un poco más de cerca. El problema fue intentar que el objeto de destino actuara como si soltara el botón cuando el cursor abandonó el objeto de evento. Adelante, intente y haga esto sin el objeto e.related. Casi lo tuve unas cuantas veces, pero no pude hacerlo bien. Lo que e.relatedObject hace es encontrar en qué objeto se encuentra, después de que se llame al evento. Por eso es tan genial. Cuando nuestro cursor abandona la película por completo, devuelve un valor nulo, de lo contrario, devolverá el objeto en el que se encuentra, por lo que podemos verificar si e.relatedObject es nulo o es padre del eventObject. Eso produce la acción correcta que estamos buscando..

En las funciones anteriores configuramos llamadas a theRepeater (). Esta será la función de lanzamiento, y recuerde que se llamará cada vez que ingresemos un nuevo marco. Vayamos a través de esta línea por línea:

 función privada theRepeater (e: Event): void // el temporizador se debe detener, intente eliminarlo y vea qué sucede. t.stop (); // Aquí hay una variable local que mantendrá la posición actual (falsa) del cursor. // Bueno, solo es "falso" después de la primera vez. var oldxer: Number = MouseCurrX; var oldyer: Number = MouseCurrY; // ahora, al igual que hicimos antes, necesitamos encontrar la diferencia entre nuestra // posición actual y la anterior. Entonces, ¿cómo es esto diferente de antes? ¿por qué? var xDiff: Number = MouseCurrX - arMousePrevX; var yDiff: Number = MouseCurrY - arMousePrevY; // Si el botón está presionado, no vamos a movernos más, el botón detendrá la acción en este caso. if (! buttonDown) // toma la diferencia y la multiplica por la decadencia. esto nos dará la nueva // diferencia, que será un poco más pequeña que la anterior, que es como // obtenemos el efecto de fricción con esto. // p.ej. si el decaimiento es 0.5, la distancia recorrida reducirá a la mitad cada fotograma. xDiff = xDiff * Decay; yDiff = yDiff * Decay; // la siguiente es una de las partes confusas para mí, esto no mueve el objeto a // todo, solo prueba para ver si nuestro targetObject ha alcanzado el límite. si lo ha hecho, // tenemos que recuperarlo. (esto podría cambiarse a alguna otra acción si // lo desea, incluso podría eliminarlo, ¿qué sucede si lo hace? ¡inténtelo! // en la función de paneo configuramos esta variable, OppositeEdge, aquí es donde lo haremos // use ese 'si targetObject es más grande que el objeto de evento' que configuramos en // la función init (). Solo voy a caminar a través de la x porque la y es // casi la misma (¿en qué se diferencia? ? piénselo!) si (xOppositeEdge) / * así que primero, "el ancho del eventObject, - el ancho del targetObject - 50", * aquí, el ancho del targetObject es mayor que el del eventObject * este permitirá que el borde opuesto del objeto objetivo esté a 50 px desde * el borde opuesto. Si va a la película de ejemplo y reduce la imagen a * 10% y la lanza alrededor, aumente el tamaño al 200% e intente y note * qué ventaja está haciendo qué, entonces verá la diferencia entre los rebotes. * Esa es la mejor manera de entender esta parte. * / if (targetObject.x < (eventObject.width - targetObject.width - 50))  xDiff = -1 * xDiff; targetObject.x = eventObject.width - targetObject.width - 50;  // this does the same thing for the other edge. if(targetObject.x > 50) xDiff = -1 * xDiff; targetObject.x = 50;  // esto es si el objeto de destino es más pequeño que el eventObject. else / * así que nuevamente estamos probando los bordes del targetObject contra el objeto de evento *. Esta vez estamos tratando con el mismo borde (bueno, * 5px fuera del borde). Así que esto rebotará como si estuviera golpeando una pared. * / if (targetObject.x < -5)  xDiff = -1 * xDiff; targetObject.x = -5;  if(targetObject.x > (eventObject.width - (targetObject.width - 5))) xDiff = -1 * xDiff; targetObject.x = eventObject.width - (targetObject.width - 5);  if (yOppositeEdge) if (targetObject.y < (eventObject.height - targetObject.height - 50))  yDiff = -1 * yDiff; targetObject.y = eventObject.height - targetObject.height - 50;  if(targetObject.y > 50) yDiff = -1 * yDiff; targetObject.y = 50;  else else if (targetObject.y < -5)  yDiff = -1 * yDiff; targetObject.y = -5;  if(targetObject.y > (eventObject.height - (targetObject.height - 5))) yDiff = -1 * yDiff; targetObject.y = eventObject.height - (targetObject.height - 5);  // bien, si tiene preguntas sobre esa parte, solo publique un comentario al respecto y las contestaré. // aquí están los vars sider y Topper (como los de la función pan). var sider: int = xDiff + targetObject.x; var Topper: int = yDiff + targetObject.y; // Necesitamos preparar esto para la próxima ronda. MouseCurrX = MouseCurrX + xDiff; MouseCurrY = MouseCurrY + yDiff; // y luego el if moveX, Y (nuevamente como la función pan) if (moveY) targetObject.y = Topper; if (moveX) targetObject.x = sider;  // y ahora configure nuestro ratón artificial prev arMousePrevX = oldxer; arMousePrevY = oldyer; // y si no estamos en modo sin fricción (OriginalDecay = 1) // vamos a restar una pequeña cantidad de nuestra descomposición, a // le da un poco más de alivio natural. si (originaldecay < 1)  Decay = Decay - .004;  // so the moving is done.  // if the button is down we need to remove the listener. else  eventObject.removeEventListener(Event.ENTER_FRAME, theRepeater);  // now we need to check if the effect is over, which is if our x and y diffs are less than 1px. if((Math.abs(xDiff) < 1 && Math.abs(yDiff) < 1))  eventObject.removeEventListener(Event.ENTER_FRAME, theRepeater);  

Y con eso, nuestra clase está terminada..


Paso 9: El código de clase completado

Puede capturar el código completado del código fuente, vinculado en la parte superior del tutorial. Está en la clase PanAndThrow.as.


Paso 10: hacer algo con él

Para hacer algo con esto necesitamos volver al MXML y agregar algunas líneas de código. Agregue nuestra declaración en la sección de variables globales, complete el método de decaimiento y llame a nuestra función panear y lanzar init (). Con todo lo agregado, aquí está el archivo MXML completo: