100 lines
3.8 KiB
JavaScript
100 lines
3.8 KiB
JavaScript
"use strict";
|
|
|
|
const StairCollider = (function(){
|
|
|
|
const StairCollider = function(hollow_bond, model){
|
|
|
|
const self = this;
|
|
this.model = model;
|
|
|
|
const bounds = model.get_world_bounds();
|
|
|
|
const is_x = (model.wall === "north" || model.wall === "south");
|
|
const length = is_x ? model.width : model.depth;
|
|
const landing_size = hollow_bond.stairs_landing_size || 1.0;
|
|
const flight_len = Math.max(1.0, length - (landing_size * 2));
|
|
const rise = hollow_bond.room_height;
|
|
const dir = model.direction;
|
|
|
|
this.bounds = {
|
|
min_x: bounds.x,
|
|
max_x: bounds.x + bounds.width,
|
|
min_y: bounds.y,
|
|
max_y: bounds.y + rise,
|
|
min_z: bounds.z,
|
|
max_z: bounds.z + bounds.depth
|
|
};
|
|
|
|
this.resolve_player = (position, controls, player_radius = 0.22) => {
|
|
const eye_height = controls.current_height || 1.75;
|
|
const px = position.x;
|
|
const py = position.y - eye_height;
|
|
const pz = position.z;
|
|
|
|
// Filtro general AABB
|
|
if(
|
|
px < self.bounds.min_x - player_radius || px > self.bounds.max_x + player_radius ||
|
|
pz < self.bounds.min_z - player_radius || pz > self.bounds.max_z + player_radius ||
|
|
py < self.bounds.min_y - 0.4 || py > self.bounds.max_y + 1.2
|
|
){
|
|
return;
|
|
}
|
|
|
|
// Progresión longitudinal a lo largo de la escalera (0 a 1)
|
|
const coord = is_x ? (px - self.bounds.min_x) : (pz - self.bounds.min_z);
|
|
|
|
let expected_y = self.bounds.min_y;
|
|
|
|
if(dir === 1){
|
|
if(coord <= landing_size){
|
|
expected_y = self.bounds.min_y;
|
|
} else if(coord >= (length - landing_size)){
|
|
expected_y = self.bounds.max_y;
|
|
} else {
|
|
const t = (coord - landing_size) / flight_len;
|
|
expected_y = self.bounds.min_y + t * rise;
|
|
}
|
|
} else {
|
|
if(coord <= landing_size){
|
|
expected_y = self.bounds.max_y;
|
|
} else if(coord >= (length - landing_size)){
|
|
expected_y = self.bounds.min_y;
|
|
} else {
|
|
const t = (length - landing_size - coord) / flight_len;
|
|
expected_y = self.bounds.min_y + t * rise;
|
|
}
|
|
}
|
|
|
|
// 1. PISADA (Subida suave de rampa)
|
|
const dist_to_stair = py - expected_y;
|
|
if(controls.velocity_y <= 0 && dist_to_stair >= -0.25 && dist_to_stair <= 0.25){
|
|
position.y = expected_y + eye_height;
|
|
controls.velocity_y = 0;
|
|
controls.is_grounded = true;
|
|
}
|
|
|
|
// 2. COLISIÓN CONTRA BARANDILLA INTERIOR
|
|
// Si el jugador no salta por encima de 1.0m, se le bloquea la salida lateral hacia el hueco
|
|
if(py < (expected_y + 1.0)){
|
|
const r = player_radius;
|
|
switch(model.wall){
|
|
case "north": // Hueco hacia +Z
|
|
if(position.z > self.bounds.max_z - r) position.z = self.bounds.max_z - r;
|
|
break;
|
|
case "south": // Hueco hacia -Z
|
|
if(position.z < self.bounds.min_z + r) position.z = self.bounds.min_z + r;
|
|
break;
|
|
case "west": // Hueco hacia +X
|
|
if(position.x > self.bounds.max_x - r) position.x = self.bounds.max_x - r;
|
|
break;
|
|
case "east": // Hueco hacia -X
|
|
if(position.x < self.bounds.min_x + r) position.x = self.bounds.min_x + r;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
};
|
|
|
|
return StairCollider;
|
|
})(); |