Home > Net >  How to block the player from leaving the canvas without getting them stuck?
How to block the player from leaving the canvas without getting them stuck?

Time:08-30

I have a special move function that works as intended, however I tried making a feature that tries to block the player from leaving the canvas.

I tried checking to see if the player's x and y was less than the canvas width/height and greater than 0, and here's my method.

const canvas = document.createElement("canvas");
// ...
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// ...
move() {
    this.angle  = this.rotv;
    this.rotv *= this.drag;
    this.vx  = this.ax;
    this.vy  = this.ay;
    this.ax *= this.drag;
    this.ay *= this.drag;
    this.vx *= this.drag;
    this.vy *= this.drag;
    if (this.x < canvas.width - this.width   3.75 && this.x > this.width   3.75) {
      this.x  = Math.cos(this.angle) * this.vx;
    }
    if (this.y < canvas.height - this.height   3.75 && this.y > this.height   3.75) {
      this.y  = Math.sin(this.angle) * this.vy;
    }
  },

However, when you are at the border of the canvas, the player gets stuck and you can no longer move, but you CAN rotate. This is how it looks like.

What am I doing wrong and how can I fix the issue?

Full code:

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var projectileArray = []
var keydown = false

const kbd = {
  ArrowLeft: false, 
  ArrowUp: false, 
  ArrowRight: false,
  ArrowDown: false,
};

const noHoldDown = {
  Space: false,
}

function Projectile(x,y,speed,direction,duration) {
  Object.assign(this, {x,y,speed,direction,duration});
  this.draw = ctx => {
    ctx.arc(this.x, this.y, 3.75, 0, 2 * Math.PI);
    ctx.fillStyle = 'white';
    ctx.fill();
  }
  this.update = ctx => {
    ctx.beginPath();
    this.x  = Math.cos(this.direction) * this.speed;
    this.y  = Math.sin(this.direction) * this.speed;
    this.draw(ctx);
    this.duration--;
  }
  this.isDone = () => this.duration <= 0;
}


const ship = {
  angle: 0,
  color: "white",
  x: canvas.width / 2,
  y: canvas.height / 2,
  width: 10,
  height: 12,
  drag: 0.9,
  accSpeed: 0.025,
  rotSpeed: 0.007,
  rotv: 0,
  ax: 0,
  ay: 0,
  vx: 0,
  vy: 0,
  rotateLeft() {
    this.rotv -= this.rotSpeed;
  },
  rotateRight() {
    this.rotv  = this.rotSpeed;
  },
  accelerate() {
    this.ax  = this.accSpeed;
    this.ay  = this.accSpeed;
  },
  decelerate() {
    this.ax -= this.accSpeed;
    this.ay -= this.accSpeed;
  },
  shoot() {
    let mySpeed = Math.sqrt(this.vx * this.vx   this.vy * this.vy)
    let bullet = new Projectile(this.x, this.y, 3   mySpeed, this.angle, 500)
    projectileArray.push(bullet);
    // projectileArray.push([this.x, this.y, this.angle])
  },
  move() {
    this.angle  = this.rotv;
    this.rotv *= this.drag;
    this.vx  = this.ax;
    this.vy  = this.ay;
    this.ax *= this.drag;
    this.ay *= this.drag;
    this.vx *= this.drag;
    this.vy *= this.drag;
    if (this.x < canvas.width - this.width   3.75 && this.x > this.width   3.75) {
      this.x  = Math.cos(this.angle) * this.vx;
    }
    if (this.y < canvas.height - this.height   3.75 && this.y > this.height   3.75) {
      this.y  = Math.sin(this.angle) * this.vy;
    }
  },
  draw(ctx) {
    ctx.save();
    ctx.lineWidth = 3;
    ctx.translate(this.x, this.y);
    ctx.rotate(this.angle);
    ctx.beginPath();
    ctx.moveTo(this.height, 0);
    ctx.lineTo(-this.height, this.width);
    ctx.lineTo(-this.height, -this.width);
    ctx.closePath();
    ctx.strokeStyle = this.color;
    ctx.stroke();
    ctx.restore();
  }
};

document.addEventListener("keydown", event => {
  if (event.code in kbd) {
    event.preventDefault();
    kbd[event.code] = true;
  }
});
document.addEventListener("keydown", event => {
  if (event.code in noHoldDown) {
    if (!keydown) {
      keydown = true;
      ship.shoot();
    }
  }
});

document.addEventListener('keyup', event => {
  if (event.code in noHoldDown) {
    keydown = false;
  }
});

document.addEventListener("keyup", event => {
  if (event.code in kbd) {
    event.preventDefault();
    kbd[event.code] = false; 
  }
});

(function update() {
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);  

  const shipActions = {
    ArrowLeft: "rotateLeft",
    ArrowUp: "accelerate",
    ArrowDown: "decelerate",
    ArrowRight: "rotateRight",
  };

  for (const key in shipActions) {
    if (kbd[key]) {
      ship[shipActions[key]]();
    }
  }
  ship.move();
  ship.draw(ctx);
  for (var i = 0; i < projectileArray.length; i  ) {
    let bullet = projectileArray[i];
    bullet.update(ctx)
  }
  projectileArray = projectileArray.filter(bullet => !bullet.isDone());
  requestAnimationFrame(update);
})();

