2.5D Renderer

Stage 1: Отрисовка стен

Проекция вершин

Самое тяжелое в проектировании — это определить базовый набор идей и абстракций. И честно говоря, в свое время мне было тяжело понять, какой шаг нужно было сделать первым, пока не познакомился с заметками DIYDoom, а в частности с тем, как необходимо сделать горизонтальную проекцию.

На этом шаге необходимо сделать проекцию вершины на камеру в виде вертикальной линии.

2.5D Renderer

2D Renderer

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

Как это рассчитать

Введем условные обозначения:

Вычисляем угол между направлением камеры и вершиной на карте:

Если угол входит в поле обзора камеры, мы линейно преобразуем его относительное положение внутри области видимости в координату X на экране:

Немного кода

Получившийся мир для нас — это множество спроецированных точек в виде вертикальных линий:


  function render25d(ctx: CanvasRenderingContext2D, settings: Settings) {
    const camera = settings.camera;
    for (const linedef of settings.level.linedefs) {
      for (const vertex of [linedef.start, linedef.end]) {
        const screenX = projectVertexToScreen(vertex, camera);
        if (screenX == null) {
          continue;
        }
        ctx.fillStyle = "black";
        ctx.fillRect(screenX, 0, 1, screen.height);
      }
    }
  }

Проекция вершины на экран:


  function projectVertexToScreen(vertex: Vertex, camera: Camera) {
    const vertexAngle = toAngle(vertex, camera).degrees;
    const cameraAngleFrom = camera.angle.degrees - camera.fov.degrees / 2;
    const cameraAngleTo = camera.angle.degrees + camera.fov.degrees / 2;

    if (cameraAngleTo < vertexAngle || vertexAngle < cameraAngleFrom) {
      return null;
    }

    return (
      ((vertexAngle - cameraAngleFrom) / camera.fov.degrees) * camera.screen.width
    );
  }

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