HUD and Height Changes

This commit is contained in:
2026-06-07 22:29:25 -07:00
parent 4ebaba9933
commit 1ed2aa46c5
41 changed files with 24787 additions and 766 deletions
@@ -4,6 +4,7 @@ using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.NetCode;
using Unity.Physics;
using Unity.Transforms;
namespace ProjectM.Server
@@ -61,6 +62,11 @@ namespace ProjectM.Server
var serverTick = SystemAPI.GetSingleton<NetworkTime>().ServerTick;
uint now = serverTick.TickIndexForValidTick;
var ecb = new EntityCommandBuffer(Allocator.Temp);
bool havePhysics = SystemAPI.TryGetSingleton<PhysicsWorldSingleton>(out var physics);
uint envMask = SystemAPI.TryGetSingleton<WorldCollisionConfig>(out var worldCol) ? worldCol.EnvironmentMask : 0u;
var envFilter = new CollisionFilter { BelongsTo = ~0u, CollidesWith = envMask, GroupIndex = 0 };
bool sweep = havePhysics && envMask != 0u;
const float SweepRadius = 0.5f; // collide-and-slide sphere radius for Husk movement
foreach (var (xform, stats, cooldown, knockback, windup) in
SystemAPI.Query<RefRW<LocalTransform>, RefRO<EnemyStats>, RefRW<EnemyAttackCooldown>,
@@ -78,6 +84,8 @@ namespace ProjectM.Server
{
float3 kpos = pos + new float3(kb.Dir.x, 0f, kb.Dir.y) * (kb.Speed * dt);
kpos.y = pos.y;
if (sweep)
kpos = SweptMove(in physics, pos, kpos, SweepRadius, envFilter);
xform.ValueRW.Position = kpos;
windup.ValueRW.WindUpUntilTick = 0; // a recoiling Husk does not wind up
continue; // recoiling: skip seek + strike this tick
@@ -106,6 +114,8 @@ namespace ProjectM.Server
float3 vel = EnemyAIMath.SeekVelocity(pos, targetPos, stats.ValueRO.MoveSpeed, stopDistance);
float3 newPos = pos + vel * dt;
newPos.y = pos.y; // hold the movement plane
if (sweep)
newPos = SweptMove(in physics, pos, newPos, SweepRadius, envFilter);
xform.ValueRW.Position = newPos;
// Face the target (planar) for presentation.
@@ -166,5 +176,38 @@ namespace ProjectM.Server
playerEntities.Dispose();
playerPositions.Dispose();
}
// Swept collide-and-slide for server-authoritative Husk movement: sphere-cast the intended step against
// the static environment (boundary ring + landmarks) and stop at / glance along the first wall hit. Closest-
// hit SphereCast is non-generic -> Burst-safe (CLAUDE.md generic-collector hazard avoided). Y is held flat.
static float3 SweptMove(in PhysicsWorldSingleton physics, float3 from, float3 to, float radius, CollisionFilter filter)
{
float3 delta = to - from;
delta.y = 0f;
float dist = math.length(delta);
if (dist < 1e-5f)
return to;
float3 dir = delta / dist;
const float skin = 0.05f;
var cw = physics.CollisionWorld;
if (!cw.SphereCast(from, radius, dir, dist, out var hit, filter))
return to;
float allowed = math.max(0f, hit.Fraction * dist - skin);
float3 stop = from + dir * allowed;
stop.y = from.y;
// Slide the unused motion along the wall, then sweep the slide so we don't tunnel a second wall.
float3 slide = EnemyAIMath.SlideVelocity(to - stop, hit.SurfaceNormal);
float slideDist = math.length(slide);
if (slideDist < 1e-5f)
return stop;
float3 sdir = slide / slideDist;
float3 result = cw.SphereCast(stop, radius, sdir, slideDist, out var hit2, filter)
? stop + sdir * math.max(0f, hit2.Fraction * slideDist - skin)
: stop + slide;
result.y = from.y;
return result;
}
}
}
@@ -9,7 +9,8 @@
"Unity.Mathematics",
"Unity.Burst",
"Unity.NetCode",
"Unity.Networking.Transport"
"Unity.Networking.Transport",
"Unity.Physics"
],
"includePlatforms": [],
"excludePlatforms": [],