2016-06-15 4 views
1

Ich versuche ein Sprite mit den Pfeiltasten zu verschieben. Unten ist die Logik, die bewirken sollte, dass das Sprite sich diagonal bewegt, wenn zwei Tasten gedrückt werden. Dies ist jedoch nicht der Fall. Es wird sich nur in eine Richtung bewegen. Da ich jeden keyCode als Boolean innerhalb einer Objekteigenschaft speichern möchte, wenn ich eine Taste drücke, würde ich denken, dass dies kein Problem sein sollte, aber ich kann es nicht zum Laufen bringen. Ich habe auch versucht, ein Array zu verwenden, um diese Booleschen Werte zu speichern und stattdessen diese Werte zu überprüfen. Kein Glück.So ändern Sie die Richtung des Sprites in Diagonale, wenn zwei Bewegungstasten gleichzeitig gedrückt werden

Ich bin am Ende meines Wissens und wäre sehr dankbar für einige Hilfe. Ich habe stackoverflow und viele verschiedene Blogs beim Aufbau von 2D-Spielen durchforstet, aber nichts, was ich versuche, funktioniert.

var keyState = {}; 

window.onkeydown = window.onkeyup = function(e) { 
    keyState[e.keyCode] = e.type == 'keydown'; 
    // checks for up and left 
    if (keyState[38] && keyState[37]) { 
    player.pos.x -= 2; 
    player.pos.y -= 2; 
    } 
    // checks for up and right 
    else if (keyState[38] && keyState[39]) { 
    player.pos.x += 2; 
    player.pos.y += 2; 
    } 
    // checks for down and left 
    else if (keyState[40] && keyState [37]) { 
    player.pos.x -= 2; 
    player.pos.y -= 2; 
    } 
    // checks for down and right 
    else if(keyState[40] && keyState [39]) { 
    player.pos.x += 2; 
    player.pos.y -= 2; 
    } 
    // checks for up 
    else if (keyState[38]) { 
    player.animation.y = 64; 
    player.pos.y -= 2; 
} 
}; 

Antwort

1

Sie müssen die Bewegungslogik aus dem Ereignis-Listener entfernen. Lassen Sie das Schlüsselereignis nur den aktuellen Status jedes Schlüssels protokollieren (nach oben oder unten), dann überprüfen Sie in der Hauptschleife den Status und verschieben Sie das Spiel nach Bedarf.

Da ich mir nicht sicher bin, ob die Bewegung konstant sein soll oder nur beim Drücken, habe ich die Option zur Änderung des Verhaltens mit der Konstantenflagge MOVE_ONLY_ON_PRESS wenn echte Bewegung nur wenn eine Presse zuerst erkannt wird. Damit keine Tastenanschläge verpasst werden, lösche ich das Schlüsselflag in der Hauptschleife.

Im Folgenden finden Sie ein Beispiel für die Verwendung der Tastatur für ein Spiel.

// global key log; 
var keyState = []; 
const KEY_UP = 38; 
const KEY_DOWN = 40; 
const KEY_LEFT = 37; 
const KEY_RIGHT = 39; 

// Player 
var player = {}; 
player.x = 100; 
player.y = 100; 
const MOVE_SPEED = 2; 
const MOVE_ONLY_ON_PRESS = false; // This will toggle constant movement or only on press 

// from your code 
window.onkeydown = window.onkeyup = function (e) { 
    if (MOVE_ONLY_ON_PRESS) { 
     if (e.type === 'keydown') { 
      keyState[e.keyCode] = true; 
     } 
    } else { 
     keyState[e.keyCode] = e.type == 'keydown'; 
    } 

} 

// in the main loop; 
function update(timer) { 
    // you dont need to test for the combinations (ie up left) when its just simple movement 
    if (keyState[KEY_UP]) { 
     player.y -= MOVE_SPEED; 
     if (MOVE_ONLY_ON_PRESS) { keyState[KEY_UP] = false; } 
    } 
    if (keyState[KEY_DOWN]) { 
     player.y += MOVE_SPEED; 
     if (MOVE_ONLY_ON_PRESS) { keyState[KEY_DOWN] = false; } 
    } 
    if (keyState[KEY_LEFT]) { 
     player.x -= MOVE_SPEED; 
     if (MOVE_ONLY_ON_PRESS) { keyState[KEY_LEFT] = false; } 
    } 
    if (keyState[KEY_RIGHT]) { 
     player.x += MOVE_SPEED; 
     if (MOVE_ONLY_ON_PRESS) { keyState[KEY_RIGHT] = false; } 
    } 
    requestAnimationFrame(update); 

} 
requestAnimationFrame(update); 

