在 JavaScript 中实现冲突检测

Sahil Bhosale 2024年2月15日
在 JavaScript 中实现冲突检测

在 JavaScript 中,当两个或多个 HTML 元素发生冲突时,就会发生冲突。默认情况下,当在 HTML 元素上使用移动事件侦听器时,它不会碰到屏幕上的任何其他元素。

它将通过 DOM 中的其他元素。因此,要在 JavaScript 中检测冲突,我们必须手动使用元素的 x 和 y 坐标进行检测。

在本文中,我们将在网页中使用两个 div 元素(两个正方形),我们将了解如何在其中一个正方形与另一个正方形发生冲突时实现冲突检测。

在 JavaScript 中实现冲突检测

我们将纯粹在 JavaScript 中实现冲突检测,我们不会使用任何其他第三方库。首先,我们将编写 HTML,然后我们将进入 CSS 部分,最后,我们将编写 JavaScript 代码。

在 HTML 中,我们将添加两个具有类 square_1square_2div 元素。square_2 将位于固定位置,而 square_1 将在屏幕上的任何位置移动。

<body>
    <div class="square_1"></div>
    <div class="square_2"></div>
</body>

我们将在 CSS 中将宽度和高度等基本样式添加到正方形的 160px 中,并将两个正方形的位置更改为 absolute。它将允许我们将方块移动到屏幕上的任何位置。

我们将给 square_1 一个红色的背景颜色,给 square_2 一个黄色的背景颜色。

由于我们希望 square_2 固定在屏幕上的特定位置,我们将添加一个 lefttop 属性并给它一个值 400px。我们还将向 square_1 添加一个 font-size 属性,因为我们将在与另一个冲突后在其上显示一个文本。

最后,我们将第一个方格的 z-index 设置为 1,因为我们希望它在移动时保持在另一个方格之上。如果我们不设置此属性,它将位于第二个正方形下方。

.square_2{
    width: 160px;
    height: 160px;
    position: absolute;
    left: 400px;
    top: 400px;
    background-color:rgb(255, 233, 36);
}

.square_1{
    position: absolute;
    width: 160px;
    height: 160px;
    background-color:rgb(255, 80, 80);
    font-size: 1.5em;
    z-index: 1;
}

输出:

没有移动事件监听器的输出

我们无法移动红色方块,因为我们没有添加移动事件监听器。

我们首先必须访问我们在 HTML 中添加到 JavaScript 代码的两个方块。为此,我们将使用 getElementsByClassName() 函数来获取两个 div 元素并将类名作为参数传递给该函数。

由于此函数返回一个数组,我们将通过索引来获取第一个元素。然后我们将两个正方形 div 存储在 square_1square_2 变量中。

现在我们可以访问两个正方形元素,我们将首先获取这两个元素的宽度和高度。我们有一个名为 getComputedStyle() 的 JavaScript 函数,它接受一个元素作为参数。

所以,我们将把 square_1square_2 变量作为参数传递给这个函数。然后,使用点符号,我们将访问元素的 CSS 属性。

请注意,我们还使用了 split() 函数。这是因为 getComputedStyle() 函数返回一个带有其单位的值。

例如,我们将两个元素的宽度设置为 160px。所以 getComputedStyle() 函数返回的值将是字符串形式的 160px

我们不想要 px 部分,所以我们使用 split() 并在其中传递 px。该函数将返回一个包含两个元素的数组,第一个元素为 160,第二个元素为空白。

我们需要值本身,所以我们将使用 [0] 来访问它。

var square_1 = document.getElementsByClassName('square_1')[0];
var square_2 = document.getElementsByClassName('square_2')[0];

var square_1_width =
    Number((getComputedStyle(square_1).width).split('px')[0]) / 2;
var square_2_width =
    Number((getComputedStyle(square_2).width).split('px')[0]) / 2;

var square_1_height =
    Number((getComputedStyle(square_1).height).split('px')[0]) / 2;
var square_2_height =
    Number((getComputedStyle(square_2).height).split('px')[0]) / 2;

由于返回的值将是一个字符串,我们将其转换为一个数字并除以 2,因为我们想要它的一半值,即 80。最后,我们将值存储到变量中,如上所示。

现在,我们将使用 addEventListener() 函数在 square_1 上添加一个 mousemove 事件侦听器。如下图所示,这个函数接受一个事件和一个回调函数作为参数。

我们将事件 e 传递给回调函数以跟踪鼠标在屏幕上的位置。

