2.5D Renderer

Stage 0: Введение

Двумерная карта

Если вы вдруг не знали или забыли, то ранние шутеры Wolfenstein 3D и DOOM от компании id Software были псевдотрёхмерными. Разработчики особым образом достраивали ещё одно измерение на основе двумерной карты и делали проекцию на воображаемый экран камеры. Поэтому вполне очевидно, что разработку отрисовщика необходимо начать с реализации двумерной карты. Для этого нам потребуется ввести некоторые абстракции.

Введём такие сущности, как Vertex (вершина) и Linedef (отрезок):


  interface Vertex {
    x: number;
    y: number;
  }

  interface Linedef {
    start: Vertex;
    end: Vertex;
  }

Для работы с углами опишем класс Angle со вспомогательными методами:


  class Angle {
    private _degrees: number;

    constructor(degrees: number) {
      this._degrees = ((degrees % 360) + 360) % 360;
    } 
    
    get degrees() {
      return this._degrees;
    }
    
    get radians() {
      return this._degrees * Math.PI / 180;
    }

    get cos() {
      return Math.cos(this.radians);
    }

    get sin() {
      return Math.sin(this.radians);
    }
  }

Опишем камеру, которую планируем перемещать по карте и на которую будет проецироваться будущее изображение:


  interface Camera {
    angle: Angle;
    fov: Angle;
    x: number;
    y: number;
    moveSpeed: number;
    rotationSpeed: number;
  }

Для каждого отрисовщика, а на странице их может быть несколько, добавим его настройки:


  interface Settings {
    camera: Camera;
    level: Level;
  }

  type Level = {
    linedefs: Linedef[];
  }

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

Управление камерой WASD

Координаты 200.00 x 320.00, угол 270

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

Реализация шага на github