Bitfelder.

Eine andere Möglichkeit, die Pfeiltasten zu vereinfachen, besteht darin, die ersten 4 Bits einer Zahl entsprechend einer Taste zu setzen, ein Bit pro Taste, dann ist es einfach, Kombinationen von Tasten als jede der 16 möglichen Kombinationen zu testen hat eine eindeutige Nummer. Sie könnten auf diese Weise viele weitere Schlüssel zuordnen, aber es wird ein wenig unpraktisch, wenn Sie zu weit gehen. sie

var arrowBits = 0; // the value to hold the bits 
const KEY_BITS = [4,1,8,2]; // left up right down 
const KEY_MASKS = [0b1011,0b1110,0b0111,0b1101]; // left up right down 
window.onkeydown = window.onkeyup = function (e) { 
    if(e.keyCode >= 37 && e.keyCode <41){ 
     if(e.type === "keydown"){ 
      arrowKeys |= KEY_BITS[e.keyCode - 37]; 
     }else{ 
      arrowKeys &= KEY_MASKS[e.keyCode - 37]; 
     } 
    }  
} 

Dies sind 8 der 16 möglichen Kombinationen

So setzen

// postfix U,D,L,R for Up down left right 
const KEY_U = 1; 
const KEY_D = 2; 
const KEY_L = 4; 
const KEY_R = 8; 
const KEY_UL = KEY_U + KEY_L; // up left 
const KEY_UR = KEY_U + KEY_R; // up Right 
const KEY_DL = KEY_D + KEY_L; // 
const KEY_DR = KEY_D + KEY_R; // 

Dies ist, wie Sie dann testen