一旦我们将鼠标光标悬停在 square_1 上并移动鼠标,我们希望将鼠标的左侧和顶部位置分配给正方形的左侧和顶部位置,以便它可以移动到我们移动鼠标光标的任何位置。

square_1.addEventListener('mousemove', (e) => {
  square_1.style.left = (e.clientX - square_1_width) + 'px';
  square_1.style.top = (e.clientY - square_1_height) + 'px';

  checkCollision();
});

输出:

添加了 Mousemove 事件侦听器冲突

e.clientXe.clientY 给出了鼠标移动的右上角和右下角位置。

但是,我们希望光标显示在正方形的中心,因此我们使用 square_1_widthsquare_1_height 减去正方形的宽度和高度,并将半宽和高度存储在其中。

这将使我们拖动时鼠标光标指向正方形的中心,如下图所示。

在运行代码之前,请确保注释掉 checkCollision() 函数,因为我们尚未在代码中定义它。

现在,让我们创建 checkCollision() 函数来检测冲突。在这里,我们将首先使用 getComputedStyle() 函数获取方格的左侧和顶部位置。

最后,我们将字符串值类型转换为数字并将其存储在变量中。

我们将把 square_1 的左侧和顶部位置存储在 x_pos_sq_1y_pos_sq_1 变量中,并将 square_2 存储在 x_pos_sq_2y_pos_sq_2 变量中。

现在,我们将检查我们的第一个正方形(红色)是否穿过第二个正方形(黄色)的四个边中的任何一个。我们将为第二个正方形(黄色)的每一边添加一个条件以进行检查。

请注意,正方形的 x 和 y 位置当前都在正方形的中心。

function checkCollision() {
  let x_pos_sq_1 = Number((getComputedStyle(square_1).left).split('px')[0]);
  let y_pos_sq_1 = Number((getComputedStyle(square_1).top).split('px')[0]);

  let x_pos_sq_2 = Number((getComputedStyle(square_2).left).split('px')[0]);
  let y_pos_sq_2 = Number((getComputedStyle(square_2).top).split('px')[0]);

  let leftPos = x_pos_sq_1 + square_1_width > x_pos_sq_2 - square_2_width;
  let rightPos = x_pos_sq_1 - square_1_width < x_pos_sq_2 + square_2_width;

  let topPos = y_pos_sq_1 + square_1_height > y_pos_sq_2 - square_2_height;
  let bottomPos = y_pos_sq_1 - square_1_height < y_pos_sq_2 + square_2_height;

  if (leftPos && rightPos && topPos && bottomPos) {
    square_1.innerHTML = 'Collision occured';
    square_2.style.border = '5px solid rgb(24, 251, 240)';
  } else {
    square_1.innerHTML = '';
    square_2.style.border = 'none';
  }
}

输出:

黄色方块与蓝色边框的冲突

为了检测红色方块是否从左侧与黄色方块发生冲突,我们将检查红色方块的 x 位置和宽度是否大于黄色方块的 x 位置减去其宽度。如果红色方块较大,则从左侧与黄色方块发生冲突。

它将返回一个布尔值,我们将存储在 leftPos 变量中。

为了检测红色方块是否从右侧与黄色方块发生冲突,我们将检查红色方块的 x 位置减去其宽度是否小于黄色方块的 x 位置及其宽度。如果较小,红色方块与右侧的黄色方块发生冲突。

它将返回一个布尔值,我们将存储在 rightPos 变量中。

顶部位置与左侧位置相似;唯一的区别是我们处理的是 y 轴和高度,而不是 x 轴和宽度。这将返回一个布尔值,我们将其存储在 topPos 变量中。

底部位置与右侧位置类似,但我们处理的是 y 轴和高度。这也将返回一个布尔值,我们将其存储在 bottomPos 变量中。

checkCollision() 函数的末尾,我们将通过添加 leftPosrightPostopPosif 条件来检查红色方块是否越过黄色方块的边界。bottomPos 里面。

如果所有变量都生成一个 true 值,则 square_1square_2 冲突。一旦发生这种情况,我们将为黄色方块添加蓝色边框,并且我们还将在红色方块上添加文本发生冲突,如上所示。

如果我们将红色方块移到黄色方块的边界之外,那么我们将从黄色方块中移除边框并从红色方块中移除文本。

作者: Sahil Bhosale
Sahil Bhosale avatar Sahil Bhosale avatar

Sahil is a full-stack developer who loves to build software. He likes to share his knowledge by writing technical articles and helping clients by working with them as freelance software engineer and technical writer on Upwork.

LinkedIn