UnityTowerDefense/Assets/_Project/Levels/LevelData.cs

144 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using UnityEngine;
using TD.Core;
namespace TD.Levels
{
/// <summary>
/// Baked level data. Authored in a Unity scene via volume MonoBehaviours; produced by
/// <see cref="LevelAuthoring.BakeLevelData"/>; consumed at runtime as the canonical map
/// definition.
/// </summary>
/// <remarks>
/// LevelData is the canonical map identity. The lobby browses LevelData assets; loading a
/// map = read LevelData → load the referenced scene at <see cref="ScenePath"/>.
///
/// All flat grid arrays use row-major indexing: <c>grid[y * GridSize.x + x]</c>.
/// Origin-relative: <see cref="GridOriginTile"/> is the world-tile coordinate that grid index
/// (0,0) corresponds to. Convert world-tile to grid-index via
/// <c>worldTile - GridOriginTile</c>.
/// </remarks>
[CreateAssetMenu(fileName = "LevelData", menuName = "TD/Level Data", order = 1)]
public class LevelData : ScriptableObject
{
// -------------------------------------------------------------------
// Lobby-facing metadata.
// -------------------------------------------------------------------
[Header("Map Metadata")]
public string MapName;
public int PlayerCount;
public string MapDescription;
public string Author;
[Tooltip("Auto-generated by bake. Use the Refresh Thumbnail button on LevelAuthoring to " +
"re-render without doing a full bake.")]
public Sprite MapThumbnail;
[Tooltip("Path to the scene this LevelData was baked from. Auto-populated by bake.")]
public string ScenePath;
// -------------------------------------------------------------------
// Bake metadata (used for dirty-detection and diagnostic display).
// -------------------------------------------------------------------
[Header("Bake Metadata")]
[Tooltip("Hash of the authoring inputs at last bake. Compared at Play-mode entry to detect " +
"unbaked changes. Captures volumes + LevelAuthoring metadata; does NOT capture " +
"visual scene content.")]
public string AuthoringHash;
[Tooltip("ISO 8601 UTC timestamp of the last successful bake.")]
public string LastBakeTimestamp;
public BakeOutcome LastBakeOutcome;
public int LastBakeWarningCount;
// -------------------------------------------------------------------
// Grid metadata.
// -------------------------------------------------------------------
[Header("Grid")]
[Tooltip("World-tile coordinate that grid index (0,0) corresponds to. Origin-relative " +
"addressing: worldTile - GridOriginTile gives the index into the flat arrays.")]
public Vector2Int GridOriginTile;
[Tooltip("Width × height of the grid in tiles.")]
public Vector2Int GridSize;
// -------------------------------------------------------------------
// Per-tile flat arrays. All indexed as grid[y * GridSize.x + x].
// -------------------------------------------------------------------
[Tooltip("Per-tile placement state: Outside / Buildable / Restricted. Length = GridSize.x * GridSize.y.")]
public PlacementState[] PlacementGrid;
[Tooltip("Per-tile initial walkability (does NOT account for towers — they stamp footprints " +
"at runtime). Length = GridSize.x * GridSize.y.")]
public bool[] WalkabilityGrid;
[Tooltip("Per-tile owning player slot. PlayerSlot.None for tiles not in any player zone. " +
"Length = GridSize.x * GridSize.y.")]
public PlayerSlot[] OwnerGrid;
// -------------------------------------------------------------------
// Per-zone and per-goal structures (populated by bake from volume data).
// -------------------------------------------------------------------
[Tooltip("One entry per declared player zone, sorted by Owner.")]
public PlayerZoneData[] PlayerZones;
[Tooltip("One entry per GoalVolume, sorted by min tile coordinate.")]
public GoalData[] Goals;
}
/// <summary>
/// Per-zone baked data. The runtime can use this to enumerate a player's spawners and leak
/// exits without scanning the full grid.
/// </summary>
[Serializable]
public class PlayerZoneData
{
public PlayerSlot Owner;
[Tooltip("Spawners in this zone, sorted by SpawnerIdInZone.")]
public SpawnerData[] Spawners;
[Tooltip("Leak exits OUT OF this zone, sorted by Target enum value. Empty for the final " +
"defender (whose zone is goal-adjacent and has no leak exit).")]
public LeakExitData[] LeakExits;
}
[Serializable]
public class SpawnerData
{
public int SpawnerIdInZone;
[Tooltip("Tile coordinate of the spawner's center (its volume's bounds center, projected to grid).")]
public Vector2Int TilePosition;
[Tooltip("Full tile coverage of the spawner volume.")]
public Vector2Int[] TileArea;
public Direction Facing;
}
[Serializable]
public class LeakExitData
{
public PlayerSlot Target;
[Tooltip("Full tile coverage of the leak exit volume.")]
public Vector2Int[] TileArea;
[Tooltip("Weight normalized so all leak exits sharing the same source zone sum to 1.0.")]
public float NormalizedWeight;
}
[Serializable]
public class GoalData
{
[Tooltip("Full tile coverage of the goal volume.")]
public Vector2Int[] TileArea;
}
}