javascript游戏中的碰撞检测

时间:2016-12-24 23:16:04

标签: javascript

我目前正在开发一款小平台游戏。但碰撞检测并不是很好。我已经看了很多这方面的教程,但似乎无法理解它。这是我的代码:



var ctx = document.getElementById("canvas").getContext("2d");
var rightPressed =false;
var spacePressed =false;
var leftPressed=false;
var gravity = 1;
//Player object
var player = {
  x:50,
  y:370,
  dy:0,
  dx:0,
  width:10,
  height:10,
  speed:10,
  jumping:false
};
//Box object
var box ={
  x:200,
  y:350,
  width:50,
  height:50
};

document.addEventListener("keydown", keyDown);
document.addEventListener("keyup", keyUp);

function keyDown(e) {
  if(e.keyCode ==39){
    rightPressed=true;
  }
  if (e.keyCode ==32){
    spacePressed=true;
  }
  if (e.keyCode ==37){
    leftPressed =true;
  }
}
function keyUp(e) {
  if(e.keyCode ==39){
    rightPressed=false;
  }
  if (e.keyCode ==32){
    spacePressed=false;
  }
  if (e.keyCode ==37){
    leftPressed =false;
  }
}
//Draw the ball
function drawBall(){
  ctx.beginPath();
  ctx.arc(player.x,player.y,10,0,Math.PI*2);
  ctx.fillStyle="red";
  ctx.fill();
}
//Draw the box
function drawBox() {
  ctx.fillRect(box.x,box.y,box.width,box.height);
}
//The main function that calls the other functions and handles the logic
function draw(){
  ctx.clearRect(0,0,canvas.width,canvas.height);
  drawBall();
  drawBox();
  if (rightPressed){
    //Right speed of the ball
    player.x+=5;
  }
  if(leftPressed){
    //Left speed of the ball
    player.x-=5;
  }
  if(spacePressed){
    if(!player.jumping){
      //The hight of the jump	
      player.dy=-player.speed * 2;
      player.jumping = true;

    }
  }
  player.dy+=gravity;

  player.x+=player.dx;
  player.y+=player.dy;

  if(player.y >= 390){
    player.y = 390;
    player.jumping = false;
  }
  //Box collision logic

  window.requestAnimationFrame(draw)
}
window.requestAnimationFrame(draw);

canvas {border:1px solid black;}

<canvas id="canvas" width="400px" height="400px"> </canvas>
&#13;
&#13;
&#13; CODEPEN HERE

2 个答案:

答案 0 :(得分:1)

我认为这是您正在寻找的行为。以下代码完成所有魔术:
(请参阅下面的代码片段了解工作演示)

//CHECK COLLISION
var collisionObjects = [rect.box, rect.wall];
for (var i=0,count=collisionObjects.length; i<count; ++i) {
    var obj = collisionObjects[i];
    var playerLeft=x-player.width, playerRight=x+player.width, playerTop=y-player.height, playerBottom=y+player.height;
    var objectLeft=obj.x, objectRight=obj.x+obj.width, objectTop=obj.y, objectBottom=obj.y+obj.height;
    //check if player is either touching or within the object-bounds
    if (playerRight>=objectLeft && playerLeft<=objectRight && playerBottom>=objectTop && playerTop<=objectBottom) {
        if (player.y+player.height==objectTop || player.y-player.height==objectBottom) {y=player.y;} //player is already colliding with top or bottom side of object
        else if (player.x+player.width==objectLeft || player.x-player.width==objectRight) {x=player.x;} //player is already colliding with left or right side of object
        else if (playerRight>objectLeft && playerLeft<objectRight && playerBottom>objectTop && playerTop<objectBottom) {
            //check on which side the player collides with the object
            var sides = {left:Math.abs(playerRight-objectLeft), right:Math.abs(playerLeft-objectRight), top:Math.abs(playerBottom-objectTop), bottom:Math.abs(playerTop-objectBottom)};
            var side = Math.min(sides.left, sides.right, sides.top, sides.bottom); //returns the side with the smallest distance between player and object
            if (side==sides.top) {y=objectTop-player.height;} else if (side==sides.left) {x=objectLeft-player.width;} //first check top, than left
            else if (side==sides.bottom) {y=objectBottom+player.height;} else if (side==sides.right) {x=objectRight+player.width;} //first check bottom, than right
        }
    }
}

但为了实现这一点,我不得不改变其他一些事情:

  • 我不得不直接更新player.xplayer.y,而是必须在绘制开始时创建变量xy,而只在更新{{1 }}。
    所以整个函数player.x=x, player.y=y应该被复制,我认为是保存。

但是不要盲目地复制它,我也做了一些其他的改动,主要是为了我自己对你的脚本的理解和可读性。做你想要的......你喜欢它,复制它,你不要,留下它:

  • 我将draw()更改为player.speedplayer.speedx。这些属性也在player.speedy中使用,因此请小心。
  • 我添加了变量draw()floor,以限制球离开画布。
  • 我将end值更改为地球上的重力值。
  • 我将gravity更改为var box,这是一个包含所有矩形形状的对象。如果您想要放置一个新的矩形,只需在var rect对象中添加一个新的矩形即可。
    rect我将draw()更改为drawBox();,这是一个绘制for (key in rect) {if (rect.hasOwnProperty(key)) {drawRect(rect[key]);}}对象内所有对象的循环。
  • rect是一个数组,其中包含应该触发与玩家发生碰撞的所有对象 正如您在演示中看到的那样,黄色var collisionObjects = [rect.box, rect.wall];不会触发碰撞,因为它不在阵列中。
    (如果你确实将shelf添加到collisionObjects-array中,大约半秒后球仍然会掉下来,我还没弄清楚原因。我认为它与宽度有关(代码中shelf),但不是这样。出于某种原因,如果对象没有碰到地板,那么球最终会落空。)

