requestAnimationFrame looping causes velocity to increase when it says it's 0

Viewed 41

This is the best way I could frame the question. I have two squares on the screen, and am trying to program collision detection. This is vanilla javascript and my code has detailed comments, please take a look, I have been stuck on this for some time.

To be specific, I set the square.yVelocity to 0 when touching any point within the top width of square2(also did this with x and sides). Even with this being set, and showing in the console when logged, square continues to move through square2.

Here is my code:

const context = document.getElementById("canvasmulti").getContext("2d");

canvasmulti.width  = window.innerWidth;
canvasmulti.height = window.innerHeight;

//CHARACTER:
const square = {
    height: 75,
    jumping: true,
    width: 75,
    x: canvasmulti.width - 75,
    xVelocity: 0,
    y: canvasmulti.height / 2,
    yVelocity: 0
  };

  const square2 = {
    height: 75,
    jumping: true,
    width: 75,
    x: 0,
    xVelocity: 0,
    y: canvasmulti.height / 2,
    yVelocity: 0
  };

//MOVEMENT:
const controller = {
    left: false,
    right: false,
    up: false,
    keyListener: function (event) {
      let key_state = (event.type == "keydown") ? true : false;
      switch (event.keyCode) {
        case 37: // left arrow
          controller.left = key_state;
          break;
        case 38: // up arrow
          controller.up = key_state;
          break;
        case 39: // right arrow
          controller.right = key_state;
          break;
      }
    }
  };

  const controller2 = {
    left: false,
    right: false,
    up: false,
    keyListener: function (event) {
      let key_state = (event.type == "keydown") ? true : false;
      switch (event.keyCode) {
        case 65: // left arrow
          controller2.left = key_state;
          break;
        case 87: // up arrow
          controller2.up = key_state;
          break;
        case 68: // right arrow
          controller2.right = key_state;
          break;
      }
    }
  };

  const loop = function () {

    //controller one
    if (controller.up && square.jumping == false) {
      square.yVelocity -= 30;
      square.jumping = true;}
    if (controller.left) {
      square.xVelocity -= 0.5;}
    if (controller.right) {
      square.xVelocity += 0.5;}
  
    //controller two
    if (controller2.up && square2.jumping == false) {
        square2.yVelocity -= 30;
        square2.jumping = true;}
    if (controller2.left) {
        square2.xVelocity -= 0.5;}
    if (controller2.right) {
        square2.xVelocity += 0.5;}

      //controller one
    square.yVelocity += 1.5;// gravity
    square.x += square.xVelocity;
    square.y += square.yVelocity;
    square.xVelocity *= 0.9;// friction
    square.yVelocity *= 0.9;// friction
  
    //controller two
    square2.yVelocity += 1.5;// gravity
    square2.x += square2.xVelocity;
    square2.y += square2.yVelocity;
    square2.xVelocity *= 0.9;// friction
    square2.yVelocity *= 0.9;// friction

    // if square1 is falling below floor line
    if (square.y > canvasmulti.height - 75) {
      square.jumping = false;
      square.y = canvasmulti.height - 75;
      square.yVelocity = 0;
    }

    // if square2 is falling below floor line
    if (square2.y > canvasmulti.height - 75) {
        square2.jumping = false;
        square2.y = canvasmulti.height - 75;
        square2.yVelocity = 0;
    }
  
    // if square1 is going off the left of the screen
    if (square.x < 0) {
      square.x = 0;
    } else if (square.x > canvasmulti.width - 75) {// if square goes past right boundary
      square.x = canvasmulti.width - 75;
    }

    // if square2 is going off the left of the screen
    if (square2.x < 0) {square2.x = 0;}
    else if (square2.x > canvasmulti.width - 75) {// if square goes past right boundary
        square2.x = canvasmulti.width - 75;
    }

    // Creates the backdrop for each frame
    context.fillStyle = "#394129";
    context.fillRect(0, 0, canvasmulti.width, canvasmulti.height); // x, y, width, height

    // Creates and fills square1 for each frame
    context.fillStyle = "#8DAA9D"; // hex for cube color
    context.beginPath();
    context.rect(square.x, square.y, square.width, square.height);
    context.fill();

    // Creates and fills square2 for each frame
    context.fillStyle = "#781818"; // hex for cube color
    context.beginPath();
    context.rect(square2.x, square2.y, square2.width, square2.height);
    context.fill();

    // Collision detection of square1 with square2

    if (square.x <= square2.x + square2.width &&
        square.x >= square2.x + square2.width - square2.width/2 && square.y >= square2.y &&
        square.y <= square2.y + square2.height)
        {square.xVelocity = 0;}; // left square1 touching right square2

    if (square.x + square.width >= square2.x && square.x + square.width <= square2.x + square2.width/2 && 
        square.y >= square2.y &&
        square.y <= square2.y + square2.height)
        {square.xVelocity = 0;}; // right square1 touching left square2

    if (square.x <= square2.x + square2.width &&
        square.x >= square2.x && square.y + square.height >= square2.y )
        {square.yVelocity = 0;}; // bottom left square1 touching top square2

     if (square.x + square.width <= square2.x + square2.width &&
         square.x + square.width >= square2.x && square.y + square.height >= square2.y )
        {square.yVelocity = 0;}; // bottom right square1 touching top square2

    // Collision detection of square2 with square1


    // call update when the browser is ready to draw again
    window.requestAnimationFrame(loop);

  };

  //square1
  window.addEventListener("keydown", controller.keyListener)
  window.addEventListener("keyup", controller.keyListener);
  //square2
  window.addEventListener("keydown", controller2.keyListener)
  window.addEventListener("keyup", controller2.keyListener);

  window.requestAnimationFrame(loop);
<canvas id="canvasmulti"></canvas>

1 Answers

The reason, I believe, is because you have already added the vector. So if you're going to make the velocity 0, you may want to set the position manually or subtract the velocity before clearing it.

for example:

if (square.x <= square2.x + square2.width &&
  square.x >= square2.x + square2.width - square2.width/2 && square.y >= square2.y &&
  square.y <= square2.y + square2.height)
  {
    // left square1 touching right square2
    square.x = square2.x + square2.width; // <== set it to a position where they don't overlap
    square.x -= square.xVelocity; // <== OR just subtract it
    square.xVelocity = 0;
  }

it gets a bit more complicated with the y vector, since you need to consider the gravity too, so setting the value may work better than adjusting it.

Related