使用圆形数学进行实体碰撞
Using circle math for solid collision
function distance(x1, y1, x2, y2) {
var x = x1 - x2;
var y = y1 - y2;
return(Math.sqrt((x*x) + (y*y)))
};
function collisionCirc(circ1, circ2) {
var d = distance(circ1.x, circ1.y, circ2.x, circ2.y);
var r = circ1.radius + circ2.radius;
return(r > d);
};
function collisionCircPoint(circ1, circ2) {
var cx = ((circ1.x * circ2.radius) + (circ2.x * circ1.radius)) / (circ1.radius + circ2.radius);
var cy = ((circ1.y * circ2.radius) + (circ2.y * circ1.radius)) / (circ1.radius + circ2.radius);
var p = [cx, cy];
return p;
};
function angleDegrees(x1, y1, x2, y2) {
return (Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI) + 180;
};
function updateCollisions() {
var a;
var p;
Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);
if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
Player.sprite.x = p[0];
Player.sprite.y = p[1];
};
};
我在地图上有 2 个精灵,每个精灵都定义了一个圆形 hitArea。我正在尝试进行玩家无法通过的平滑圆形碰撞。我以为我可以将 Player.sprite 的坐标设置为碰撞点,但它只是将他扭曲到 MapObjects.chest 的坐标,即使碰撞点是正确的并且距离碰撞点 20 像素MapObject.chest的中心。我做错了什么或者需要什么更多的信息来创建碰撞,就像 JavaScript 物理库,我可以在其中围绕一个圆形对象旋转?
碰撞点在玩家和障碍物之间。如果将玩家移向碰撞点,实际上是在将玩家移近。例如,如果玩家和障碍物之间正好有 40 px (r1+r2),那么碰撞点就在他们之间,距离障碍物只有 20 px!
当您有多个对象时,很难在碰撞已经发生时正确处理。如果附近只有一个障碍物,您只需将玩家直接移离障碍物即可。但是,这样玩家实际上可能会陷入另一个障碍物中。
另一个解决办法是回到起点,尝试小幅度的运动,直到没有碰撞。这样你最终会做对,但这也可能很慢。
数学上正确的解决方案是计算碰撞发生前移动的最大距离。这是通过求解以下向量方程来完成的:
# p = player position before moving
# o = obstacle position
# u = player direction (unit vector)
# d = distance to move
distance(o, p + d * u) = o.radius + p.radius
那是数学,你可以自己解决,也可以使用 Wolfram Alpha 之类的工具解决。
求解该方程式将为您提供零个、一个或两个可能的距离值。您可以忽略负值,因为它们意味着玩家已经越过了障碍。如果你只得到一个值,这意味着玩家只会擦过障碍物,你也可以忽略它。两个值表示碰撞发生在这些距离之间;较小的值是碰撞开始的地方,较大的值是玩家已经穿过障碍物的地方。另外,如果一个值为正,另一个为负,则意味着玩家已经在障碍物内,这种情况永远不会发生。
你应该 运行 检查附近的所有障碍物,然后根据最小的 non-negative 结果(即零或正)或更小的结果移动玩家,如果玩家不能'没那么快。
最后,为了围绕一个圆形物体转圈,你可以在碰撞后将玩家沿垂直方向移动一点(向左或向右,取决于玩家将通过障碍物的哪一侧),如果这不会引起任何新的碰撞。
还有许多其他可能的实现方式。
Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);
if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
if (Player.sprite.x - MapObjects.chest.x > 0) {
Player.sprite.x += 1;
} else if (Player.sprite.x + MapObjects.chest.x > 0) {
Player.sprite.x -= 1;
};
if (Player.sprite.y - MapObjects.chest.y > 0) {
Player.sprite.y += 1;
} else if (Player.sprite.y + MapObjects.chest.y > 0) {
Player.sprite.y -= 1;
};
};
};
我补充说,它实际上工作得很好,只是当 运行 以特定角度进入 MapObjects.chest 的命中区域时玩家速度稍微过快。稍后处理。
function distance(x1, y1, x2, y2) {
var x = x1 - x2;
var y = y1 - y2;
return(Math.sqrt((x*x) + (y*y)))
};
function collisionCirc(circ1, circ2) {
var d = distance(circ1.x, circ1.y, circ2.x, circ2.y);
var r = circ1.radius + circ2.radius;
return(r > d);
};
function collisionCircPoint(circ1, circ2) {
var cx = ((circ1.x * circ2.radius) + (circ2.x * circ1.radius)) / (circ1.radius + circ2.radius);
var cy = ((circ1.y * circ2.radius) + (circ2.y * circ1.radius)) / (circ1.radius + circ2.radius);
var p = [cx, cy];
return p;
};
function angleDegrees(x1, y1, x2, y2) {
return (Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI) + 180;
};
function updateCollisions() {
var a;
var p;
Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);
if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
Player.sprite.x = p[0];
Player.sprite.y = p[1];
};
};
我在地图上有 2 个精灵,每个精灵都定义了一个圆形 hitArea。我正在尝试进行玩家无法通过的平滑圆形碰撞。我以为我可以将 Player.sprite 的坐标设置为碰撞点,但它只是将他扭曲到 MapObjects.chest 的坐标,即使碰撞点是正确的并且距离碰撞点 20 像素MapObject.chest的中心。我做错了什么或者需要什么更多的信息来创建碰撞,就像 JavaScript 物理库,我可以在其中围绕一个圆形对象旋转?
碰撞点在玩家和障碍物之间。如果将玩家移向碰撞点,实际上是在将玩家移近。例如,如果玩家和障碍物之间正好有 40 px (r1+r2),那么碰撞点就在他们之间,距离障碍物只有 20 px!
当您有多个对象时,很难在碰撞已经发生时正确处理。如果附近只有一个障碍物,您只需将玩家直接移离障碍物即可。但是,这样玩家实际上可能会陷入另一个障碍物中。
另一个解决办法是回到起点,尝试小幅度的运动,直到没有碰撞。这样你最终会做对,但这也可能很慢。
数学上正确的解决方案是计算碰撞发生前移动的最大距离。这是通过求解以下向量方程来完成的:
# p = player position before moving
# o = obstacle position
# u = player direction (unit vector)
# d = distance to move
distance(o, p + d * u) = o.radius + p.radius
那是数学,你可以自己解决,也可以使用 Wolfram Alpha 之类的工具解决。
求解该方程式将为您提供零个、一个或两个可能的距离值。您可以忽略负值,因为它们意味着玩家已经越过了障碍。如果你只得到一个值,这意味着玩家只会擦过障碍物,你也可以忽略它。两个值表示碰撞发生在这些距离之间;较小的值是碰撞开始的地方,较大的值是玩家已经穿过障碍物的地方。另外,如果一个值为正,另一个为负,则意味着玩家已经在障碍物内,这种情况永远不会发生。
你应该 运行 检查附近的所有障碍物,然后根据最小的 non-negative 结果(即零或正)或更小的结果移动玩家,如果玩家不能'没那么快。
最后,为了围绕一个圆形物体转圈,你可以在碰撞后将玩家沿垂直方向移动一点(向左或向右,取决于玩家将通过障碍物的哪一侧),如果这不会引起任何新的碰撞。
还有许多其他可能的实现方式。
Player.hitArea = new PIXI.Circle(Player.sprite.x, Player.sprite.y, 20);
MapObjects.chest.hitArea = new PIXI.Circle(MapObjects.chest.x, MapObjects.chest.y, 20);
if (collisionCirc(Player.hitArea, MapObjects.chest.hitArea)) {
p = collisionCircPoint(Player.hitArea, MapObjects.chest.hitArea);
a = angleDegrees(Player.sprite.x, Player.sprite.y, MapObjects.chest.x, MapObjects.chest.y);
if (Player.sprite.x - MapObjects.chest.x > 0) {
Player.sprite.x += 1;
} else if (Player.sprite.x + MapObjects.chest.x > 0) {
Player.sprite.x -= 1;
};
if (Player.sprite.y - MapObjects.chest.y > 0) {
Player.sprite.y += 1;
} else if (Player.sprite.y + MapObjects.chest.y > 0) {
Player.sprite.y -= 1;
};
};
};
我补充说,它实际上工作得很好,只是当 运行 以特定角度进入 MapObjects.chest 的命中区域时玩家速度稍微过快。稍后处理。