154 lines
5.3 KiB
JavaScript
154 lines
5.3 KiB
JavaScript
import { TILE } from '../core/constants.js';
|
||
import { BLOCKS } from '../data/blocks.js';
|
||
import { state } from '../core/state.js';
|
||
import { getBlock, isSolid } from '../world/world-storage.js';
|
||
import { calculateDamage } from '../entities/player.js';
|
||
|
||
function resolveY(e) {
|
||
// Всегда пересчитываем grounded (не держим "липким")
|
||
e.grounded = false;
|
||
|
||
const x1 = e.x + 2;
|
||
const x2 = e.x + e.w - 2;
|
||
|
||
// Проверяем, находится ли игрок на лестнице (по центру)
|
||
const cx = e.x + e.w / 2;
|
||
const cy = e.y + e.h / 2;
|
||
const gx = Math.floor(cx / TILE);
|
||
const gy = Math.floor(cy / TILE);
|
||
const b = getBlock(gx, gy);
|
||
const onLadder = b && BLOCKS[b.t] && BLOCKS[b.t].climbable;
|
||
|
||
// Если на лестнице - можно двигаться вверх/вниз
|
||
if (onLadder) {
|
||
e.grounded = true;
|
||
|
||
// Если нажимаем прыжок на лестнице - поднимаемся
|
||
if (state.inp.jump) {
|
||
e.vy = -200;
|
||
}
|
||
// Если нажимаем вниз - спускаемся
|
||
else if (state.inp.down) {
|
||
e.vy = 100;
|
||
}
|
||
// Иначе - остаёмся на месте (нет гравитации)
|
||
else {
|
||
e.vy = 0;
|
||
}
|
||
return;
|
||
}
|
||
|
||
// Проверяем, можно ли запрыгнуть на лестницу рядом (слева или справа)
|
||
const leftGX = Math.floor((e.x - 4) / TILE);
|
||
const rightGX = Math.floor((e.x + e.w + 4) / TILE);
|
||
const playerGY = Math.floor((e.y + e.h / 2) / TILE);
|
||
|
||
const leftBlock = getBlock(leftGX, playerGY);
|
||
const rightBlock = getBlock(rightGX, playerGY);
|
||
const leftLadder = leftBlock && BLOCKS[leftBlock.t] && BLOCKS[leftBlock.t].climbable;
|
||
const rightLadder = rightBlock && BLOCKS[rightBlock.t] && BLOCKS[rightBlock.t].climbable;
|
||
|
||
// Если рядом есть лестница и игрок прыгает - притягиваем к ней
|
||
if ((leftLadder || rightLadder) && state.inp.jump && e.vy < 0) {
|
||
// Перемещаем игрока к лестнице
|
||
if (leftLadder && e.x > leftGX * TILE + TILE / 2) {
|
||
e.x = leftGX * TILE + TILE / 2 - e.w / 2;
|
||
} else if (rightLadder && e.x < rightGX * TILE + TILE / 2) {
|
||
e.x = rightGX * TILE + TILE / 2 - e.w / 2;
|
||
}
|
||
e.grounded = true;
|
||
e.vy = -150; // меньший прыжок при запрыгивании на лестницу
|
||
return;
|
||
}
|
||
|
||
// 1) Если движемся вниз ИЛИ стоим (vy >= 0) — проверяем опору под ногами
|
||
// Берём точку на 1px ниже стопы, чтобы не зависеть от ровного попадания в границу тайла.
|
||
if (e.vy >= 0) {
|
||
const probeY = e.y + e.h + 1;
|
||
const gy = Math.floor(probeY / TILE);
|
||
const gxA = Math.floor(x1 / TILE);
|
||
const gxB = Math.floor(x2 / TILE);
|
||
|
||
if (isSolid(gxA, gy) || isSolid(gxB, gy)) {
|
||
e.y = gy * TILE - e.h; // прижимаем к полу
|
||
e.vy = 0;
|
||
e.grounded = true;
|
||
|
||
// урон от падения — только игроку и только не в воде
|
||
if (e === state.player && !state.player.inWater) {
|
||
const fallTiles = (e.y - e.fallStartY) / TILE;
|
||
if (fallTiles > 6) {
|
||
const damage = calculateDamage((fallTiles - 6) * 10);
|
||
state.player.hp -= damage;
|
||
}
|
||
}
|
||
if (e === state.player) e.fallStartY = e.y;
|
||
}
|
||
}
|
||
|
||
// 2) Проверка на возможность запрыгнуть на блок, если игрок рядом с ним
|
||
if (e.vy < 0 && e === state.player) {
|
||
const gy = Math.floor(e.y / TILE);
|
||
const gxA = Math.floor(x1 / TILE);
|
||
const gxB = Math.floor(x2 / TILE);
|
||
|
||
// Проверяем, есть ли блок рядом с игроком
|
||
if ((isSolid(gxA, gy) || isSolid(gxB, gy)) && !isSolid(gxA, gy - 1) && !isSolid(gxB, gy - 1)) {
|
||
e.y = (gy + 1) * TILE;
|
||
e.vy = 0;
|
||
e.grounded = true;
|
||
if (e === state.player) e.fallStartY = e.y;
|
||
console.log("Jumped onto block!");
|
||
}
|
||
}
|
||
|
||
// 2) Если движемся вверх — проверяем потолок
|
||
if (e.vy < 0) {
|
||
const gy = Math.floor(e.y / TILE);
|
||
const gxA = Math.floor(x1 / TILE);
|
||
const gxB = Math.floor(x2 / TILE);
|
||
if (isSolid(gxA, gy) || isSolid(gxB, gy)) {
|
||
e.y = (gy + 1) * TILE;
|
||
e.vy = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
function resolveX(e) {
|
||
const y1 = e.y + 2;
|
||
const y2 = e.y + e.h - 2;
|
||
|
||
// Проверяем, находимся ли мы на лестнице
|
||
const cx = e.x + e.w / 2;
|
||
const cy = e.y + e.h / 2;
|
||
const gx = Math.floor(cx / TILE);
|
||
const gy = Math.floor(cy / TILE);
|
||
const b = getBlock(gx, gy);
|
||
const onLadder = b && BLOCKS[b.t] && BLOCKS[b.t].climbable;
|
||
|
||
if (e.vx > 0) {
|
||
const gx = Math.floor((e.x + e.w) / TILE);
|
||
const gyA = Math.floor(y1 / TILE);
|
||
const gyB = Math.floor(y2 / TILE);
|
||
const solidA = isSolid(gx, gyA);
|
||
const solidB = isSolid(gx, gyB);
|
||
|
||
if (solidA || solidB) {
|
||
e.x = gx * TILE - e.w;
|
||
e.vx = 0;
|
||
}
|
||
} else if (e.vx < 0) {
|
||
const gx = Math.floor(e.x / TILE);
|
||
const gyA = Math.floor(y1 / TILE);
|
||
const gyB = Math.floor(y2 / TILE);
|
||
const solidA = isSolid(gx, gyA);
|
||
const solidB = isSolid(gx, gyB);
|
||
|
||
if (solidA || solidB) {
|
||
e.x = (gx + 1) * TILE;
|
||
e.vx = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
export { resolveY, resolveX }; |