if ((arrowBits & KEY_UL) === KEY_UL) { // is UP and LEFT only down 
if (arrowBits & KEY_UL) {    // is Up left down (down and right may also be down) 
if ((arrowBits & KEY_U) === KEY_U) { // is Up only down 
if (arrowBits & KEY_U) {    // is Up down (any other key may be down) 
if (!(arrowBits & KEY_U)) {   // is Up up (any other key may be down) 
if (!arrowBits) {      // no keys are down 
if (arrowBits) {      // any one or more keys are down 
+0

Schöne Perspektive. In meiner Situation muss ich jedoch nach Kombinationen suchen. Dies liegt daran, dass ich ändern muss, welcher Teil des Sprite-Blatts verwendet wird, wenn jede Richtung gedrückt wird. Wenn ich jedoch nur vier verschiedene Richtungen verwende, wäre das in Ordnung. Ich kann wahrscheinlich einfach eine if-Anweisung hinzufügen, die auf den reziproken Wert prüft, ob mehrere keystates gleichzeitig gedrückt werden, und dann einen else-Block verwenden, der das ausführt, was Sie geschrieben haben. – Streamer

+0

@Azurasky Normalerweise mache ich die Pfeiltasten zu einem einzigen Wert Einstellung zuordnen die Einstellung der Bits 0-3 nach oben, unten, links, rechts. Dann kann ich nach einer von 16 möglichen Kombinationen suchen oder einfach ein bisschen maskieren, um zu sehen, ob die Taste gedrückt ist. ZB Up Bit 0 zum Setzen von 'keyMap | = 1' zum Löschen von' keyMap & = 0b1110' und wenn ich nach UP, LEFT (Bits 0,2) 'if (keyMap === 0b0101) {'oder if (keyMap === 5) '(0b ist das binäre Zahlenpräfix und 0x ist das hexadezimale Präfix, das für das Arbeiten mit Bitfeldern praktisch ist) – Blindman67

+0

Oh Mann, dieses Zeug ist schwer zu verdauen. Ich schaue mir etwas Dokumentation über Bitfelder an (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) und habe gerade erfahren, dass .toString (2) auf eine Zahl gibt ihre binäre Darstellung zurück. Deine Antwort ging von gut zu großartig nach deinem Schnitt! Ich lerne so viel. – Streamer

2

Sie explizit die Objektschlüssel Werte als booleans gesetzt sollte und Sie sollten sie in separaten keydown/keyup Handler wechseln:

let keysdown = {}; 

window.addEventListener('keydown', function(evt) { 
    keysdown[evt.which] = true; 

    if (keysdown["38"] === true && keysdown["37"] === true) { 
    console.log('up & left'); 
    } else if (keysdown["38"] === true && keysdown["39"] === true) { 
    console.log('up & right'); 
    } else if (keysdown["40"] === true && keysdown["37"] === true) { 
    console.log('down and left'); 
    } else if (keysdown["40"] === true && keysdown["39"] === true) { 
    console.log('down and right'); 
    } else if (keysdown["38"] === true) { 
    console.log('up'); 
    } 
}, false); 

window.addEventListener('keyup', function(evt) { 
    keysdown[evt.which] = false; 
}, false); 

Dieser protokolliert alle richtigen Tastenkombinationen für mich.

+0

Es funktioniert. Ihre Antwort hilft mir nicht wirklich zu verstehen, warum mein Code nicht funktioniert hat. – Streamer

+0

@Azurasky. Machen Sie die Anstrengung, analytisch zu sein! Untersuchen Sie den Arbeitscode, um zu sehen, warum es funktioniert. Dies wird Ihnen helfen zu verstehen, warum Ihr Code nicht funktioniert. ;-) – markE

+0

@markE Die Logik ist fehlerhaft. Schlüsselereignisse werden einmal pro Tastendruck ausgelöst, also Taste "unten", dann "links" werden zwei Ereignisse ausgelöst, die Logik wird beim ersten Ereignis nach unten und das zweite Ereignis wird nach unten und links bewegt, dann wird die Taste zweimal ausgelöst Wenn Sie die Taste "down" loslassen, wird ein zweiter Zug nach links hinzugefügt (weil er immer noch als abwärts gespielt wird), und die endgültige Veröffentlichung wird nichts bewirken. – Blindman67

0

kann ich Ihnen nicht sagen, Warum funktioniert dein Code nicht? Wenn ich die Spielerbewegungen durch Konsolenlogs ersetze, funktioniert es für mich.

Obwohl es ziemlich primitiv ist.

Zuerst den Keystate-Manager von der Bewegungslogik trennen.

var isKeyDown = (function(alias){ 
    for(var i=0, a=Object.create(null); i<256;) a[i++]=false; 
    for(var k in alias) i=0|alias[k], i>0 && i<256 && Object.defineProperty(a,k,{get:Function("return this["+i+"]")}); 

    function keyStateHandler(e){ 
     a[e.which||e.keyCode] = e.type==="keydown" 
    } 
    addEventListener("keydown", keyStateHandler, false); 
    addEventListener("keyup", keyStateHandler, false); 

    return a; 
})({ 
    //add some aliases for more readable code 
    up: 38, 
    left: 37, 
    right: 39, 
    down: 40 
}); 

einmal, da das Update-Intervall des keydown-Ereignisses nicht zuverlässig ist, variiert zwischen Browsern und mit dem Update-Intervall des Brwoser weicht nicht flackern verursacht synchronisieren.

Jetzt erstellen Sie eine Hauptschleife für Ihr Spiel und berücksichtigen Sie das Timing. Obwohl requestAnimationFrame auf eine konstante Framerate abzielt, haben Sie möglicherweise Verzögerungen, und Sie möchten nicht, dass sich Ihr Player während dieser Verzögerungen mit unterschiedlichen Geschwindigkeiten bewegt.

var lastCall = Date.now(); 
function tick(){ 
    requestAnimationFrame(tick); 

    var now = Date.now(), 
     time = (now - lastCall)/1000; //time in seconds 
     //because it's easier to think in terms like 2px/s 
     //than 0.002px/ms or 0.0333 px/frame 
    lastCall = now; 

    move(time); 
} 
tick(); 

jetzt die tatsächliche Bewegung:

//the speed of your player: it would be better if this would be 
//a property of the player than hardcoded like you did, or global like this 
var speed = 2; // 2px/second 
function move(time){ 
    //accounts for varying framerates 
    //opposite directions cancel each other out 
    var dx = (isKeyDown.right - isKeyDown.left) * time, 
     dy = (isKeyDown.down - isKeyDown.up) * time; 

    //taking account for diagonals 
    if(dx && dy) dx /= Math.SQRT2, dy /= Math.SQRT2; 

    player.pos.x += dx * speed; 
    player.pos.y += dy * speed; 
} 
Verwandte Themen