Книга: Выразительный JavaScript

Движение и столкновение

Теперь нам надо добавить обработку движений – самое интересное в игре. Простой подход, который используют большинство игр – разделить время на небольшие отрезки, и на каждом шаге сдвигать актёров на дистанцию, соответствующую их скорости (расстояние в секунду), умноженное на длительность временного отрезка (в секундах).

Это просто. Сложность в том, что надо обрабатывать взаимодействие предметов. Когда игрок касается пола или стены, он не должен проходить насквозь. Игра должна замечать, когда движение одного объекта приводит к столкновению с другим и реагировать соответственно. Стены останавливают движение, монеты собираются, и так далее.

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

Перед тем, как сдвинуть игрока или блок лавы, мы проверяем, не приведёт ли нас движение внутрь непустой части фона. Если да – мы отменяем движение. Реакция на это будет зависеть от типа актёра – игрок останавливается, лава отскакивает.

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

Метод сообщает, не пересекается ли прямоугольник (заданный позицией и размером) с каким-либо непустым пространством фоновой решётки.

Level.prototype.obstacleAt = function(pos, size) {
  var xStart = Math.floor(pos.x);
  var xEnd = Math.ceil(pos.x + size.x);
  var yStart = Math.floor(pos.y);
  var yEnd = Math.ceil(pos.y + size.y);
  if (xStart < 0 || xEnd > this.width || yStart < 0)
    return "wall";
  if (yEnd > this.height)
    return "lava";
  for (var y = yStart; y < yEnd; y++) {
    for (var x = xStart; x < xEnd; x++) {
      var fieldType = this.grid[y][x];
      if (fieldType) return fieldType;
    }
  }
};

Метод вычисляет занимаемые телом ячейки решётки, применяя Math.floor и Math.ceil на координатах тела. Помните, что размеры ячеек – 1?1 единиц. Округляя границы тела вверх и вниз, мы получаем промежуток из ячеек фона, которых касается тело.


Оглавление книги

Оглавление статьи/книги

Генерация: 1.107. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз