Обнаружение столкновения объекта с пространственным разделением в JavaScript - PullRequest
2 голосов
/ 07 января 2020

Я пытаюсь создать систему из множества объектов, которые формируют действие, когда они сталкиваются друг с другом, я использую библиотеку P5.min. js.

Я настроил массив для сетки и массив для объектов, но я не могу найти правильный путь к go через каждую ячейку сетки и проверять только объекты внутри этой ячейки до переходя к следующей ячейке.

Вот что у меня есть до сих пор

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

Как я проверяю столкновение между всеми объектами:

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

Как Насколько я вижу, мне нужно поместить эти циклы for в другой, проходящий через каждую ячейку в сетке, но я не знаю, как ограничить поиск, к которому когда-либо tempArray (s) относится объект

Если в этом есть какой-то смысл, это то, что я пытаюсь сделать

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

1 Ответ

2 голосов
/ 07 января 2020

Ячейка сетки представлена ​​массивом массива gridArray. Вам необходимо иметь коллекцию молекул для каждой ячейки сетки . Я рекомендую использовать Set с вместо Array, так как заказ не имеет значения. Идея состоит в том, чтобы иметь возможность доступа к набору молекул в данной ячейке сетки (i,j) с синтаксисом:

gridArray[i][j]

Следующий код создаст массив numOfRow массивы:

const numOfRow = 5;

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

gridArray с похожим на это:

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

Внутри splitIntoGrid вы проверяете, какие молекулы в каких ячейках сетки находятся. Это хорошо. Однако для каждой ячейки сетки вы перезаписываете global variable tempArray. Поэтому в конце выполнения функции tempArray будет содержать только молекулы последней ячейки сетки, а это не то, что вам нужно. Для данной ячейки сетки мы добавим правильные молекулы к 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);
                    }
            });
        }
    }
}

Теперь вы готовы проверять наличие столкновений в каждой ячейке сетки. У нас будет четыре петли внутри друг друга. Два для навигации по сетке и два для сравнения молекул, которые содержатся внутри каждой ячейки сетки:

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

В приведенном выше коде, #forEach пригодится.

...