javascriptbooleanp5.jskeypressgame-development

Detect multiple keypresses and trigger an action once in p5.js


I want the user to be able to press a+d once and my game should increase the score, not hold it to increase score, similar to when pressing a+d causes a special effect to occur in a game.

This code did not work so I didn't bother to call it fail attempts test.

function keyPressed() {
    if (key == 'a' && key == 'd')
  score += 1;
}

This is my first failing attempt:

function keyPressed() {
    if (key == 'a' || key == 'd')
  score += 1;
}

This is my second failing attempt.

The reason for it is because when I press 1 button, it still increases the score and when pressing 2 buttons and holding them to increase faster but does not stop, which is not what I have in mind.

Score2keypress.js:

let RightButtom = false;
let LeftButtom = false;

let character = {
  "score": 0
}

function setup() {
  createCanvas(600, 600);
}

function draw() {
  background(220);

  // draw score character
  fill(0, 0, 255); //move6
  text("Score: " + character.score, 20, 120);

  // update score increase character
  if (RightButtom) {
    character.score += 1;
  } //move8
  if (LeftButtom) {
    character.score += 1;
  } //move10

  /////////////ScoreExtra
  // show boolean values onscreen for clarity
  textSize(20);
  text("RightButtom = " + RightButtom +
    "\nLeftButtom = " + LeftButtom, 10, 10, width / 2, height / 2);
}

//////////////ScoreExtra

function keyPressed() {
  if (key == 'a') {
    LeftButtom = true;
  }
  if (key == 'd') {
    RightButtom = true;
  }
}

function keyReleased() {
  if (key == 'a') {
    LeftButtom = false;
  }
  if (key == 'd') {
    RightButtom = false;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>


Solution

  • There are a few approaches. The event-driven approach is using p5's keyPressed and keyReleased callbacks, pulling the key's code string from the native KeyboardEvent object. Adding and removing these key codes to a pressed set lets you implement variants of single-trigger logic.

    const character = {score: 0};
    const pressed = new Set();
    
    function setup() {
      createCanvas(600, 600);
      textSize(20);
    }
    
    function draw() {
      background(220);
      text("Score: " + character.score, 20, 50);
    }
    
    function keyPressed(evt) {
      const {code} = evt;
    
      if (!pressed.has(code)) {
        pressed.add(code);
    
        if (pressed.has("KeyA") && pressed.has("KeyD")) {
          character.score++;
        }
      }
    }
    
    function keyReleased(evt) {
      pressed.delete(evt.code);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

    If you want to detect and take action purely in draw, p5.js provides keyIsDown which accepts a parameter keycode.

    const character = {score: 0};
    const pressed = new Set();
    
    function setup() {
      createCanvas(600, 600);
      textSize(20);
    }
    
    function draw() {
      background(220);
      text("Score: " + character.score, 20, 50);
      
      if (keyIsDown(65) && keyIsDown(68)) {
        if ((keyIsDown(65) && !pressed.has(68)) ||
            (!pressed.has(65) && keyIsDown(68))) {
          character.score++;
        }
    
        pressed.add(65);
        pressed.add(68);
      }
    
      if (!keyIsDown(65)) {
        pressed.delete(65);
      }
      if (!keyIsDown(68)) {
        pressed.delete(68);
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

    As mentioned, there are multiple behavioral variants you can implement. Here's a variant that prevents retriggers with the same key:

    const character = {score: 0};
    const pressed = new Set();
    
    function setup() {
      createCanvas(600, 600);
      textSize(20);
    }
    
    function draw() {
      background(220);
      text("Score: " + character.score, 20, 50);
      
      if (keyIsDown(65) && !pressed.has(65) && // 'a' and 'd'
          keyIsDown(68) && !pressed.has(68)) {
        character.score++;
        pressed.add(65);
        pressed.add(68);
      }
    
      if (!keyIsDown(65)) {
        pressed.delete(65);
      }
      if (!keyIsDown(68)) {
        pressed.delete(68);
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

    In all above cases, the behavior lets the user press and hold one key indefinitely, then press the other. If you want these keys to be pressed on the exact same frame, or within n frames, you could remove the key from the set after it's been in there for n frames and add it to a requireRetrigger set that will prevent it from firing an action until it's been released. keyReleased might be handy here.