# Procedural Tile System (Sample)

The **Procedural Tile System** keeps a ring of world tiles centered on the player (or any transform). As the center moves, tiles outside the ring despawn while new tiles in front spawn in. This is designed to pair cleanly with **Grid Cells** mode in the `NavMeshBakerService`, but it also works with **Continuous AABB** (the service falls back to “around target” bakes when needed).

At runtime the manager:

* Converts the center’s world position to a **grid cell**.
* Maintains a configurable number of **rings** around that cell (e.g., rings=1 → 3×3; rings=2 → 5×5).
* Spawns tiles by asking a **provider** which prefab to use per cell.
* Optionally **pools** tiles for smooth, GC-friendly streaming.
* (Optional) Notifies the **NavMeshBakerService** to enqueue bakes after tile changes.

***

### When to Use

* Open worlds or endless runners built from repeated “tile” prefabs.
* Procgen/streaming maps where you want consistent tile alignment with runtime NavMesh baking.
* Any scene where you want a simple, deterministic grid centered on the player.

***

### Setup

1. **Add the Manager**
   * Create an empty GameObject (e.g., `ProceduralTileManager`) and add **`ProceduralTileManager`**.
   * Assign **Center Target** (player or camera). If unassigned, Main Camera is used by default.
   * Optionally assign **Tiles Parent** (a container transform for spawned tiles).
2. **Pick Tile Size & Rings**
   * Set **Tile Size XZ** to match your tile prefab’s footprint (e.g., 16×16 or 32×32).
   * Set **Rings** (1 = 3×3, 2 = 5×5, etc.). Larger rings mean more tiles alive at once.
3. **Provide Prefabs**
   * Implement **`IProceduralTileProvider`** (below) or assign a sample provider scriptable (e.g., a noise/biome-based provider).
   * Drag that asset into **Provider Asset**.
4. **NavMesh Integration (recommended)**
   * Enable **Enqueue Bake After Changes** so the **NavMeshBakerService** refreshes local cells when tiles change.
   * In your **`NavMeshBakeProfile`**, set **Bake Mode = Grid Cells** and **Cell Size XZ** equal to your **Tile Size XZ** for perfect alignment.
5. **Play**
   * Move the player — tiles stream in front, old tiles despawn behind, and the service bakes navmesh for new cells.

***

### Inspector Reference

**References**

* **Center Target (Transform)**: Usually your player or camera.
* **Tiles Parent (Transform)**: Optional parent for spawned tiles; defaults to the manager object.

**Tiling**

* **Tile Size XZ (Vector2)**: World footprint per tile in meters.
* **Rings (int)**: 0=current cell only; 1=3×3; 2=5×5; etc.
* **Y Height (float)**: World Y position to place tile centers.

**Spawning**

* **Poll Rate Seconds (float)**: How often the manager checks for cell changes.
* **Hysteresis (0..0.9)**: “Stickiness” to avoid thrashing near cell boundaries.
* **Use Pooling (bool)**: Reuse despawned tile instances per prefab.

**Tile Provider**

* **Provider Asset (ScriptableObject)**: Must implement `IProceduralTileProvider`.

**NavMesh Integration**

* **Enqueue Bake After Changes (bool)**: If enabled, calls `NavMeshBakerService.EnqueueCurrentGridCells()` after tiles spawn/despawn.

***

### Provider Interface

```csharp
public interface IProceduralTileProvider
{
    GameObject GetPrefabForCell(Vector2Int cell);
}
```

* Return a prefab (tile) for the given cell coordinate.
* Return `null` to spawn an empty container tile (useful for testing layout).
* You can encode biomes, noise, or “seeded” content using the `cell` index.

#### Example Provider (Sample)

```csharp
using UnityEngine;

[CreateAssetMenu(menuName = "Runtime Navmesh Baker/Simple Noise Tile Provider")]
public class SimpleNoiseTileProvider : ScriptableObject, MegaCrush.RuntimeNavmeshBaker.IProceduralTileProvider
{
    [SerializeField] private GameObject grassPrefab;
    [SerializeField] private GameObject rockPrefab;
    [SerializeField] private float threshold = 0.5f;
    [SerializeField] private float scale = 0.1f;

    public GameObject GetPrefabForCell(Vector2Int cell)
    {
        float n = Mathf.PerlinNoise(cell.x * scale, cell.y * scale);
        return n < threshold ? grassPrefab : rockPrefab;
    }
}
```

***

### Object Pooling

* When **Use Pooling** is enabled, the manager keeps a **stack per prefab**.
* Despawned tiles are **deactivated** and pushed back to the pool; new tiles pop from the pool if available.
* In Editor, despawns use `DestroyImmediate` outside Play Mode; in Play Mode, `Destroy`.

***

### How It Works (Runtime Flow)

1. Converts the **Center Target** position to a **grid cell** using `Tile Size XZ` and **Hysteresis**.
2. Builds the set of **wanted cells** for the configured **Rings**.
3. **Despawns** any active tiles not in the wanted set; **spawns** any missing wanted tiles.
4. If **Enqueue Bake After Changes** is enabled, calls the baker service to bake the current ring.
5. Repeats every **Poll Rate Seconds**.

***

### Public API

* **`ForceRefreshNow()`**\
  Rebuilds the tile ring immediately (ignores poll cadence and hysteresis).
* **`SetCenterTarget(Transform t)`**\
  Changes the follow target at runtime (useful for switching player/camera).

***

### Best Practices

* **Match Sizes**: In Grid Cells mode, set **Profile.Cell Size XZ** exactly equal to **Tile Size XZ** to keep baking aligned to tiles.
* **Keep Rings Low**: Start with `rings=1` (3×3) and increase only if you see visible pop-in.
* **Balance Polling**: `pollRateSeconds` of 0.1–0.25s is responsive without being noisy.
* **Use Layers**: Put tile geometry on layers included in the **Profile Layer Mask** so the baker collects the right sources.
* **Surface Placement**: If your tiles contain geometry that should be baked using **CollectObjects.Children**, put a `DynamicNavMeshSurface` on the tile root prefab (or a higher parent) as appropriate for your project.

***

### Troubleshooting

* **“Nothing spawns”**\
  Ensure **Provider Asset** is assigned and returns a prefab for the requested cells.
* **“Agents can’t find navmesh”**\
  Verify **NavMeshBakerService** is in the scene, a **NavMeshBakeProfile** is assigned, and **Enqueue Bake After Changes** is enabled (or manually enqueue bakes).
* **“Tiles flicker near boundaries”**\
  Increase **Hysteresis** (e.g., 0.2–0.3) or lower **Poll Rate Seconds**.
* **“CPU spikes during moves”**\
  Reduce **Rings**, use **Pooling**, and lower **Max Concurrent Bakes** in the profile.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://megacrush.gitbook.io/megacrush-unity-assets/runtime-navmesh-baker/runtime-navmesh-baker-user-manual/extras/procedural-tile-system-sample.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