CodePudding user response:

Lets make a snippet. I fixed it by trimming the value rather then preventing it from changing when it overflows. Because once it overflowed in your case it got stuck.

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var projectileArray = []
var keydown = false

const kbd = {
  ArrowLeft: false,
  ArrowUp: false,
  ArrowRight: false,
  ArrowDown: false,
};

const noHoldDown = {
  Space: false,
}

function Projectile(x, y, speed, direction, duration) {
  Object.assign(this, {
    x,
    y,
    speed,
    direction,
    duration
  });
  this.draw = ctx => {
    ctx.arc(this.x, this.y, 3.75, 0, 2 * Math.PI);
    ctx.fillStyle = 'white';
    ctx.fill();
  }
  this.update = ctx => {
    ctx.beginPath();
    this.x  = Math.cos(this.direction) * this.speed;
    this.y  = Math.sin(this.direction) * this.speed;
    this.draw(ctx);
    this.duration--;
  }
  this.isDone = () => this.duration <= 0;
}


const ship = {
  angle: 0,
  color: "white",
  x: canvas.width / 2,
  y: canvas.height / 2,
  width: 10,
  height: 12,
  drag: 0.9,
  accSpeed: 0.025,
  rotSpeed: 0.007,
  rotv: 0,
  ax: 0,
  ay: 0,
  vx: 0,
  vy: 0,
  rotateLeft() {
    this.rotv -= this.rotSpeed;
  },
  rotateRight() {
    this.rotv  = this.rotSpeed;
  },
  accelerate() {
    this.ax  = this.accSpeed;
    this.ay  = this.accSpeed;
  },
  decelerate() {
    this.ax -= this.accSpeed;
    this.ay -= this.accSpeed;
  },
  shoot() {
    let mySpeed = Math.sqrt(this.vx * this.vx   this.vy * this.vy)
    let bullet = new Projectile(this.x, this.y, 3   mySpeed, this.angle, 500)
    projectileArray.push(bullet);
    // projectileArray.push([this.x, this.y, this.angle])
  },
  move() {
    this.angle  = this.rotv;
    this.rotv *= this.drag;
    this.vx  = this.ax;
    this.vy  = this.ay;
    this.ax *= this.drag;
    this.ay *= this.drag;
    this.vx *= this.drag;
    this.vy *= this.drag;
    
    this.x  = Math.cos(this.angle) * this.vx;
    this.y  = Math.sin(this.angle) * this.vy;
    
    this.x = Math.min(this.x, canvas.width - this.width)
    this.x = Math.max(this.x, 0   this.width)

    this.y = Math.min(this.y, canvas.height - this.height)
    this.y = Math.max(this.y, 0   this.height)

  },
  draw(ctx) {
    ctx.save();
    ctx.lineWidth = 3;
    ctx.translate(this.x, this.y);
    ctx.rotate(this.angle);
    ctx.beginPath();
    ctx.moveTo(this.height, 0);
    ctx.lineTo(-this.height, this.width);
    ctx.lineTo(-this.height, -this.width);
    ctx.closePath();
    ctx.strokeStyle = this.color;
    ctx.stroke();
    ctx.restore();
  }
};

document.addEventListener("keydown", event => {
  if (event.code in kbd) {
    event.preventDefault();
    kbd[event.code] = true;
  }
});
document.addEventListener("keydown", event => {
  if (event.code in noHoldDown) {
    if (!keydown) {
      keydown = true;
      ship.shoot();
    }
  }
});

document.addEventListener('keyup', event => {
  if (event.code in noHoldDown) {
    keydown = false;
  }
});

document.addEventListener("keyup", event => {
  if (event.code in kbd) {
    event.preventDefault();
    kbd[event.code] = false;
  }
});

(function update() {
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  const shipActions = {
    ArrowLeft: "rotateLeft",
    ArrowUp: "accelerate",
    ArrowDown: "decelerate",
    ArrowRight: "rotateRight",
  };

  for (const key in shipActions) {
    if (kbd[key]) {
      ship[shipActions[key]]();
    }
  }
  ship.move();
  ship.draw(ctx);
  for (var i = 0; i < projectileArray.length; i  ) {
    let bullet = projectileArray[i];
    bullet.update(ctx)
  }
  projectileArray = projectileArray.filter(bullet => !bullet.isDone());
  requestAnimationFrame(update);
})();
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

CodePudding user response:

This solution doesn't necessarily stop the player from leaving the canvas, but it does rebound the player.

In the move() function, do:

move() {
    this.angle  = this.rotv;
    this.rotv *= this.drag;
    this.vx  = this.ax;
    this.vy  = this.ay;
    this.ax *= this.drag;
    this.ay *= this.drag;
    this.vx *= this.drag;
    this.vy *= this.drag;
    this.x  = Math.cos(this.angle) * this.vx;
    this.y  = Math.sin(this.angle) * this.vy;
    if (this.x > canvas.width   ship.height) {
      this.x -= this.x   ship.height
    }
    if (this.x   ship.height < 0) {
      this.x  = canvas.width   ship.height
    }
    if (this.y   ship.height < 0) {
      this.y  = canvas.height   ship.height
    }
    if (this.y > canvas.height   ship.height) {
      this.y -= this.y   ship.height
    }
  },
  • Related