简体   繁体   English

在 JavaScript 中使用空间分区检测对象碰撞

[英]Detecting object collision with spatial partitioning in JavaScript

I'm trying to create a system of many objects that preform an action when they collide with each other, I'm using the P5.min.js library.我正在尝试创建一个由许多对象组成的系统,当它们相互碰撞时会执行一个动作,我正在使用 P5.min.js 库。

I've set up an array for the grid and an array for the objects, but I can't figure out the right way to go through each grid cell and check only the objects inside that cell before moving on to the next cell.我已经为网格设置了一个数组,并为对象设置了一个数组,但我无法找出正确的方法来遍历每个网格单元并在移动到下一个单元之前只检查该单元内的对象。

Here's what I've got so far这是我到目前为止所得到的

let molecules = [];
const numOfMolecules = 100;
let collisions = 0;
let check = 0;
let maxR = 10; //max molecule radius
let minR = 2; //min molecule radius
let numOfCol = 5;
let numOfRow = 5;
let CellW = 600/numOfCol; //gridWidth
let CellH = 600/numOfRow; //gridHeight
let remain = numOfMolecules;
let gridArray = [];



function setup() {
    createCanvas(600, 600);
    background(127);

    for (let i = 0; i < numOfMolecules; i++) {
        molecules.push(new Molecule());
    }
}

function draw() {
    background(127);

    molecules.forEach(molecule => {
        molecule.render();
        molecule.checkEdges();
        molecule.step();
    });

    drawGrid();
    splitIntoGrid();
    collision();
    displayFR();
}

function drawGrid() {
    for (i = 0; i < numOfRow+1; i++){
        for (j = 0; j < numOfCol+1; j++){
            noFill();
            stroke(0);
            rect(CellW*(j-1), CellH*(i-1), CellW, CellH);
        }
    }
}

function splitIntoGrid(){
    for (let i = 0; i < numOfRow; i++){
        for (let j = 0; j < numOfCol; j++){
            tempArray = [];
            molecules.forEach(molecule => {
                if (molecule.position.x > (CellW*j) &&
                    molecule.position.x < (CellW*(j+1)) &&
                    molecule.position.y > (CellH*i) &&
                    molecule.position.y < (CellH*(i+1))) {
                        tempArray.push(molecule.id);
                    }
            });
        }
    }
}

How I'm checking collision between all objects:我如何检查所有对象之间的碰撞:

function collision() {
    for (let i=0; i < molecules.length; i++){
        for (let j=0; j < molecules.length; j++){
            let diff = p5.Vector.sub(molecules[j].position, molecules[i].position);
            check++;
            if (i != j && diff.mag() <= molecules[j].radius + molecules[i].radius){
                collisions++;
                molecules[j].changeColor();
            }
        }
    }
}

As far as I can see, I need to put these for loops inside another one going through each cell in the grid, but I don't know how to limit the search to which ever tempArray(s) the object is in据我所知,我需要将这些 for 循环放在另一个循环中,遍历网格中的每个单元格,但我不知道如何将搜索限制为对象所在的 tempArray(s)

If this makes any sense, this is what I'm trying to do如果这有任何意义,这就是我想要做的

function collision() {
  for (let k = 0; k < gridArray.length; k++){
    for (let i=0; i < gridArray.tempArray.length; i++){
        for (let j=0; j < gridArray.tempArray.length; j++){
            let diff = p5.Vector.sub(gridArray.tempArray[j].position, gridArray.tempArray.position);
            check++;
            if (i != j && diff.mag() <= gridArray.tempArray[j].radius + gridArray.tempArray[i].radius){
                collisions++;
                gridArray.tempArray[j].changeColor();
                gridArray.tempArray[i].changeColor();
            }
        }
    }
  }
}

The grid cell is represented by an array of array gridArray .网格单元由数组gridArray的数组gridArray You need to have a collection of molecules for each grid cell.您需要为每个网格单元收集分子。 My recommendation would be to use Set s instead of an Array since the order is irrelevant.我的建议是使用Set而不是Array因为顺序无关紧要。 The idea is to be able to access the set of molecules on a given grid cell (i,j) with the syntax:这个想法是能够使用以下语法访问给定网格单元(i,j)上的一组分子:

gridArray[i][j]

The following code will create an array of numOfRow arrays:以下代码将创建一个由numOfRow数组numOfRow数组:

const numOfRow = 5;

const gridArray = (new Array(numOfRow)).fill([]);

gridArray with look like this: gridArray看起来像这样:

[ [], [], [], [], [] ]

Inside splitIntoGrid you are checking which molecules are in which grid cells.splitIntoGrid您正在检查哪些分子在哪些网格单元中。 This is good.这很好。 However, for each grid cell, you are overwriting the global variable tempArray .但是,对于每个网格单元,您都将覆盖全局变量tempArray Therefore, at the end of the function's execution, tempArray will only hold the molecules of the last grid cell, which isn't what you want.因此,在函数执行结束时, tempArray将只保存最后一个网格单元格的分子,这不是您想要的。 For a given grid cell, we will add the right molecules to a Set associated with this grid cell.对于给定的网格单元,我们会将正确的分子添加到与该网格单元关联的Set中。

The Set data structure has an #add method which appends a new element to the set: Set数据结构有一个#add方法,它向集合追加一个新元素:

function splitIntoGrid() {
    for (let i = 0; i < numOfRow; i++) {
        for (let j = 0; j < numOfCol; j++) {
            gridArray[i][j] = new Set();
            molecules.forEach(molecule => {
                if (molecule.position.x > (CellW*j) 
                    && molecule.position.x < (CellW*(j+1))
                    && molecule.position.y > (CellH*i) 
                    && molecule.position.y < (CellH*(i+1))) {
                        gridArray[i][j].add(molecule);
                    }
            });
        }
    }
}

Now you're ready to check for collisions on each grid cells.现在您已准备好检查每个网格单元上的碰撞。 We will have a total of four loops inside one another.我们将总共有四个循环。 Two to navigate through the grid and two to compare the molecules that are contained inside each grid cell:两个用于在网格中导航,两个用于比较每个网格单元内包含的分子:

function collision() {
  for (let i = 0; i < numOfRow; i++) {
    for (let j = 0; j < numOfCol; j++) {
      gridArray[i][j].forEach(moleculeA => {
        gridArray[i][j].forEach(moleculeB => {
          const diff = p5.Vector.sub(moleculeA.position, moleculeB.position);
          if (moleculeA != moleculeB && diff.mag() <= moleculeA.radius + moleculeB.radius) {
            collisions++;
            moleculeA.changeColor();
            moleculeB.changeColor();
          }
        });
      });
    }
  }
}

In the above code, #forEach comes in handy.在上面的代码中, #forEach派上用场。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM