Javascript 使用基于速度的二维运动修复简单碰撞检测
在这种情况下,你可以用箭头移动“玩家”方格,放置一盏有空间的灯,并被推到相反的方向,以防止从任何方向越过蓝线。“玩家”使用x和y速度变量创建运动,如果检测到碰撞,则将它们乘以-1(+某个值)Javascript 使用基于速度的二维运动修复简单碰撞检测,javascript,three.js,collision-detection,Javascript,Three.js,Collision Detection,在这种情况下,你可以用箭头移动“玩家”方格,放置一盏有空间的灯,并被推到相反的方向,以防止从任何方向越过蓝线。“玩家”使用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);
};
设xVelocity=0;
设yVelocity=0;
var blockedMapGrid=[[0,30]、[0,50]、[0100]、[0150]、[0200]、[0250],
[50,0],[100,0],[150,0],[200,0],[250,0],[300,0]];
var animate=函数(){
if(键状态[37]){
xVelocity-=1;
}
if(键状态[38]){
yVelocity+=1;
}
if(键状态[39]){
x速度+=1;
}
if(键状态[40]){
yVelocity-=1;
}
对于(变量i=0;i
探测器的这部分错误:
Math.abs(player.position.x - blockedMapGrid[i][0]) +
Math.abs(player.position.y - blockedMapGrid[i][1]) < 36
您可以改变检测到碰撞时的操作,但这里的关键是使用4个条件查找两个框是否重叠
更新
问题中代码引起的另一个问题是检测到碰撞后“反弹”或“卡住”
根据经验,在碰撞后,如果不确保角色回到“清除”位置,即玩家的边界框不与任何障碍物重叠,则不得使用velocity=-velocity
。否则您将陷入无限循环冲突?->vel=-vel,pos+=vel*t->collision->…
速度从负向正反弹回来,而不允许玩家离开墙
修复它的最简单方法是首先在临时变量中计算播放器的新位置,检查新位置是否没有碰撞,然后将其永久化并调用render()
,否则只需忽略它并在不移动播放器的情况下进行渲染
另一种方法是记住最后一个已知的“好”位置,只有当角色返回到前一个位置时,才返回对角色的控制,可能是在动画或一系列无法控制的动作之后
还有更复杂的方法,主要涉及某种物理模拟,让角色在多个障碍物上弹跳,假设控制输入不会压倒惯性——想象一辆汽车在湿滑的道路上行驶或一艘船撞上多棵树。但无论哪种方式,在检测到碰撞后和调用“render()”之前,都必须将角色放置到物理上可能的位置,否则它将被著名的“卡在纹理中” 谢谢你的评论-我考虑过使用带半径的点,因为它在数组中占用的空间更少。但我认为定制形状的矩形可以弥补这一差异
尽管我遇到了“矩形内滑动”的错误,但您的方法仍然有效。当你跑到墙边,同时按下相反方向的箭头时,玩家进入盒子,开始在阻塞区域以几乎0的速度移动。这是一件平常的事吗?我可以将反弹速度设置为略高于传入速度,但不确定这是最好的way@SanchezPanza我将更新一个答案,以帮助反弹。
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;
}
}