2010-06-29 11 views
10

Al presionar la barra espaciadora en el juego se disparará un personaje, presionar la barra espaciadora cuando se muestre un cuadro de confirmación hará que esta casilla desaparezca y al presionar la barra espaciadora en un formato de puntuación más alta se agregará un espacio en un cuadro de entrada. En este ejemplo, hay varios eventos para la misma clave, pero solo uno se dispara a la vez.¿Cuál es la mejor manera de manejar múltiples eventos clave en Javascript?

¿Existe un método general (o específico para Javascript) o una forma de programación para agregar eventos a una determinada clave, por lo que solo se ejecutan bajo ciertas circunstancias?

Por supuesto que se puede hacer así:

var inGame = true|false; 
var inConfirmationBox = true|false; 

function spaceBarHandler(){ 
    if(inGame){ /*shoot*/} 
    else if(inConfirmationBox){ /*remove box*/} 
} 

document.onkeydown = function(){ /* call space bar handler if space bar was pressed */ }; 

Pero esta es una manera muy confusa de programación, ya que las acciones específicas se mezclan entre sí en una función de gestión de la barra de espacio, lo que hace que el mantenimiento dura.

¿Cuál es la mejor manera de manejar eventos múltiples para una clave, de manera que estos eventos solo se disparen bajo ciertas circunstancias?

Respuesta

4

Las funciones son objetos de primera clase en javascript, lo que las hace realmente potentes. Debido a esto, su problema se puede resolver de manera muy elegante.

// the whole thing can be encapsulated 
// into an object actually 

function spaceBarHandler() { 
    var state = spaceBarHandler.state; 
    var actions = spaceBarHandler.actions; 

    // execute function if exists 
    if (actions[state]) { 
     actions[state](); 
    } 
} 

// spaceBar actions 
spaceBarHandler.actions = { 
    shoot: function() { 
    // bang bang 
    }, 
    removeBox: function() { 
    // do it... 
    } 
}; 

// change current state from outside 
// we are in the game 
spaceBarHandler.state = "shoot"; 

// change current state from outside 
// confirmation box is shown 
spaceBarHandler.state = "removeBox"; 

Todos estos casos serán manejados por una función. Si desea extender con otro caso, simplemente agrega otra función al objeto de acciones. Observe cómo todo se encapsula en un objeto.

+0

Creo que esta es la mejor respuesta, ¡gracias! La idea es genial y definitivamente la usaré; también agregaré un método 'addState (name, fn)', que hace que este objeto se complete. Gracias:] – Harmen

+0

Pero aún está lejos de "la mejor manera" de manejar este problema. ¡Una pila administrada de controladores es mucho más conveniente! Como esta pregunta está bastante desactualizada, si alguien está interesado, podría desarrollarme. – Pierre

0

Adjunte los detectores de eventos a elementos individuales en lugar de todo el documento.

document.getElementById('highscore').onkeypress = function(keyEvent) { 
     if (is_spacebar(keyEvent)) //Do something... 
}; 

document.getElementById('game').onkeypress = function(keyEvent) { 
     if (is_spacebar(keyEvent)) //Do something else... 
}; 

Este es un ejemplo simplista. Probablemente tendrá que lidiar con el burbujeo de eventos que se puede controlar al usar addEventListener() para adjuntar funciones a eventos. Debido a problemas de compatibilidad con el navegador (IE) que involucran esto, se debe usar alguna biblioteca JS para tratar los eventos.

+1

Esto no es una mala idea, pero el problema general es que mientras 'document' siempre tiene foco,' # game' won ' Tiene a menos que deliberadamente mueva el foco hacia adentro (y luego puede perder el foco si el usuario hace clic y vuelve a la ventana). – bobince

+0

Hmm sí, ya veo lo que dices. La mentalidad de la aplicación web aquí. Esto es probablemente similar a implantar la capacidad de arrastrar o cambiar el tamaño de un elemento, el detector de eventos 'mousemove' debe adjuntarse a la ventana o al documento; de lo contrario, el evento dejaría de dispararse una vez que el cursor no esté sobre dicho elemento antes de que su posición sea actualizada. la función de evento. Ah bien – MooGoo

0

Hay algunas formas, que normalmente implican la ramificación de código para el modelo de evento "especial" de IE.

Una forma es dejar de pulsaciones de teclas se manejan más abajo del que brotará para el manejador clave documento:

confirmationbox.onkeydown = function(event) { 
    if (event === undefined) event = window.event; 

    // do something with event.keyCode 

    if ('stopPropagation' in event) // standards browsers 
     event.stopPropagation(); 
    else if ('cancelBubble' in event) // IE before version 9 
     event.cancelBubble = true; 
}; 

document.onkeydown = ... // will not be called for keydowns inside confirmationbox 

Otra forma sería la de comprobar el elemento de destino del evento para ver si hay en la caja:

document.onkeydown = function(event) { 
    if (event === undefined) event = window.event; 
    var target = 'target' in event ? event.target : event.srcElement; // srcElement is for IE<9 

    if (target === containerbox || isDescendantOf(target, containerbox) { 
     // do containerbox stuff 
    } else { 
     // do other stuff 
    } 
}; 

function isDescendantOf(element, ancestor) { 
    while (element = element.parentNode) 
     if (element === ancestor) 
      return true; 
    return false; 
} 
+0

excepto lo que sucede cuando el cuadro de confirmación no tiene foco (por ejemplo, foco no configurado, o foco no reiniciado cuando el usuario hace clic en el área de juego) en cuyo caso el cuadro de confirmación ya no captura la entrada –

+0

, ¿hay alguna razón para no usar el operador predeterminado: 'event = event || window.event'? –

+0

Eso es lo que generalmente se quiere; Sin embargo, no estoy seguro de cuál es el comportamiento del OP. Si el origen del evento clave no es importante y solo importa el momento, entonces sí, la única forma de hacerlo sería la variable externa. – bobince

0

En su lugar, podría agregar y eliminar el detector de eventos según sea necesario.

vamos a suponer que usted está usando un marco de JavaScript (si no lo está, entonces probablemente debería estar considerando la cantidad de código JS involucrado en un juego como este)

utilizando PrototypeJS:

cuando juego comienza,

document.observe("keydown",shootHandler()); 

cuando se crea el cuadro de mensaje,

function createBox(text) { 
    ...snip 

    document.observe("keydown",closeBox()); 
    document.fire("game:pause"); 
} 

y, por ejemplo

var paused = false; 

function shoothandler() { 
    if (!paused) { 
     alert("pew! pew!"); 
    } 
} 

function closeBox() { 
    $('messagebox').remove(); 
    document.fire("game:unpaused"); 
    document.stopObserving("keydown",closeBox()); 
} 

document.observe("game:paused", function() { paused = true;}); 
document.observe("game:unpaused", function() { paused = false;}); 
document.observe("game:over", function() { document.stopObserving("keydown",shootHandler());}); 

No he incluido la pantalla de puntuación más alta, pero la teoría es la misma.

Como puede ver, también usé eventos personalizados para notificar el estado de pausa. El mismo evento también podría ser disparado por un botón de puase en la interfaz, etc.

Cuestiones relacionadas