在这个codePen demo中你可以用箭头移动“玩家”方形,放置一个有空间的灯光,并且应该被推向相反方向从任何方向停止越过蓝线。如果检测到碰撞,“player”使用x和y速度变量来创建移动并将它们乘以-1(+某个值)。 问题在于,在被推离墙壁之后,“玩家”被卡在一个位置,在该位置只能从墙上向后移动,同时出现卡在与其垂直的轴上。 (例如 - 如果墙壁位于播放器顶部,您只能移动到底部,而不是在撞到墙壁后向左或向右移动) 理论上,我想要一个平滑的滑动碰撞检测,其中卡在墙上的玩家会慢慢滑下左侧或右侧,这取决于是否按下左箭头或右箭头。 (在我身边,我能够实现这一目标,但总是一个方向会“流动”,让玩家向某个方向滑动) 我想过使用光线或其他方法来检测命中,但它们似乎需要比简单方法更多的计算时间。非常感谢任何输入和建立可扩展碰撞检测的任何建议,以下是我从演示中移动和碰撞检测的基本代码:
let xVelocity = 0;
let yVelocity = 0;
var blockedMapGrid = [[0,30],[0,50],[0,100],[0,150],[0,200],[0,250],
[50,0],[100,0],[150,0],[200,0],[250,0],[300,0]];
var animate = function() {
if (keyState[37]) {
xVelocity -= 1;
}
if (keyState[38]) {
yVelocity += 1;
}
if (keyState[39]) {
xVelocity += 1;
}
if (keyState[40]) {
yVelocity -= 1;
}
for (var i = 0; i < blockedMapGrid.length; i++) {
if (Math.abs(player.position.x - blockedMapGrid[i][0]) +
Math.abs(player.position.y - blockedMapGrid[i][1]) < 36) {
xVelocity = -xVelocity * 1.2;
yVelocity = -yVelocity * 1.2;
console.log("Blocked by " + blockedMapGrid[i][0])
};
}
player.position.x = player.position.x + xVelocity;
player.position.y = player.position.y + yVelocity;
yVelocity *= 0.80;
xVelocity *= 0.80;
camera.position.x = player.position.x;
camera.position.y = player.position.y;
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
这部分探测器错了:
Math.abs(player.position.x - blockedMapGrid[i][0]) +
Math.abs(player.position.y - blockedMapGrid[i][1]) < 36
基本上,在这里,您通过使用添加的绝对值而不是平方和的根来近似从玩家到网格上的点的距离。事实是,你不需要这么复杂的网格(重复的线条)和距离。
看起来你正在进行Axis-Aligned Bounding Box(AABB)检测。在互联网上有plenty resources如何优化它。
但一般的方法是这样的。您的网格数组应包含(x,y,w,h)
度量的框。可能是薄,长,方,任何东西。让我们假设你的玩家有一个边界框(player.x, player.y, player.w, player.h)
,然后
for (var i = 0; i < grid.length; i++) {
if (player.x < grid[i].x + grid[i].w &&
player.x + player.w > grid[i].x &&
player.y < grid[i].y + grid[i].h &&
player.y + player.h > grid[i].y) {
//collision detected! move player to previous known position
break;
}
}
您可以改变,检测到碰撞时的操作,但是找到两个框是否重叠使用4个条件是关键。
更新
问题中的代码引起的另一个问题是在检测到碰撞后“弹跳”或“卡住”。
根据经验,你不应该在碰撞后使用velocity = -velocity
,也不要确保角色回到“清除”,即玩家的边界框不与任何障碍物重叠。否则你将陷入无限循环collision? -> vel = -vel, pos += vel*t -> collision -> ...
,速度从负到正反弹而不会让玩家离开墙。
解决这个问题的最简单方法是首先计算玩家在临时变量中的新位置,检查新位置是否没有碰撞,然后将其永久化并调用render()
,否则只需忽略它并渲染而不移动玩家。
另一种方法是记住最后一个已知的“好”位置,并且只有当它返回到之前的位置时,可能在动画或一堆无法控制的动作之后才给予对角色的控制。
有更复杂的方法,主要是涉及某种物理仿真,让角色反弹多个障碍,假设控制输入不会过度惯性 - 想想在湿滑的道路上的汽车或撞到多棵树的船。但无论哪种方式,在你检测到碰撞之后和调用“render()”之前,你必须将角色放置在物理上可能的位置,否则它将被称为“陷入纹理”。