From 1afc78d64f0fa14184c885af5b56ba68bd519330 Mon Sep 17 00:00:00 2001 From: Matt F Date: Thu, 25 Jun 2026 11:36:31 -0700 Subject: [PATCH] Code fix to make sure towers are flush with the ground This may need to be changed later if we have any towers that have visuals that go underneath the ground. Right now that won't work, but we also don't have anything like that. --- .../Scripts/Gameplay/TowerPlacementManager.cs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs index 29cd90e..7c4662d 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs @@ -601,9 +601,9 @@ namespace TD.Gameplay } Vector3 spawnPos = GridCoordinates.GetFootprintCenterWorld(anchor, def.FootprintSize); - // Towers sit on the buildable plane (Y=0); raise slightly so the mesh base - // sits flush rather than half-clipped. A cube of scale 1 needs +0.5 on Y. - spawnPos.y = 0.5f; + // Place on the buildable plane (Y=0); SeatOnGround below corrects the final Y + // from the mesh bounds so the tower rests flush regardless of its pivot. + spawnPos.y = 0f; var go = Instantiate(def.TowerPrefab, spawnPos, Quaternion.identity); var instance = go.GetComponent(); @@ -626,9 +626,32 @@ namespace TD.Gameplay Destroy(go); return; } + + // Seat the tower flush on the ground from its mesh bounds — BEFORE Spawn so the + // corrected transform is captured in the spawn sync. Handles any pivot. + SeatOnGround(go, groundY: 0f); + netObj.Spawn(destroyWithScene: true); } + /// + /// Shifts vertically so the lowest point of its combined + /// renderer bounds rests at . Lets towers be authored with + /// any mesh pivot (center, base, etc.) and still sit flush on the ground — no + /// per-prefab Y tweaking. No-op if the prefab has no renderers. + /// + private static void SeatOnGround(GameObject go, float groundY) + { + var renderers = go.GetComponentsInChildren(); + if (renderers.Length == 0) return; + + Bounds b = renderers[0].bounds; + for (int i = 1; i < renderers.Length; i++) + b.Encapsulate(renderers[i].bounds); + + go.transform.position += Vector3.up * (groundY - b.min.y); + } + // ----- Utility ---------------------------------------------------- private static bool TryGetDefinition(int typeId, out TowerDefinition def)