HTML5 Canvas:鼠标和多边形碰撞检测

发布于 2024-09-16 23:15:14 字数 419 浏览 3 评论 0原文

所以我正在使用 HTML5 和 Javascript 制作一款塔防游戏。我唯一的问题是检测鼠标何时接触攻击者的路径,这是阻止玩家在路径上建造塔楼所必需的。攻击者的路径是在 MAP.js 文件中通过二维数组(包含 x 和 y 对的数组)确定的(请参阅底部的链接),所以我必须处理的是一系列点连接时建立路径。我只是想禁止玩家在路径的 50 像素范围内放置塔。老实说,我对碰撞检测很糟糕,所以我们将不胜感激。

这是所有代码的链接: http://shapeshifting.comuv.com/Tower_Defense/td/

正如您可能想象的那样,仅.js 文件适用,但大多数相关代码位于objects.js 文件内。 (凌乱请见谅)

So I'm making a tower defense game with HTML5 and Javascript. My sole problem is detecting when the mouse comes in contact with the attacker's pathway, which is necessary in order to stop the player from building towers on the path. The path of the attackers is determined in the MAP.js file (see the link at the bottom), by a two dimensional array (an array containing x and y pairs), so what I have to work with is a series of points that make up a path when connected. I merely want to prohibit the player from placing towers within, say, 50 pixels of the path. To be honest I am just awful with collision detection, so some help would be greatly appreciated.

Here is the link to all the code:
http://shapeshifting.comuv.com/Tower_Defense/td/

As you might imagine, only the .js files are applicable, but most of the relevant code is inside the objects.js file. (PLease excuse the messiness)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

当爱已成负担 2024-09-23 23:15:15

它可能更简单,更快地定义用户可以在地图文件中明确放置塔的区域...将每个区域定义为凸多边形(可能包括地图边缘,分割凹多边形,更喜欢水平或垂直线,然后测试鼠标位于其中一个多边形中,请参阅此答案以获取实现

如何测试一个点是否在二维整数坐标中的凸多边形内部?

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

It probably simpler, and faster to define the areas the user can place towers in eplicitly in the map file... Define each area as a convex polygon (posibly including the map edges, split concave polygons, prefer horizontal or vertical lines, then test of the mouse is in one of the polygons, see this answer for an implementatio

How to test if a point is inside of a convex polygon in 2D integer coordinates?

Decomposing to triangles makes the test even simpler

鹤舞 2024-09-23 23:15:14

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

您不希望您的游戏根据用户移动鼠标进行大量数学计算 - 它需要简短而快速 - 因此快速进行预先计算至关重要。

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

如果你的地图不是网格,那么你仍然想要预先计算一些东西,但策略会稍微复杂一些。第一种可能性是像 Hitesh 一样执行数学运算以生成分辨率稍高的碰撞图,然后其余部分与网格策略完全相同 - 因此,例如,如果每个 4x4 像素块都是一个碰撞条目,那么塔是否可以Placed 是一个测试,测试其坐标是否位于足够的 1 之上 - 您可能要求 100% 的测试为 1,或者您可能让它们达到一点点,假设 75% 的测试为 1。

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

前 2 种网格方法的好处之一是,您可以轻松进行 QA - 将碰撞贴图存储为图像并进行目视检查,以确保它看起来适合其所基于的贴图。如果您不想编写代码来生成它们,也可以手动绘制它。

圆形方法为您提供了合法的曲线,并且可以产生更精细的碰撞边缘细节,但显然更难测试并确保没有贴图具有不良碰撞贴图。编写地图生成工具也需要更多工作。

祝你好运!

Collision detection is one of those old, hidden problems of coding a game. Typically people take darkpenguin's approach of precalculating in some fashion where on your static map is and is not placeable. The next step is to come up with a way to specify the most efficient collide map.

You don't want your game to do a ton of math in response to the user moving their mouse - it needs to be short and quick - so precalculating down to something quick is critical.

If your map is a grid, then you have your answer right there - the collision map is a precalculated 2D array - basically a very small black and white image with a pixel for each place on the grid. White pixels (1) are placeable and black pixels (0) are not. You just use this 2D array of true/false as a lookup. If you want to save memory you can bundle each strip of 32 spaces on the grid into a single bit flag.

If your map is not a grid, then you still want to precalculate things, but the strategy is a bit more complex. The first possibility is to perform math like Hitesh to produce a slightly higher-resolution collide map, and then the rest is exactly as the grid strategy - so for example if every 4x4 block of pixels was one collide entry, then whether a tower can be placed is a test as to whether its coordinates test out to be on top of enough 1's - you might require 100% of tests be 1's, or you might let them reach a little and let say 75% of tests be 1's.

If this still is not enough detail, you can do these more complex polygon tests, but you want them to be as simple as possible. When not using a precalculated grid, the simplest 2D collision test is 2 circles - you just calculate the distance between their centers and check if it's greater or less than the sum of their radii. If you precalculate your monster path into a trail of circles, the next step is to partition those circles into... guess what... a grid. This prevents every check from having to test every single circle on the map. This allows you to have a high number of these circles in the collision map, as the collision test is first a lookup into what grid entries the tower is currently over, followed by checking if it's colliding with just the circles it's closest to, rather than the entire map. It's important to note that this precalculated grid of circle lists will often have the same circle in multiple neighboring grid entries, because every grid entry that contains any portion of a given circle must have that circle in its collide checklist.

One of the nice things about the first 2 grid approaches is that it's very easy to QA yourself - literally store the collision map as an image and visually inspect it to ensure it looks right for the map it's based on. You can also draw it by hand if you don't want to write the code to generate them.

The circle approach gives you legitimate curves and can lead to finer collide edge detail, but it's obviously harder to test and ensure no maps have bad collide maps. It's also more work to write the map generation tool.

Good luck!

第七度阳光i 2024-09-23 23:15:14

我会逐步解决这个问题。让我们看看你从什么开始。您有一条由点定义的路径——点对定义一条线段。所以你真正拥有的是一条由线段组成的路径。当用户移动鼠标时,您将获得当前位置的 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)
}

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

I would approach this in steps. Let's look at what you start with. You have a path defined by points -- pairs of points define a line segment. So what you really have is a path made of line segments. When the user moves the mouse, you will get x,y coordinates of the current position. What you want to do is find the distance of the mouse point to all of the line segments. If it is less than 50 pixels from any line segment, then you don't want to allow them to build there.

To find the distance between a point and a line segment, the pseudo code looks like this. Assume that points A and B represent both ends of a line segment and point C is the mouse point.

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)
}

This would answer your collision detection question but I think you'd then want to look at performance. How many line segments will be in your path and do you want to calculate the distance to each line segment every time the user moves their mouse? You can put the line segments into a quadtree so that you'd only have to test mouse point collisions against a smaller number of line segments.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文