Files
ToastconcernandClaude Opus 5.5 e9d670b755 Invisible walls: placed in Studio, and Meta's converted; Planet removed; submenu safe triangle
- World > Add > Invisible Wall: a 2 x 2.5 m box (Object role) standing on the floor across the view. Frame Home
  never draws it; it stops you and is never stood on.
- Meta's invisible walls (a solid collider with nothing drawn, 2 m or taller: Cascadia's, Space Station's, Desert
  Terrace's, Haven's) load as invisible walls instead of surfaces, so the play space they bound holds.
- Walk grid: a drawn floor's edge exemption no longer applies within a body's radius of a wall, so a wall through a
  drawn floor takes that floor away. tools/walktest/wallcheck: walls at every angle never have walkable area inside.
- New items land on the home's own surfaces when the spot is beyond the walkable area.
- The Planet (World > Add > Planet, Planet Pull) is gone; older files' planet zones still load.
- ImGui menus: a safe triangle from where the pointer was on the item to the whole submenu; crossing other items
  on the way neither opens them nor closes it (resting 0.3 s still does).
- Self-test: invisible wall placed, walked into (with and without the area), through a drawn floor, undone (98/98).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:44:56 -05:00

45 lines
2.5 KiB
C++

// Invisible walls (2 x 2.5 x 0.1 m Object boxes) at the spawn at 0..165 degrees: the walkable area sampled every 2 cm
// round each, and the closest walkable sample to the wall's footprint (XZ). The area may run up to a wall's face, never
// into it: exit 2 when any sample is inside one.
// wallcheck <home> [drawn] drawn: the wall stands on a drawn floor (a Walkable box) too
#include "hsl_scene.h"
#include "walkgrid.h"
#include <cmath>
#include <cstdio>
int main(int argc, char** argv) {
HslScene s; std::string err;
if (!loadHslScene(std::string(argv[1]), s, err)) return 1;
const float* sp = s.world.spawns[0].pos;
const bool drawn = argc > 2; // on a drawn floor (Walkable box) too
float worst = 1e9f;
for (int deg = 0; deg < 180; deg += 15) {
const float a = deg * 3.14159265f / 180, c = std::cos(a), sn = std::sin(a);
HomeWorld w = s.world;
if (drawn) {
WorldCollider f; f.kind = WorldCollider::Box; f.role = WorldCollider::Walkable; f.half[0] = f.half[2] = 1.5f; f.half[1] = 0.02f;
f.world[12] = sp[0]; f.world[13] = sp[1] + 0.02f; f.world[14] = sp[2];
w.colliders.push_back(f);
}
WorldCollider b; b.kind = WorldCollider::Box; b.role = WorldCollider::Object; b.half[0] = 1.0f; b.half[1] = 1.25f; b.half[2] = 0.05f;
const float m[16] = {c, 0, -sn, 0, 0, 1, 0, 0, sn, 0, c, 0, sp[0] + 0.013f, sp[1] + 1.25f, sp[2] + 0.027f, 1}; // off the cell grid
for (int k = 0; k < 16; ++k) b.world[k] = m[k];
w.colliders.push_back(b);
auto g = bakeWalkGrid(s, w, WalkParams{});
float closest = 1e9f;
for (float dz = -1.6f; dz <= 1.6f; dz += 0.02f)
for (float dx = -1.6f; dx <= 1.6f; dx += 0.02f) {
const float x = m[12] + dx, z = m[14] + dz;
if (!g->walkable(x, z, sp[1] + 0.1f)) continue;
// distance to the wall's footprint (a rectangle 2 x 0.1 in its own frame)
const float lx = dx * c - dz * sn, lz = dx * sn + dz * c;
const float ox = std::fabs(lx) - 1.0f, oz = std::fabs(lz) - 0.05f;
const float d = ox > 0 || oz > 0 ? std::hypot(std::max(ox, 0.0f), std::max(oz, 0.0f)) : std::max(ox, oz);
closest = std::min(closest, d);
}
std::printf("%3d deg: closest walkable %.3f m from the wall\n", deg, closest);
worst = std::min(worst, closest);
}
std::printf("worst %.3f m\n", worst);
return worst < 0 ? 2 : 0;
}