碰撞后如何保持玩家位置?

How to keep player position after collision?

我在 canvas 制作游戏,我已经包含了一个库来为我处理碰撞。 碰撞效果很好,但我不太确定如何 "freeze" 玩家在碰撞后不允许朝那个方向移动。谁能帮帮我?

我尝试了什么:

  moveRight() {
    this.pp.x = this.position.x;
    this.position.x += 20;
  }
  moveLeft() {
    this.pp.x = this.position.x;
    this.position.x -= 20;
  }
  moveUp() {
    this.pp.y = this.position.y;
    this.position.y += 20;
  }
  moveDown() {
    this.pp.y = this.position.y;
    this.position.y -= 20;
  }

我试着跟踪 "previous position" 并将其设置为碰撞时的那个,但它的行为真的很奇怪,实际上不起作用。

理想情况下,我想在我的播放器 class 中创建一个 stop() 函数,我会在播放器与世界发生碰撞时调用它。

非常感谢,非常感谢任何帮助! ! !

我使用 lib(https://github.com/RonenNess/SSCD.js/)to 为我做碰撞测试,这里是代码:

export function collisionDetection(game) {
  let world = new SSCD.World({ grid_size: 1024 });
  let player = new SSCD.Rectangle(
    new SSCD.Vector(game.player.position.x, game.player.position.y),
    new SSCD.Vector(game.player.width, game.player.height)
  );
  let zombie = new SSCD.Rectangle(
    new SSCD.Vector(game.zombie.position.x, game.zombie.position.y),
    new SSCD.Vector(game.zombie.width, game.zombie.height)
  );
  let walls = game.walls;
  walls.forEach(wall => {
    world.add(
      new SSCD.Rectangle(
        new SSCD.Vector(wall.position.x, wall.position.y),
        new SSCD.Vector(wall.width, wall.height)
      )
    );
  });

  if (world.test_collision(player)) {
    game.player.speed = 0;
    return 
}

一种方法是将 20 作为 class 的 property。此 属性 将是“speed”属性。然后您可以使用“this.speed”访问它。一旦你检测到碰撞,将速度设置为 0,你将 "freeze" 你的角色。

例如 moveRight 会变成

moveRight() {
    this.pp.x = this.position.x;
    this.position.x += this.speed;
  }

一种低预算的方法是循环更新坐标(因此 x+=10,执行 10 次 x++),并且 "undo" 发生碰撞时的变化,请参阅最后的未命名函数(传递给 setInterval() 的函数):

function range(l,x,h){
  return l<=x && x<h;
}
function rnd(r){
  return Math.floor(Math.random()*r);
}
function Rect(x,y,w,h){
  this.x=x;
  this.y=y;
  this.w=w;
  this.h=h;
}
Rect.prototype.draw=function(ctx){
  ctx.strokeRect(this.x,this.y,this.w,this.h);
};
Rect.prototype.contains=function(x,y){
  return range(this.x,x,this.x+this.w) &&
    range(this.y,y,this.y+this.h);
}
Rect.prototype.intersects=function(r){
  return this.contains(r.x,r.y) ||
    this.contains(r.x+r.w,r.y) ||
    this.contains(r.x,r.y+r.h) ||
    this.contains(r.x+r.w,r.y+r.h);
}
const player=new Rect(1,1,10,10);
const walls=[];
for(let i=0;i<5;i++){
  let x=rnd(200);
  let y=rnd(200);;
  walls.push(new Rect(x+20,y+20,rnd(250-x)+10,rnd(250-y)+10));
}
function collide(){
  if(player.x<=0 || player.y<=0 ||
     player.x+player.w>=300 || player.y+player.h>=300)
     return true;
  for(let i=0;i<walls.length;i++)
    if(walls[i].intersects(player))
      return true;
  return false;
}
const ctx=cnv.getContext("2d");
function draw(){
  ctx.clearRect(0,0,300,300);
  ctx.strokeStyle="#FF0000";
  ctx.strokeRect(0,0,300,300);
  ctx.strokeStyle="#0000FF";
  for(let i=0;i<walls.length;i++)
    walls[i].draw(ctx);
  ctx.strokeStyle="#00FF00";
  player.draw(ctx);
}
draw();

const keymap=[false,false,false,false];
addEventListener("keydown",function(event){
  if(range(37,event.keyCode,41))
    keymap[event.keyCode-37]=true;
});
addEventListener("keyup",function(event){
  if(range(37,event.keyCode,41))
    keymap[event.keyCode-37]=false;
});

setInterval(function(){
  for(let i=0;i<10;i++){
    if(keymap[0]){
      player.x--;
      if(collide())
        player.x++;
    }
    if(keymap[1]){
      player.y--;
      if(collide())
        player.y++;
    }
    if(keymap[2]){
      player.x++;
      if(collide())
        player.x--;
    }
    if(keymap[3]){
      player.y++;
      if(collide())
        player.y--;
    }
  }
  draw();
},100);
<canvas id="cnv" width="300" height="300"></canvas>

"Game" 应该响应方向键,甚至可以同时按下多个方向键。另外,在开始后使用 "Full page",因为它不适合这里的方框,无论如何箭头都会疯狂地滚动所有内容。哦,它需要单击 canvas 一次。


我也看到了编辑,我想你可以检查那个页面的 https://github.com/RonenNess/SSCD.js#resolve-penetration-or-penetration-prevention 部分,然后试验 repel().