tower-sell #12
2 changed files with 29 additions and 2 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
// Assets/_Project/Scripts/Gameplay/TowerInstance.cs
|
// Assets/_Project/Scripts/Gameplay/TowerInstance.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using TD.Core;
|
using TD.Core;
|
||||||
|
|
@ -511,11 +512,20 @@ namespace TD.Gameplay
|
||||||
? resolvedDefinition.FootprintSize
|
? resolvedDefinition.FootprintSize
|
||||||
: new Vector2Int(2, 2);
|
: new Vector2Int(2, 2);
|
||||||
|
|
||||||
|
// Collect the footprint, then stamp walkability as a BATCH so a single
|
||||||
|
// OnWalkabilityChanged fires for the whole footprint. Per-tile SetWalkable fires
|
||||||
|
// that event once PER TILE — on despawn (sell) that meant up to 4 full enemy A*
|
||||||
|
// re-paths for a 2×2 tower in one frame, which was the sell hitch. Placement
|
||||||
|
// batches for the same reason (TowerPlacementManager.StampWalkable). Occupancy
|
||||||
|
// doesn't fire walkability events, so it stays per-tile.
|
||||||
|
var footprint = new List<Vector2Int>(footprintSize.x * footprintSize.y);
|
||||||
foreach (var tile in GridCoordinates.GetFootprintTiles(anchorTile.Value, footprintSize))
|
foreach (var tile in GridCoordinates.GetFootprintTiles(anchorTile.Value, footprintSize))
|
||||||
{
|
{
|
||||||
loader.SetWalkable(tile, walkable);
|
footprint.Add(tile);
|
||||||
loader.SetOccupied(tile, occupied);
|
loader.SetOccupied(tile, occupied);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loader.SetWalkableBatch(footprint, walkable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reused per-instance across color updates to avoid per-call GC allocation.
|
// Reused per-instance across color updates to avoid per-call GC allocation.
|
||||||
|
|
|
||||||
|
|
@ -365,10 +365,27 @@ namespace TD.Gameplay
|
||||||
PlaySellEffectRpc(worldPos);
|
PlaySellEffectRpc(worldPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One-time guard so a missing spawner warns once per peer instead of on every sale.
|
||||||
|
private static bool s_warnedNoSellSpawner;
|
||||||
|
|
||||||
[Rpc(SendTo.Everyone)]
|
[Rpc(SendTo.Everyone)]
|
||||||
private void PlaySellEffectRpc(Vector3 worldPos)
|
private void PlaySellEffectRpc(Vector3 worldPos)
|
||||||
{
|
{
|
||||||
SellEffectSpawner.Instance?.Play(worldPos);
|
var spawner = SellEffectSpawner.Instance;
|
||||||
|
if (spawner == null)
|
||||||
|
{
|
||||||
|
if (!s_warnedNoSellSpawner)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[TowerPlacementManager] A tower was sold, but there is no " +
|
||||||
|
"SellEffectSpawner in the scene — no coin VFX or sell sound " +
|
||||||
|
"will play. Add a SellEffectSpawner GameObject to each Match " +
|
||||||
|
"scene (assign its Sell Sound clip; the coin burst works even " +
|
||||||
|
"with no VFX prefab).");
|
||||||
|
s_warnedNoSellSpawner = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spawner.Play(worldPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- Server-side commit hooks called by Builder ------------------
|
// ----- Server-side commit hooks called by Builder ------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue