我正在从头开始研究实时移动系统。我想绝对避免安装bilion节点模块,因为我更喜欢自己编写代码(也是为了深入了解正在发生的事情)。
到目前为止,我有一个有效的碰撞检测和碰撞距离模块。
现在我有一个在包含各种矩形的区域中移动的圆圈。所有内容都有bb //bounding box
属性,圆圈包含中间x
和y
坐标以及radius
,而矩形包含左上角和右下角的坐标 - 正确点。
我在这里只使用2个函数:collision
(如果2 bb
碰撞则返回true)和circ_to_rect_dist
(返回矩形最近边之间的距离)圆的最近点,如果圆是碰撞,则为0。它还返回距离的水平和垂直分量。)({d: distance, h: delta x, v: delta y}
)
现在,代码成功停止向墙壁移动(如果您的速度大于距离,则移动您联系)。但是一旦有接触,除了会破坏接触的方向之外,我不能朝其他方向移动。
例如,如果我的圆圈触及矩形的左侧,我无法向上或向下移动。那是因为最近点之间的垂直距离仍为0。
有关如何修改系统以使其能够“滑动”在墙上的任何想法吗?
另外,还有一个我无法解释的小错误: 向右,向下和向左移动会导致块的移动按预期移动,向上移动会让你怪异地弹跳,这很奇怪,考虑到它在其他3个方向上工作得很好......
无论如何,这是相关的代码: 运动功能:
step()
{
//MOVEMENT
//MOVEMENT V 2.3
if(this.hspeed != 0 || this.vspeed != 0)
{
var newx = this.bb.x + this.hspeed;
var newy = this.bb.y + this.vspeed;
for(var w=0; w < Wall.list.length; w++)
{
var wall = Wall.list[w];
if(bb.collision(bb.circ(newx, newy, this.bb.radius), wall.bb))
{
var move_dist = bb.circ_to_rect_dist(this.bb, wall.bb)
var hspeed = move_dist.h * (this.hspeed<0?-1:1);
var vspeed = move_dist.v * (this.vspeed<0?-1:1);
newx = this.bb.x + hspeed;
newy = this.bb.y + vspeed;
}
}
this.bb.x = newx;
this.bb.y = newy;
}
//OTHER
for(var i in this.attacks)
{
if(this.attacks[i].reload > 0)
{
this.attacks[i].reload--;
}
else
{
if(this.attacks[i].pressed == 1)
{
this.attacks[i].reload = this.attacks_data[i].reload;
this.shoot(i);
}
}
}
}
这是我正在使用的一组碰撞相关函数:
const bb = {}
module.exports = bb;
bb.point = function(x, y)
{
return(
{
type: "point",
x: x,
y: y
});
}
bb.line = function(x1, y1, x2, y2)
{
return(
{
type: "line",
point: [bb.point(x1, y1), bb.point(x2, y2)]
});
}
bb.rect = function(x1, y1, x2, y2)
{
return(
{
type: "rect",
point: [{x: x1, y: y1}, {x: x2, y: y2}]
});
}
bb.circ = function(x, y, radius)
{
return(
{
type: "circ",
x: x,
y: y,
radius: radius
});
}
bb.circ_to_line_dist = function(a, b)
{
var ptl = bb.point_to_line_dist(a, b);
ptl.d -= Math.min(a.radius, ptl.d);
ptl.h -= Math.min(a.radius, ptl.h);
ptl.v -= Math.min(a.radius, ptl.v);
return(ptl);
}
bb.circ_to_rect_dist = function(a, b)
{
var lines = bb.rect_extract_lines(b);
var min_dist = bb.circ_to_line_dist(a, lines[0]);
for(var i=1; i<lines.length; i++)
{
var tmp_dist = bb.circ_to_line_dist(a, lines[i]);
if(tmp_dist.d < min_dist.d)
{min_dist = tmp_dist;}
}
return(min_dist);
}
bb.point_to_point_dist = function(a, b)
{
var dx = Math.abs(a.x - b.x);
var dy = Math.abs(a.y - b.y);
return({d: Math.sqrt(dx*dx + dy*dy), h: dx, v: dy});
}
bb.point_to_line_dist = function(a, b)
{
/*var num = Math.abs( (b.point[1].y-b.point[0].y)*a.x - (b.point[1].x-b.point[0].x)*a.y + (b.point[1].x*b.point[0].y) - (b.point[1].y*b.point[0].x) );
var den = bb.point_to_point_dist(b.point[0], b.point[1]);
return(num/den);*/
var A = a.x - b.point[0].x;
var B = a.y - b.point[0].y;
var C = b.point[1].x - b.point[0].x;
var D = b.point[1].y - b.point[0].y;
var dot = A * C + B * D;
var len_sq = C * C + D * D;
var param = -1;
if (len_sq != 0) //in case of 0 length line
{
param = dot / len_sq;
}
var xx, yy;
if (param < 0)
{
xx = b.point[0].x;
yy = b.point[0].y;
}
else if (param > 1)
{
xx = b.point[1].x;
yy = b.point[1].y;
}
else
{
xx = b.point[0].x + param * C;
yy = b.point[0].y + param * D;
}
var dx = Math.abs(a.x - xx);
var dy = Math.abs(a.y - yy);
return {d: Math.sqrt(dx * dx + dy * dy), h: dx, v: dy};
}
//circle and rectangle collision
bb.circ_to_rect = function(a, b)
{
if(bb.point_to_rect(a, b))
{return(true);}
var lines = bb.rect_extract_lines(b);
for(var i in lines)
{
if(bb.line_to_circ(lines[i], a))
{return(true);}
}
return(bb.point_to_rect(a, b));
}