在canvas上绘制的图像中添加碰撞检测

3
我正在使用HTML5画布和JavaScript创建一个简单的基于Web的游戏。我目前在画布上显示一些图像,每个图像代表快餐店里的物品。我还有四个“描述框”,每个标签分别为资产、负债、收入或支出。
这些图像中的每一个都属于这些描述框之一,用户需要将每个图像拖放到正确的描述框中。
我计划通过使用JS变量名称和每个项目图像的HTML alt标记来检查用户是否已将图像拖到正确的框中。例如,img “chair”具有alt标记“asset”,并且资产的描述框具有变量名称“assetsDescriptionBox”,因此我将使用if语句检测用户正在拖动的图像是否被拖到了画布的与资产描述框显示的位置相同的区域,并且如果该图像具有alt标记“asset”,则它将从画布中消失(并添加到数组中以供稍后在游戏中使用)。
但是,如果用户正在拖动的图像没有alt标记“asset”,而是拥有其他标记,例如“liability”,则它将在画布上重新绘制回原来的位置。
我不确定如何实现这一点。我已经研究了碰撞检测,似乎可以使用JS方法getBoundingClientRect来获取图像的“外部限制”,然后检查两个图像的外部限制是否重叠,如果重叠,则执行某些操作。但是,我不确定如何使用此方法,并且在快速搜索Google时找不到任何特别有用的信息。
请问是否有人知道这是否是实现此目标的最佳方法?如果是,请提供如何使用getBoundingClientRect方法的示例?或者如果不是,您会如何做?
编辑17/12/2012 @ 16:45:
顺便说一下,我正在使用KineticJS库(我已经保存了本地副本以进行一两个更改)添加拖放功能,因此我认为需要更改/添加库中的某些内容以添加碰撞检测。
大家有什么想法吗?
编辑01/01/2013 @ 12:35:
你好,谢谢你的回答 - 确实看起来像是我想要做的事情。我已经在画布上显示了所有图像,其中四个是“静态”的,不能在画布上拖动 - 这些是我想要用作我的“放置区域”,并且可以拖放其余的图像。我不太确定如何将您的代码提供的功能添加到我已经拥有的内容中?如果您访问以下网址:users.aber.ac.uk/eef8/project/development/featureset2dev,您将能够看到我已经完成的工作。
要在我的描述框中添加“dropzone”功能,我需要使用以下行将其添加到画布中吗?
var i = new Image(200, 200, 50, 50, 'cat.jpg', 300, 300, 60, 60); 

您在示例中所做的是什么?

1
getBoundingClientRect适用于DOM元素。在您的画布上,图像只是像素,并且没有与其关联的DOM元素,因此此函数将无法使用。您需要跟踪图像的边界框,以便可以检测单击哪个图像,并通过跟踪目标的边界框,您还可以找出它被放置在哪个位置(kineticjs库难道没有类似的功能吗?)。基本上,跟踪所有交互对象的边界框,碰撞检测就是找出哪些边界框重叠。 - Damp
1个回答

3

我觉得最好的方法是跟踪每个对象的X/Y位置、宽度和高度;使用这样一个简单的矩形碰撞函数,它会检查两个对象的边界框是否重叠。

function collides(a, b)
{
    if (a.x < b.x + b.width &&
        a.x + a.width > b.x &&
        a.y < b.y + b.height &&
        a.y + a.height > b.y) return true;
}

如果我要处理这个问题,我可能会设置一个对象,并将一个拖放区域对象附加到它上面,这样图片就只能触发一个拖放区域,而不是使用纯JS检查alt标签。
function Image(x, y, w, h, i, dx, dy, dw, dh)
{
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;
    this.image = i;
    this.dropzone = new DropZone(dx, dy, dw, dh);
}

function DropZone(x, y, w, h)
{
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;
}

var i = new Image(200, 200, 50, 50, 'cat.jpg', 300, 300, 60, 60);

然后您需要一个循环,当您移动图像时更新拖动图像的坐标。请注意,您不能在画布中绘制的精灵上设置单击处理程序,只能在画布本身上设置;您需要检查鼠标坐标是否在绘制的精灵内。

当然,另一种方法是使用HTML5拖放API,虽然我没有使用它的经验,但它可能更适合您的需求。

http://www.html5rocks.com/en/tutorials/dnd/basics/


1
函数collides应该在“else”情况下返回false。 - GameAlchemist
当然,虽然我没有发现需要返回false值的必要性;如果出现碰撞,则会采取一些行动,在敌人被摧毁/得分增加的情况下,否则一切都会按照正常方式继续。 - Ben
嗨,谢谢你的回答-看起来确实是我想做的事情。我已经在画布上显示了所有的图片,其中有四个“静态”图片,不能被拖动-这些是我想要用作我的“放置区”,而其他的可以拖放。我不太确定如何将你的代码提供的功能添加到我已有的内容中?如果你访问以下链接:http://users.aber.ac.uk/eef8/project/development/featureset2dev/,你就能看到我已经实现了什么。 - Noble-Surfer
要将“dropzone”功能添加到我的描述框中,我是否应该像您在示例中所做的那样使用行var i = new Image(200, 200, 50, 50, 'cat.jpg', 300, 300, 60, 60);将它们添加到画布中? - Noble-Surfer
是的,这就是我设置的方式;使用图像的x/y/w/h以及放置区域的x/y/w/h。当然,您可以在创建新图像时修改这些值。然后,在您的更新函数中(请查看requestAnimationFrame),使用“collides”函数检查图像是否与其放置区域发生碰撞;“if(collides(i, i.dropzone)) { // success! }” - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接