Stage 4: Улучшаем движение
Учитываем высоту сектора
До этого шага камера двигалась по карте почти как точка на плоскости: менялись x и
y, а высота взгляда оставалась условно постоянной. Но в уровне уже есть сектора с разной высотой пола,
поэтому при переходе на ступеньку камера должна оказаться выше, а при спуске - ниже.
2.5D Renderer
2D Renderer
Для этого у камеры появляется собственная высота height: это расстояние от пола сектора до глаз игрока.
Само положение глаз хранится в camera.z. Когда камера переходит в другой сектор, мы берем высоту пола
этого сектора и прибавляем к ней высоту камеры:
function moveCamera(camera: Camera, direction: number, sector: Sector) {
const playerCos = camera.angle.cos * camera.moveSpeed;
const playerSin = camera.angle.sin * camera.moveSpeed;
const newX = camera.x + direction * playerCos;
const newY = camera.y + direction * playerSin;
const height = camera.height || DEFAULT_CAMERA_HEIGHT;
const newZ = sector.floorHeight! + height;
return {
...camera,
x: newX,
y: newY,
z: newZ,
};
}
Главная строка здесь sector.floorHeight + height и она говорит, что глаза игрока всегда находятся на одной и той же высоте относительно пола текущего сектора. Поэтому при движении по лестнице меняется не только положение на карте, но и вертикальное положение камеры.
Чтобы понять, какой пол сейчас под камерой, перед движением ищем сектор, в котором находится камера. Здесь нам уже
помогает BSP-дерево: findCameraSector возвращает текущий сектор, а движение пересчитывается с учетом его высоты.
setSettings((prev) => {
const sector = findCameraSector(bspTree, prev.camera)!;
return {
...prev,
camera: moveCamera(prev.camera, isMoving(), sector),
};
});
Виджет карты, а именно клавиши Z и X позволяют поднять или опустить камеру вручную. Но даже такое движение нельзя оставлять без границ: камера не должна проваливаться ниже пола и не должна подниматься выше потолка сектора.
function riseCamera(camera: Camera, direction: number, sector: Sector) {
const speed = camera.riseSpeed || DEFAULT_CAMERA_VERTICAL_SPEED;
const height = camera.height || DEFAULT_CAMERA_HEIGHT;
let newZ = camera.z! + direction * speed;
newZ = Math.max(
sector.floorHeight! + height,
Math.min(sector.ceilHeight! - height, newZ)
);
return {
...camera,
z: newZ,
};
}
По итогу горизонтальное перемещение остается прежним, но высота взгляда теперь зависит от сектора. Благодаря этому ступени и разные уровни пола начинают ощущаться не только в геометрии стен, но и в поведении камеры.