2.5D Renderer

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

Проекция отрезков

На этом шаге мы можем воспользоваться следующей идеей: зная высоту предмета на конкретном расстоянии, мы можем найти его высоту на любом другом расстоянии, используя пропорцию. А зная высоту, мы можем получить координату Y для нижней и верхней части этого предмета.

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

2.5D Renderer

2D Renderer

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

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

Определим расстояние от позиции камеры до точки:

Пусть на расстоянии 1 высота стены будет равна константе H wall, тогда на расстоянии d высота:

На основе проекции screenX на экран и найденной высоты стены h формируем координаты четырёхугольника.

Немного кода

Ранее спроецированные точки достраиваем до четырёхугольника:


  function projectionToPoints(
    camera: Camera,
    vertexProjectionStart: VertexProjection,
    vertexProjectionEnd: VertexProjection,
  ): Vertex[] {
    const wallStartHeight = vertexProjectionStart.height;
    const wallEndHeight = vertexProjectionEnd.height;
    const horizontalHeight = camera.screen.height / 2;

    return [
      {
        x: vertexProjectionStart.screenX,
        y: horizontalHeight - wallStartHeight / 2,
      },
      {
        x: vertexProjectionStart.screenX,
        y: horizontalHeight + wallStartHeight / 2,
      },
      { x: vertexProjectionEnd.screenX, y: horizontalHeight + wallEndHeight / 2 },
      { x: vertexProjectionEnd.screenX, y: horizontalHeight - wallEndHeight / 2 },
    ];
  }

И теперь на их основе рисуем многоугольник на экране:


  function render25d(
    ctx: CanvasRenderingContext2D,
    settings: Settings,
  ) {
    for (const linedef of settings.level.linedefs) {
      const vertexProjectionStart = projectVertexToScreen(settings.camera, linedef.start);
      const vertexProjectionEnd = projectVertexToScreen(settings.camera, linedef.end);
  
      if (!vertexProjectionStart || !vertexProjectionEnd) {
        continue;
      }
  
      drawPolygon(
        ctx,
        projectionToPoints(settings.camera, vertexProjectionStart, vertexProjectionEnd),
      );
    }
  }

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