代码段:

&#13;
&#13;
height
&#13;
var ctx = document.getElementById("canvas").getContext("2d");
//OBJECTS====================
var player = {x:50,y:100, dx:0,dy:0, width:10,height:10, speedx:5,speedy:10, jumping:false, color:"red"};
var rect = {
	box: {x:150,y:350, width:50,height:50, color:"blue"},
	shelf: {x:220,y:250, width:60,height:5, color:"gold"},
	wall: {x:360,y:300, width:10,height:100, color:"green"}
};
//VARS====================
var rightPressed = false;
var spacePressed = false;
var leftPressed = false;
var gravity = 0.98;
var floor = canvas.height-player.height;
var end = canvas.width-player.width;

//KEY-HANDLERS====================
document.addEventListener("keydown",function(e) {
	if (e.keyCode==39) {rightPressed=true;} //RIGHT
	if (e.keyCode==37) {leftPressed=true;} //LEFT
	if (e.keyCode==32) {spacePressed=true;} //JUMP
});
document.addEventListener("keyup",function(e) {
	if (e.keyCode==39) {rightPressed=false;} //RIGHT
	if (e.keyCode==37) {leftPressed=false;} //LEFT
	if (e.keyCode==32) {spacePressed=false;} //JUMP
});

//DRAW====================
//OBJECTS--------------------
function drawPlayer() {
	ctx.fillStyle = player.color;
	ctx.beginPath();
	ctx.arc(player.x,player.y,10,0,Math.PI*2);
	ctx.fill();
}
function drawRect(obj) {
	ctx.fillStyle = obj.color;
	ctx.fillRect(obj.x,obj.y,obj.width,obj.height);
}
//SCENE--------------------
function draw() {
	ctx.clearRect(0,0,canvas.width,canvas.height);
	drawPlayer(); //draw player
	for (key in rect) {if (rect.hasOwnProperty(key)) {drawRect(rect[key]);}} //draw all objects in 'rect'
	
	//MOVE PLAYER
	var x=player.x, y=player.y;
	if (rightPressed) {x = x+player.speedx;} //right
	if (leftPressed) {x = x-player.speedx;} //left
	if (spacePressed && !player.jumping) { //jump
		player.jumping = true;
		player.dy = -player.speedy * 2; //jump-factor
	}
	
	x = x+player.dx;
	if (x <= player.width) {x=player.width;}
	if (x >= end) {x=end;}
	
	player.dy += gravity;
	y = y+player.dy;
	if (y >= floor) {y=floor; player.jumping=false;}
	
	//CHECK COLLISION
	var collisionObjects = [rect.box, rect.wall];
	for (var i=0,count=collisionObjects.length; i<count; ++i) {
		var obj = collisionObjects[i];
		var playerLeft=x-player.width, playerRight=x+player.width, playerTop=y-player.height, playerBottom=y+player.height;
		var objectLeft=obj.x, objectRight=obj.x+obj.width, objectTop=obj.y, objectBottom=obj.y+obj.height;
		//check if player is either touching or within the object-bounds
		if (playerRight>=objectLeft && playerLeft<=objectRight && playerBottom>=objectTop && playerTop<=objectBottom) {
			if (player.y+player.height==objectTop || player.y-player.height==objectBottom) {y=player.y;} //player is already colliding with top or bottom side of object
			else if (player.x+player.width==objectLeft || player.x-player.width==objectRight) {x=player.x;} //player is already colliding with left or right side of object
			else if (playerRight>objectLeft && playerLeft<objectRight && playerBottom>objectTop && playerTop<objectBottom) {
				//check on which side the player collides with the object
				var sides = {left:Math.abs(playerRight-objectLeft), right:Math.abs(playerLeft-objectRight), top:Math.abs(playerBottom-objectTop), bottom:Math.abs(playerTop-objectBottom)};
				var side = Math.min(sides.left, sides.right, sides.top, sides.bottom); //returns the side with the smallest distance between player and object
				if (side==sides.top) {y=objectTop-player.height;} else if (side==sides.left) {x=objectLeft-player.width;} //first check top, than left
				else if (side==sides.bottom) {y=objectBottom+player.height;} else if (side==sides.right) {x=objectRight+player.width;} //first check bottom, than right
				player.jumping=false;
			}
		}
	}
	//SET PLAYER POSITION
	player.x=x, player.y=y;
	
	//NEXT FRAME--------------------
	requestAnimationFrame(draw)
} draw();
&#13;
canvas {border:1px solid black;}
&#13;
&#13;
&#13; codepen: http://codepen.io/anon/pen/bByQJg?editors=0010
jsfiddle: https://jsfiddle.net/zvkgnegt/8/

答案 1 :(得分:0)

所以我知道这不会帮助你修复你的代码,但如果你看一下首页上的演示,我强烈建议你查看http://wickeditor.com/(点击查看第4个)你会看到它提供了很好的碰撞检测,你可以从网站下载项目,它应该使它非常容易复制,以满足你的需求。