En la primera parte de esta serie, presentamos la idea de usar spriting como una forma sencilla y multiplataforma de tener una animación interactiva para la web. En la segunda parte, conseguimos algunas animaciones funcionando, y en la tercera limpiamos nuestro código y lo preparamos para la web.
Ahora, en nuestra parte final de hoy, vamos a caminar a través de la configuración manejadores de eventos de modo que, en lugar de responder a los botones pulsados, nuestros robots sigan el mouse alrededor de la pantalla. En el proceso, también hablaremos sobre cómo hacer que el código sea compatible con el navegador y la pantalla táctil.
Si echas un vistazo a nuestro código de la última vez, verás que mientras el código funciona bien (y con varios robots), no hay una manera muy fácil de indicar el código para que se ejecute..
Controladores de eventos son comandos que le dicen a cierto código que se ejecute cuando se desencadenan ciertos eventos. Por ejemplo, podrías tener mi_función ()
ejecutar cada vez que un usuario haga clic en su div
con el id 'my_div'
. O podrías tener my_other_function ()
ejecutar cada vez que un usuario mueve su mouse sobre 'my_other_div'
.
En teoría, esta es una idea bastante simple y directa. Desafortunadamente, una vez que comienzas a involucrar diferentes navegadores, esto puede ser un poco confuso. En un mundo ideal, cada navegador web interpretaría el mismo código y HTML de la misma manera, y los desarrolladores escribirían el código una vez y funcionaría de la misma manera para todos los usuarios. En el mundo real, los diferentes navegadores pueden tener comandos completamente diferentes para hacer lo mismo (* tos * * tos * Internet Explorer), y, a veces, tratar de conseguir que una sola pieza de código se ejecute de la misma forma en todos los navegadores puede sentirse como arrear gatos. Recientemente, la situación ha mejorado mucho, ya que Chrome, Firefox, Safari y Opera responden de manera muy similar al código, Internet Explorer 9 y 10 están mucho más en línea con los estándares que las versiones anteriores, y casi nadie usa Internet Explorer. 7 o 6 más. Por lo tanto, para nuestro código, conseguiremos que los controladores de eventos funcionen tanto para los navegadores modernos como para Internet Explorer 8.
Como nota al margen, este es un caso en el que realmente vale la pena usar una biblioteca robusta de JavaScript, como jQuery. jQuery hace todo el trabajo por usted en las pruebas entre navegadores, por lo que solo tendrá que ingresar un comando y la biblioteca jQuery lo traducirá para cada navegador detrás de escena. Además, muchos de los comandos en jQuery son mucho más intuitivos y simples que el JavaScript central también..
Pero, como soy terco, y ya que esta es una oportunidad de aprendizaje, continuaremos por el camino difícil y haremos todo esto solo con JavaScript y sin dependencias.!
Entonces, nuestro primer paso será decidir cómo queremos interactuar exactamente con la página. Cuando muevo mi mouse sobre el área del escenario, quiero que todos los robots corran hacia el mouse. Cuando alcancen el mouse, o si el mouse está directamente sobre ellos, quiero que dejen de correr. Si el ratón cruza sobre ellos, quiero que salten. Y, finalmente, cuando el mouse abandone el área del escenario, quiero que dejen de correr. Comenzaremos adjuntando estos eventos dentro del RobotMaker
función:
stage.addEventListener ('mousemove', stage_mousemove_listener, false); robot.addEventListener ('mouseover', robot_mouseover_listener, false); stage.addEventListener ('mouseout', stage_mouseout_listener, false);
Entonces, en las líneas anteriores, hemos dicho que cada vez que el usuario mueve el mouse dentro del elemento de escenario, activamos una función llamada stage_mousemove_listener ()
(note que no incluimos los paréntesis en el comando). Del mismo modo, cuando el usuario mueve el mouse sobre el elemento robot, se dispara robot_mouseover_listener ()
, y cuando el usuario mueve el mouse fuera del escenario, se dispara stage_mouseout_listener ()
.
Desafortunadamente, como mencionamos anteriormente, Internet Explorer 8 y versiones anteriores tienen un comando (similar pero) diferente para hacer lo mismo, así que tendremos que probar para saber qué comando entenderá el navegador del usuario y cómo hacerlo..
if (stage.addEventListener) // Probaremos si este comando está disponible stage.addEventListener ('mousemove', stage_mousemove_listener, false); robot.addEventListener ('mouseover', robot_mouseover_listener, false); stage.addEventListener ('mouseout', stage_mouseout_listener, false); else // Si no, tenemos que usar los comandos de IE stage.attachEvent ('onmousemove', stage_mousemove_listener); robot.attachEvent ('onmouseover', robot_mouseover_listener); stage.attachEvent ('onmouseout', stage_mouseout_listener);
Puede notar que el formato de los comandos es muy similar, pero tiene algunas diferencias importantes, como se dice 'addEventListener'
mientras el otro dice 'attachEvent'
. Uno dice 'movimiento del ratón'
mientras el otro dice 'onmousemove'
. Uno requiere un tercer parámetro, mientras que el otro solo usa dos. Mezclar cualquiera de estos hará que el comando no se ejecute. Estos son los tipos de cosas que harán que quieras golpear tu cabeza contra la pared. Desafortunadamente, este no es el final de la codificación adicional que tendremos que hacer para la capacidad de navegador cruzado.
A continuación, vamos a escribir las funciones de escucha. Comenzaremos con la función que se activa cuando el usuario se mueve sobre el escenario. Ya que esta es una movimiento del ratón
oyente, esta función se activará cada vez que el mouse se mueva dentro del área del escenario (lo que significa que se disparará varias veces por segundo mientras el mouse se mueve). Esta función deberá comparar la ubicación del robot con la ubicación del mouse y hacer que el robot se comporte en consecuencia. Cada vez que se activa la función, verificará si el robot necesita continuar en la misma dirección o cambiar los comportamientos. Por lo tanto, tendrá que ser algo como esto:
// Dentro de RobotMaker // Necesitaremos introducir algunas variables adicionales para rastrear var mouseX; // Para rastrear la posición horizontal del mouse var running_dir = "; // Para rastrear si (y dónde) el robot está ejecutando actualmente var stageOffset; // Para rastrear la posición de la función de escenario stage_mousemove_listener (e) // Encuentre la posición horizontal de el mouse dentro del escenario ... // Esa posición se guardará en 'mouseX' // Luego comparamos 'mouseX' con el robot, y decidimos si necesitamos correr de manera diferente si (((robot.offsetLeft + (15 * run_speed )) < (mouseX - robot.offsetWidth)) && running_dir !== 'r' && (!jump_timer || jump_timer === undefined)) // If the mouse is in the stage and to the right of the robot, make run right, if not already running_dir = 'r'; clearTimeout(run_timer); run_r(1, robot.offsetLeft); else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== 'l' && (!jump_timer || jump_timer === undefined)) // If the mouse is in the stage and to the left of the robot, make run left, if not already running_dir = 'l'; clearTimeout(run_timer); run_l(1, robot.offsetLeft); else if ((robot.offsetLeft < mouseX) && ((robot.offsetLeft + robot.offsetWidth) > mouseX) && running_dir! == "&& (! jump_timer || jump_timer === undefined)) // Si el mouse está en el escenario y sobre un robot, deténgase y desactive running_dir running_dir ="; clearTimeout (run_timer); if (face_right) robot.style.backgroundPosition = "0px 0px"; else robot.style.backgroundPosition = "0px -50px"; // Si nada de lo anterior es verdadero, entonces dejamos que nuestro comportamiento actual continúe
Entonces, en la función anterior, una vez que somos capaces de encontrar mouseX
, lo comparamos con el lugar donde se encuentra el robot y activamos o detenemos las diferentes funciones de ejecución según sea necesario. Desafortunadamente, encontrando mouseX
Es un poco complicado, ya que la posición del mouse es otra cosa que diferentes navegadores hacen de manera diferente. En lugar de (más) explicaciones complicadas y largas, aquí está el método de búsqueda en varios navegadores mouseX
, inspirado en el excelente blog Quirksmode (que es una gran fuente para el estudio de JavaScript más avanzado).
function stage_mousemove_listener (e) var posX = 0; si (! e) var e = window.event; if (e.pageX) posX = e.pageX; else if (e.clientX) posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; mouseX = posX - stageOffset.xpos; // ¡Y encontramos mouseX!
Tenemos un argumento llamado mi
En la función, aunque no le pasemos nada. Como este es un detector de eventos, podemos tener una variable automática llamada mi
que almacena información de eventos como datos del ratón. Pero como los diferentes navegadores lo almacenan de manera diferente, tenemos que agregar muchos pasos adicionales.
Finalmente encontramos mouseX
encontrando posx
(que es la posición x del mouse en la página) y restar a qué distancia está el escenario del extremo izquierdo de la página (almacenado en stageOffset.xpos
). Esto nos permite saber a qué distancia del borde izquierdo del escenario está el mouse, lo cual podemos comparar directamente con robot.offsetLeft
. Como el escenario podría ubicarse de manera diferente en la página dependiendo del diseño, también necesitaremos encontrar el desplazamiento de píxeles exacto del escenario para que la función sea precisa, y almacenar esa información en stageOffset
. Afortunadamente, hay un buen truco que podemos usar para encontrar el desplazamiento absoluto de un elemento con esta función del blog de Vishal Astik..
// Dentro de RobotMaker var x = 0; var y = 0; function find_stage_offset (el) x = el.offsetLeft; y = el.offsetTop; el = el.offsetParent; while (el! == null) x = parseInt (x) + parseInt (el.offsetLeft); y = parseInt (y) + parseInt (el.offsetTop); el = el.offsetParent; devuelve xpos: x, ypos: y; var stageOffset = find_stage_offset (stage);
Así que ahora que hemos escrito el movimiento del ratón
oyente, los demás serán mucho más fácil. Para el robot ratón sobre
Escucha, solo necesitamos comprobar si el robot ya está saltando y, si no, detener el temporizador de ejecución y hacer que salte..
function robot_mouseover_listener () if (! jump_timer || jump_timer === undefined) clearTimeout (run_timer); jmp (verdadero, robot.offsetTop);
los mouseout
El oyente también es bastante simple. Solo necesitamos restablecer algunas de nuestras variables que estamos usando para rastrear al robot, y si el robot no está saltando, devuélvalo al sprite de pie..
function stage_mouseout_listener () mouseX = undefined; running_dir = "; if (! jump_timer || jump_timer === undefined) clearTimeout (run_timer); if (face_right) robot.style.backgroundPosition =" 0px 0px "; else robot.style.backgroundPosition =" 0px - 50px ";
Las funciones que animan los movimientos de correr y saltar no han cambiado mucho esta vez. Acabamos de añadir la variable de seguimiento. running_dir
, eliminado la declaración que verifica si el robot está a punto de chocar contra la pared (ya que esto es redundante con nuestra mouseout
Función), y agregue un poco de código a la función de salto que verifica de nuevo si el robot debería comenzar a ejecutarse si el mouse se encuentra dentro del escenario después de que salga de un salto. Aquí está el código final (bastante grande):
function run_r (phase, left) face_right = true; running_dir = 'r'; if ((left + (15 * run_speed)) < (mouseX - robot.offsetWidth)) // if mouse is to the right, run left = left + (15 * run_speed); robot.style.left = left+"px"; switch (phase) case 1: robot.style.backgroundPosition = "-40px 0px"; run_timer = setTimeout(function()run_r(2, left);, 200); break; case 2: robot.style.backgroundPosition = "-80px 0px"; run_timer = setTimeout(function()run_r(3, left);, 200); break; case 3: robot.style.backgroundPosition = "-120px 0px"; run_timer = setTimeout(function()run_r(4, left);, 200); break; case 4: robot.style.backgroundPosition = "-80px 0px"; run_timer = setTimeout(function()run_r(1, left);, 200); break; else if ((left + (15 * run_speed)) < mouseX) // if mouse if above, stop robot.style.backgroundPosition = "0px 0px"; running_dir ="; else // if mouse is to the left, run left running_dir = 'l'; run_l(1, robot.offsetLeft); function run_l(phase, left) face_right = false; running_dir = 'l'; if (mouseX < robot.offsetLeft - (15 * run_speed)) // if mouse is to the left, run left = left - (15 * run_speed); robot.style.left = left+"px"; switch (phase) case 1: robot.style.backgroundPosition = "-40px -50px"; run_timer = setTimeout(function()run_l(2, left);, 200); break; case 2: robot.style.backgroundPosition = "-80px -50px"; run_timer = setTimeout(function()run_l(3, left);, 200); break; case 3: robot.style.backgroundPosition = "-120px -50px"; run_timer = setTimeout(function()run_l(4, left);, 200); break; case 4: robot.style.backgroundPosition = "-80px -50px"; run_timer = setTimeout(function()run_l(1, left);, 200); break; else if (mouseX < (robot.offsetLeft + robot.offsetWidth - (15 * run_speed))) // if mouse overhead, stop robot.style.backgroundPosition = "0px -50px"; running_dir ="; else // if mouse is to the right, run right running_dir = 'r'; run_r(1, robot.offsetLeft); function jmp(up, top) running_dir ="; if (face_right) robot.style.backgroundPosition = "-160px 0px"; else robot.style.backgroundPosition = "-160px -50px"; if (up && (robot.offsetTop > (20 * (1 / jump_height)))) top = top - (top * 0.1); robot.style.top = top + "px"; jump_timer = setTimeout (function () jmp (arriba, arriba);, 60); else if (arriba) arriba = falso; jump_timer = setTimeout (function () jmp (arriba, arriba);, 60); else if (! up && (robot.offsetTop < 115)) top = top + (top * 0.1); robot.style.top = top+"px"; jump_timer = setTimeout(function()jmp(up, top);, 60); else robot.style.top = "120px"; if (face_right) robot.style.backgroundPosition = "0px 0px"; else robot.style.backgroundPosition = "0px -50px"; jump_timer = false; if (mouseX !== undefined) if (((robot.offsetLeft + (15 * run_speed)) < (mouseX - robot.offsetWidth)) && running_dir !== 'r') // make run right, if not already running_dir = 'r'; clearTimeout(run_timer); run_r(1, robot.offsetLeft); else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== 'l') // make run left, if not already running_dir = 'l'; clearTimeout(run_timer); run_l(1, robot.offsetLeft);
Entonces, ahora, tenemos nuestras funciones reescritas que funcionan bien en todos los navegadores ... a menos que esos navegadores tengan entrada táctil. Todavía nos queda un poco más para que nuestros robots funcionen con todo. Ya que las pantallas táctiles se comportan de manera un poco diferente, tendremos que hacer un poco de codificación adicional en nuestros oyentes de eventos.
Necesitamos establecer algunas reglas nuevas para las pantallas táctiles: si se toca la pantalla en cualquier lugar del escenario, el robot correrá hasta ese punto hasta que el dedo se levante. Si el usuario toca el robot, el robot saltará. En primer lugar, agregaremos algunos controladores de eventos táctiles adicionales a nuestra función anterior, y vamos a escribir el código de tal manera que se ejecute automáticamente cada vez que RobotMaster
la función se llama.
(function () if (stage.addEventListener) stage.addEventListener ('touchstart', stage_mousemove_listener, false); stage.addEventListener ('touchmove', stage_mousemove_listener, false); stage.addEventListener ('touchmove', stage_match_most.moy_stall_stall_stall_stall.estation ; stage.addEventListener ('mousemove', stage_mousemove_listener, false); robot.addEventListener ('mouseover', robot_mouseover_listener, false); stage.addEventListener (egentación del ratón), stage_mouseout_listener, false); , stage_mousemove_listener); robot.attachEvent ('onmouseover', robot_mouseover_listener); stage.attachEvent ('onmouseout', stage_mouseout_listener);) ();
No tendremos que preocuparnos de que los escuchas táctiles estén en el formato de Internet Explorer 8, y si algún dispositivo no tiene soporte táctil ignorará los escuchas. Ahora tendremos que actualizar el stage_mousemove_listener ()
Funciona para comportarse de manera diferente si el navegador tiene capacidad táctil.
function stage_mousemove_listener (e) / * * Primero verificamos si se trata de un dispositivo de pantalla táctil (si tiene e.touches) * / if (e.touches) e.preventDefault (); // queremos cancelar lo que el navegador usualmente haría si se tocara allí // Si el toque estaba dentro de los límites del escenario ... si ((e.touches [0] .pageX> stageOffset.xpos) && (e.touches [ 0] .pageX < (stageOffset.xpos + stage.offsetWidth)) && (e.touches[0].pageY > stageOffset.ypos) && (e.touches [0] .pageY < (stageOffset.ypos + stage.offsetHeight))) // we set the mouseX to equal the px location inside the stage mouseX = e.touches[0].pageX - stageOffset.xpos; else // if the touch was outside the stage, we call the mouseout listener stage_mouseout_listener(); /* * If the touch is directly on the robot, then we stop the run timer and make the robot jump */ if ((e.touches[0].pageX > robot.offsetLeft) && (e.touches [0] .pageX < (robot.offsetLeft + robot.offsetWidth)) && (e.touches[0].pageY > (stageOffset.ypos + stage.offsetHeight - robot.offsetHeight)) && (e.touches [0] .pageY < (stageOffset.ypos + stage.offsetHeight)) && (!jump_timer || jump_timer === undefined)) clearTimeout(run_timer); jmp(true, robot.offsetTop); else // Finding the mouseX for non-touch devices… // All of our non-touch device code here
Puede notar que ya no tenemos "puertas" en nuestra RobotMaker
función, pero ya que estamos llamando a todo nuestro código con los controladores de eventos que estamos asignando dentro RobotMaker
, ¡Ya no los necesitamos! Tanto para nuestro escenario como para nuestros personajes, desearemos agregar un poco de CSS especialmente para dispositivos táctiles para que no intente cortar y pegar ninguna imagen cuando un usuario mantenga un dedo sobre ellos..
#stage, .character -webkit-user-select: none;
Y finalmente, declararemos todos nuestros robots en la parte inferior de la página, utilizando el mismo formato que nuestra función de controlador de eventos para que el código se ejecute automáticamente cuando se carga la página. Este método también evita que estos objetos de robot sean variables globales, por lo que La única variable global que tenemos en este script completo es la RobotMaker ()
función.
(function () var j = RobotMaker (document.getElementById ('j'), 1, 1); var j2 = RobotMaker (document.getElementById ('j2'), .8, 5); var j3 = RobotMaker (document .getElementById ('j3'), 1.1, .5); var j4 = RobotMaker (document.getElementById ('j4'), .5, .75);) ();
Por favor revisa el resultado final en todo su esplendor.!
Le recomiendo que estudie el código completo (¡y lo comento todo!), Y también puede descargar los cuatro sprites de robot aquí.
Feliz animando!