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

时间:2019-12-01 12:29:59

标签: javascript html canvas collision

我正在用画布制作游戏,并且我包括一个库来为我处理碰撞。 碰撞工作正常,但是我不确定如何将玩家“冻结”到位,并且在碰撞后不允许沿该方向移动。有人可以帮我吗?

我尝试过的事情:

  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;
  }

我尝试跟踪“先前位置”并将其设置为发生碰撞时的位置,但是它的表现确实很奇怪,实际上并不起作用。

理想情况下,我想在玩家类中创建一个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 
}

2 个答案:

答案 0 :(得分:3)

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

例如moveRight将变为

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

答案 1 :(得分:1)

一种低成本的方法是循环更新坐标(因此,x+=10进行10次x++),并在发生碰撞时“撤消”更改,请参见未命名函数在最后(传递给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>

“游戏”应该响应箭头键,甚至可以同时按下多个键。另外,在开始后使用“整页”,因为它不适合此处的框,并且箭头无论如何都会疯狂滚动所有内容。哦,它需要单击画布一次。


我也看到了修改,我认为您可以检查该页面的https://github.com/RonenNess/SSCD.js#resolve-penetration-or-penetration-prevention部分,并尝试使用repel()