Javascript HTML5画布:鼠标和多边形碰撞检测

Javascript HTML5画布:鼠标和多边形碰撞检测,javascript,html,canvas,collision-detection,Javascript,Html,Canvas,Collision Detection,所以我用HTML5和Javascript制作了一个塔防游戏。我唯一的问题是检测鼠标何时接触到攻击者的路径,这是阻止玩家在路径上建造塔楼所必需的。攻击者的路径在MAP.js文件(见底部链接)中由二维数组(一个包含x和y对的数组)确定,因此我需要处理的是一系列点,它们在连接时构成一条路径。我只想禁止玩家在路径的50像素范围内放置塔。老实说,我只是在碰撞检测方面很糟糕,所以如果能提供一些帮助,我将不胜感激 以下是所有代码的链接: 正如您所想象的,只有.js文件是适用的,但是大部分相关代码都在obje

所以我用HTML5和Javascript制作了一个塔防游戏。我唯一的问题是检测鼠标何时接触到攻击者的路径,这是阻止玩家在路径上建造塔楼所必需的。攻击者的路径在MAP.js文件(见底部链接)中由二维数组(一个包含x和y对的数组)确定,因此我需要处理的是一系列点,它们在连接时构成一条路径。我只想禁止玩家在路径的50像素范围内放置塔。老实说,我只是在碰撞检测方面很糟糕,所以如果能提供一些帮助,我将不胜感激

以下是所有代码的链接:


正如您所想象的,只有.js文件是适用的,但是大部分相关代码都在objects.js文件中。(请原谅我的混乱)

我会分步骤来处理这个问题。让我们看看你从什么开始。您有一个由点定义的路径——点对定义一条线段。所以你真正拥有的是一条由线段组成的路径。当用户移动鼠标时,您将获得当前位置的x、y坐标。您要做的是找到鼠标点到所有线段的距离。如果距离任何线段的距离小于50像素,则不希望允许它们在那里构建

要查找点和线段之间的距离,伪代码如下所示。假设点A和B表示线段的两端,点C是鼠标点

float distancePoint2LineSegment(Point a, Point b, Point c) {
  Vector ab = b - a
  Vector ac = c - a
  Vector bc = c - b

  float e = dotProduct(ac, ab)
  if (e <= 0.0)
    return sqrt(dotProduct(ac, ac))

  float f = dotProduct(ab, ab)
  if (e >= f)
    return sqrt(dotProduct(bc, bc))

  return sqrt(dotProduct(ac, ac) - e * e / f)
}
浮点距离Point2LineSegment(点a、点b、点c){
向量ab=b-a
向量ac=c-a
向量bc=c-b
浮点数e=点积(ac,ab)
如果(e=f)
返回sqrt(点产品(bc,bc))
退货sqrt(点产品(ac,ac)-e*e/f)
}

这将回答你的碰撞检测问题,但我认为你会想看看性能。您的路径中将有多少条线段?您是否希望在用户每次移动鼠标时计算到每条线段的距离?您可以将线段放在四叉树中,这样您只需测试鼠标点与较少线段的碰撞。

在地图文件中以电子格式定义用户可以放置塔楼的区域可能更简单、更快。。。将每个区域定义为一个凸多边形(可能包括地图边、分割凹多边形、首选水平线或垂直线),然后在其中一个多边形中测试鼠标,有关实现,请参阅此答案


分解为三角形使测试更加简单

碰撞检测是游戏编码中古老而隐蔽的问题之一。通常,人们会采用darkpenguin的方法,以某种方式预先计算静态地图上可放置和不可放置的位置。下一步是找到一种指定最有效碰撞地图的方法

你不想让你的游戏在用户移动鼠标时做大量的数学运算——它需要短而快——因此预先计算到一些快的东西是至关重要的

如果你的地图是一个网格,那么你的答案就在那里-碰撞地图是一个预先计算的2D数组-基本上是一个非常小的黑白图像,网格上的每个位置都有一个像素。白色像素(1)是可放置的,黑色像素(0)不是。您只需将此二维真/假数组用作查找。如果要节省内存,可以将网格上的每个32个空格绑定到一个位标志中

如果你的地图不是一个网格,那么你仍然需要预先计算,但是策略有点复杂。第一种可能是像Hitesh一样进行数学运算,生成一个分辨率稍高的碰撞地图,然后剩下的与网格策略完全一样-例如,如果每个4x4像素块都是一个碰撞条目,那么呃一座塔可以被放置是一个测试,它的坐标测试是否在足够的1之上-你可能要求100%的测试是1,或者你可能让他们达到一点,比如说75%的测试是1

如果这仍然不够详细,您可以执行这些更复杂的多边形测试,但您希望它们尽可能简单。如果不使用预先计算的网格,最简单的2D碰撞测试是两个圆-您只需计算它们中心之间的距离,并检查其是否大于或小于半径之和。如果您预先计算将你的怪物路径划分成一条圆圈轨迹,下一步是将这些圆圈划分成…猜猜看…一个网格。这可以防止每次检查都必须测试地图上的每个圆圈。这允许你在碰撞地图中有大量的圆圈,因为碰撞测试首先是查找塔的网格条目当前结束,然后检查它是否仅与最近的圆碰撞,而不是与整个地图碰撞。需要注意的是,此预先计算的圆列表网格通常在多个相邻的网格条目中具有相同的圆,因为包含给定圆任何部分的每个网格条目都必须具有该圆在它的碰撞清单中

前两种网格方法的优点之一是,很容易对自己进行质量保证——将碰撞贴图直接存储为图像,并对其进行目视检查,以确保其外观与所基于的贴图相符。如果不想编写代码生成碰撞贴图,也可以手工绘制

“圆”方法可以提供合法的曲线,并可以产生更精细的碰撞边细节,但显然更难测试并确保没有贴图具有糟糕的碰撞贴图。编写贴图生成工具也需要更多的工作


祝你好运!

使用正方形可能是最简单的,这会让你回到网格的概念。