fix: restore walkthrough collisions and spawn controls

This commit is contained in:
Aymeric Rabot
2026-06-07 23:58:49 -04:00
parent be0f491bbd
commit 6b8dc33b62
9 changed files with 552 additions and 141 deletions
+61 -30
View File
@@ -1,48 +1,79 @@
import type { FloorplanGeometry } from '@pascal-app/core'
import type { FloorplanGeometry, FloorplanPoint, GeometryContext } from '@pascal-app/core'
import type { SpawnNode } from './schema'
const SPAWN_COLOR = '#818cf8'
const ROTATE_ARROW_CORNER_OFFSET = 0.22
/**
* 2D floor-plan marker for a spawn point. A small filled circle at the
* spawn's position, with a triangular arrow indicating the facing
* direction (rotation around Y, looking down at the X-Z plane).
*
* Color matches the 3D renderer's `SPAWN_COLOR = '#22c55e'` so the user
* Color matches the 3D renderer's indigo spawn material so the user
* sees the same visual identity in both views.
*
* Coordinates are level-local meters; rotation is radians.
*/
export function buildSpawnFloorplan(node: SpawnNode): FloorplanGeometry {
export function buildSpawnFloorplan(node: SpawnNode, ctx: GeometryContext): FloorplanGeometry {
const [px, , pz] = node.position
const ry = node.rotation
const isSelected = ctx.viewState?.selected ?? false
const children: FloorplanGeometry[] = [
{
kind: 'group',
transform: { translate: [px, pz], rotate: ry },
children: [
// Direction-pointing triangle, base centered at origin, tip in -Z
// (forward). Matches the 3D arrow's orientation.
{
kind: 'polygon',
points: [
[0, -0.28],
[-0.18, 0.12],
[0.18, 0.12],
],
fill: SPAWN_COLOR,
opacity: 0.85,
},
// Spawn body marker — circle outline so the spawn is legible at
// small zoom levels where the triangle would shrink past visibility.
{
kind: 'circle',
cx: 0,
cy: 0,
r: 0.34,
stroke: SPAWN_COLOR,
strokeWidth: 0.025,
fill: SPAWN_COLOR,
opacity: 0.18,
},
],
},
]
if (isSelected) {
const cornerLocalX = 0.34 + ROTATE_ARROW_CORNER_OFFSET
const cornerLocalZ = 0.34 + ROTATE_ARROW_CORNER_OFFSET
const [cornerX, cornerZ] = rotatePlanVector(cornerLocalX, cornerLocalZ, ry)
const [radialX, radialZ] = rotatePlanVector(1, 1, ry)
children.push({
kind: 'rotate-arrow',
point: [px + cornerX, pz + cornerZ],
angle: Math.atan2(radialZ, radialX),
affordance: 'spawn-rotate',
pivot: [px, pz],
})
}
return {
kind: 'group',
transform: { translate: [px, pz], rotate: ry },
children: [
// Direction-pointing triangle, base centered at origin, tip in -Z
// (forward). Matches the 3D arrow's orientation.
{
kind: 'polygon',
points: [
[0, -0.28],
[-0.18, 0.12],
[0.18, 0.12],
],
fill: '#22c55e',
opacity: 0.85,
},
// Spawn body marker — circle outline so the spawn is legible at
// small zoom levels where the triangle would shrink past visibility.
{
kind: 'circle',
cx: 0,
cy: 0,
r: 0.34,
stroke: '#22c55e',
strokeWidth: 0.025,
fill: '#22c55e',
opacity: 0.18,
},
],
children,
}
}
function rotatePlanVector(x: number, y: number, rotation: number): FloorplanPoint {
const c = Math.cos(rotation)
const s = Math.sin(rotation)
return [x * c - y * s, x * s + y * c]
}