Release Healer Man 0.1.29
This commit is contained in:
1 parent
8c9809d3e0
commit
544c1bee91
120 files changed
+4363
-1036
No files matched your search
+47
-7
@@ -1,16 +1,56 @@
|
||||
import type { ArenaStageManifest } from "./arenaTypes";
|
||||
import { Raycaster, Vector3, type Object3D } from "three";
|
||||
import { clampCameraPitch, DEFAULT_CAMERA_PITCH } from "./inputMath";
|
||||
import type { ArenaStageManifest, Vec3Tuple } from "./arenaTypes";
|
||||
|
||||
export const ARENA_CAMERA_DISTANCE = 5.8;
|
||||
export const ARENA_CAMERA_FOCUS_HEIGHT = 1.35;
|
||||
|
||||
export interface ArenaCameraPose {
|
||||
readonly position: [number, number, number];
|
||||
readonly target: [number, number, number];
|
||||
}
|
||||
|
||||
export function arenaCameraPose(stage: ArenaStageManifest, team: 0 | 1): ArenaCameraPose {
|
||||
const centerX = (stage.bounds.min[0] + stage.bounds.max[0]) / 2;
|
||||
const centerZ = (stage.bounds.min[2] + stage.bounds.max[2]) / 2;
|
||||
const floorY = Math.min(...stage.teamSpawns.map((spawn) => spawn[1]));
|
||||
export function arenaSpawnYaw(stage: ArenaStageManifest, team: 0 | 1): number {
|
||||
const from = stage.teamSpawns[team];
|
||||
const to = stage.preparationGates[team];
|
||||
return Math.atan2(to[0] - from[0], to[2] - from[2]);
|
||||
}
|
||||
|
||||
/** Follow the controlled character at their elevation, including underground arenas. */
|
||||
export function arenaCameraPose(
|
||||
footPosition: Vec3Tuple,
|
||||
yaw: number,
|
||||
pitch = DEFAULT_CAMERA_PITCH,
|
||||
distance = ARENA_CAMERA_DISTANCE,
|
||||
): ArenaCameraPose {
|
||||
const safeYaw = Number.isFinite(yaw) ? yaw : 0;
|
||||
const safePitch = clampCameraPitch(pitch);
|
||||
const radius = Number.isFinite(distance) ? Math.max(0.25, Math.min(12, distance)) : ARENA_CAMERA_DISTANCE;
|
||||
const target: [number, number, number] = [footPosition[0], footPosition[1] + ARENA_CAMERA_FOCUS_HEIGHT, footPosition[2]];
|
||||
return {
|
||||
position: [...stage.spectatorPositions[team]],
|
||||
target: [centerX, floorY + 1.2, centerZ],
|
||||
target,
|
||||
position: [
|
||||
target[0] - Math.sin(safeYaw) * Math.cos(safePitch) * radius,
|
||||
target[1] + Math.sin(safePitch) * radius,
|
||||
target[2] - Math.cos(safeYaw) * Math.cos(safePitch) * radius,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/** Probe both directions so one-sided imported walls also obstruct the camera. */
|
||||
export function arenaCameraClearDistance(target: Vector3, desired: Vector3, environment: Object3D, ray: Raycaster): number {
|
||||
const length = target.distanceTo(desired);
|
||||
if (length < 0.001) return 0;
|
||||
const direction = desired.clone().sub(target).normalize();
|
||||
let distance = length;
|
||||
for (const offset of [[0, 0, 0], [0.18, 0, 0], [-0.18, 0, 0], [0, 0.18, 0], [0, -0.18, 0]]) {
|
||||
const origin = target.clone().add(new Vector3(...offset));
|
||||
ray.near = 0.03;
|
||||
ray.far = length;
|
||||
ray.set(origin, direction);
|
||||
for (const hit of ray.intersectObject(environment, true)) distance = Math.min(distance, hit.distance - 0.2);
|
||||
ray.set(origin.addScaledVector(direction, length), direction.clone().negate());
|
||||
for (const hit of ray.intersectObject(environment, true)) distance = Math.min(distance, length - hit.distance - 0.2);
|
||||
}
|
||||
return Math.max(0.15, distance);
|
||||
}
|
||||
Reference in new issue
Block a user