Обзор

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

Шаг 1 - Определите противостоящие объекты

Первым шагом в реализации обнаружения столкновений является определение объектов, с которыми мы хотим тестировать. В нашем примере мы будем тестировать против вымышленного ГЕРОЯ и группы ВРАГОВ.

Шаг 2. Создайте "конфликтующую" переменную

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

var colliding = false;

Шаг 3. Напишите функцию «collisionDetection»

Мы начнем нашу функцию «collisionDetection» с определения размера наших объектов. В нашем примере все наши объекты имеют размер 20, и все они являются кругами. Здесь мы сохраняем простоту. Мы также хотим создать экземпляр переменной столкновения, которая по умолчанию имеет значение false. Это отличается от предыдущей переменной «столкновения», которую мы создали, тем, что переменная «столкновение» будет оставаться ложной все время, пока объект-герой не сталкивается с врагом, и будет оставаться верной все время, пока герой сталкивается с враг. Задача переменной «collision» внутри «collisionDetection» состоит в том, чтобы сообщить нам, когда наш герой сталкивается с врагом или прекращает столкновение с врагом, и в обоих случаях мы будем переключать переменную «столкновения». Наконец, мы создаем экземпляр переменной hero, которая относится к группе heros.

var collisionDetection = function() {
  var radius = 20;
  var collision = false;
  var hero = heros;

Далее мы будем использовать метод «each», чтобы проверить расстояние каждого врага от героя. Если расстояние от врага до героя меньше двойного радиуса объекта (который является размером наших круглых объектов), мы установим для параметра «столкновение» значение true. Для определения расстояния воспользуемся теоремой Пифагора (a² + b² = c²). Фактически, мы будем измерять положение (x, y) наших врагов на экране в отличие от положения (x, y) нашего героя, учитывая, что экран разделен на сетку координат (x, y). c² - это расстояние, но у нас есть только значения a и b (x и y), поэтому мы используем теорему Пифагора.

enemies.each(function() {
  var enemyX = parseInt(this.cx.animVal.value) + radius;
  var enemyY = parseInt(this.cy.animVal.value) + radius;
  var heroX = parseInt(hero[0][0].cx.animVal.value) + radius;
  var heroY = parseInt(hero[0][0].cy.animVal.value) + radius;
  var a = enemyX - heroX;
  var b = enemyY - heroY;
  var c = Math.sqrt(a * a + b * b);
  var distance = c;
  if (distance < radius * 2) {
    collision = true;
  }
});

Переменная «вражеский X» выше вычисляет положение врага на экране по значению x (animVal отслеживает положение объекта во время анимации). Переменная «ownY» вычисляет позицию врага на экране по оси y. «HeroX» и «heroY» делают то же самое с героем. Мой герой входит в группу «героев», поэтому я выделяю его, выбирая индекс [0] [0], где находится мой герой. Возвращаясь к нашей теореме Пифагора, a = позиция "врагаX" минус позиция "heroX", b = позиция "врагаY" минус позиция "heroY", а c = квадратный корень из a² + b². Я создал экземпляр переменной «distance» только для пояснения, что это расстояние между врагом и героем.

Затем мы устанавливаем «столкновение» равным «столкновению». Опять же, «столкновение» просто описывает состояние наших объектов-героев. Если мы проверим столкновение дважды во время одного и того же столкновения между героем и объектом, мы можем обнаружить, что это не новое столкновение, а продолжение предыдущего столкновения.

  colliding = collision;
};

Последнее, что нам нужно сделать, это установить нашу функцию «collisionDetection» на таймер, чтобы она постоянно проверяла наличие столкновений во время движения наших объектов. Мы можем легко сделать это в D3.js, используя метод «таймера» D3.

d3.timer(collisionDetection);

Бонусный шаг - инициировать подсчет столкновений

Если мы хотим подсчитать количество столкновений, которые происходят между нашим героем и врагами, нам нужно только проверить, имеет ли значение переменной «collision» значение true, а значение переменной «colliding» - ложь. Это скажет нам, что объекты перешли из состояния отсутствия столкновений в состояние столкновения. Затем наша переменная «столкновения» будет установлена ​​в значение true, и этот раздел нашей функции не будет запущен, пока другой враг не столкнется с героем или в следующий раз, когда этот враг столкнется с нашим героем. Посмотрим, как это выглядит.

if (collision && collision !== colliding) {
 collisionCount++;
}

Резюме

Наша завершенная функция обнаружения столкновений выглядит так:

var colliding = false;
var collisionDetection = function() {
  var radius = 20;
  var collision = false;
  var hero = heros;
  enemies.each(function() {
    var enemyX = parseInt(this.cx.animVal.value) + radius;
    var enemyY = parseInt(this.cy.animVal.value) + radius;
    var heroX = parseInt(hero[0][0].cx.animVal.value) + radius;
    var heroY = parseInt(hero[0][0].cy.animVal.value) + radius;
    var a = enemyX - heroX;
    var b = enemyY - heroY;
    var c = Math.sqrt(a * a + b * b);
    var distance = c;
    if (distance < radius * 2) {
      collision = true;
    }
  }); // end enemies.each
  if (collision && collision !== colliding) {
    collisionCount++;
  }
  colliding = collision;
}; // end collisionDetection
d3.timer(collisionDetection);

Если кто-то хочет выделить здесь синтаксис, вот функция в Sublime:

И вот оно!