2025-09-10 12:35:22 +02:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
|
using UnityEngine.Serialization;
|
2025-09-16 15:02:50 +02:00
|
|
|
|
using Pooling;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Minigames.DivingForPictures
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Spawns and manages trench wall tiles for the endless descender minigame.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class TrenchTileSpawner : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
[Header("Tile Prefabs")]
|
|
|
|
|
|
[Tooltip("List of possible trench tile prefabs.")]
|
2025-09-16 15:02:50 +02:00
|
|
|
|
[SerializeField] private List<GameObject> tilePrefabs;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
|
|
|
|
|
[Header("Tile Settings")]
|
2025-09-16 15:02:50 +02:00
|
|
|
|
[SerializeField] private int initialTileCount = 3;
|
|
|
|
|
|
[SerializeField] private float tileSpawnBuffer = 1f;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
|
|
|
|
|
[Header("Movement Settings")]
|
2025-09-16 15:02:50 +02:00
|
|
|
|
[SerializeField] private float moveSpeed = 3f;
|
|
|
|
|
|
[SerializeField] private float speedUpFactor = 0.2f;
|
|
|
|
|
|
[SerializeField] private float speedUpInterval = 10f;
|
|
|
|
|
|
[SerializeField] private float maxMoveSpeed = 12f;
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
|
|
|
|
|
[Header("Object Pooling")]
|
2025-09-16 15:02:50 +02:00
|
|
|
|
[SerializeField] private bool useObjectPooling = true;
|
|
|
|
|
|
[SerializeField] private int maxPerPrefabPoolSize = 2;
|
|
|
|
|
|
[SerializeField] private int totalMaxPoolSize = 10;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
[Header("Events")]
|
|
|
|
|
|
[FormerlySerializedAs("OnTileSpawned")]
|
2025-09-10 12:35:22 +02:00
|
|
|
|
public UnityEvent<GameObject> onTileSpawned;
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
[FormerlySerializedAs("OnTileDestroyed")]
|
|
|
|
|
|
public UnityEvent<GameObject> onTileDestroyed;
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
// Private fields
|
|
|
|
|
|
private readonly Dictionary<GameObject, float> _tileHeights = new Dictionary<GameObject, float>();
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private readonly List<GameObject> _activeTiles = new List<GameObject>();
|
|
|
|
|
|
private readonly Dictionary<int, int> _tileLastUsed = new Dictionary<int, int>();
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private int _spawnCounter;
|
|
|
|
|
|
private float _speedUpTimer;
|
|
|
|
|
|
private Camera _mainCamera;
|
|
|
|
|
|
private float _screenBottom;
|
|
|
|
|
|
private float _screenTop;
|
2025-09-16 12:23:25 +02:00
|
|
|
|
private TrenchTilePool _tilePool;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
private const float TileSpawnZ = -1f;
|
|
|
|
|
|
private const float DefaultTileHeight = 5f;
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
private void Awake()
|
2025-09-10 12:35:22 +02:00
|
|
|
|
{
|
|
|
|
|
|
_mainCamera = Camera.main;
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
|
|
|
|
|
// Calculate tile heights for each prefab
|
2025-09-16 15:02:50 +02:00
|
|
|
|
CalculateTileHeights();
|
|
|
|
|
|
|
|
|
|
|
|
// Ensure all prefabs have Tile components
|
|
|
|
|
|
ValidateTilePrefabs();
|
|
|
|
|
|
|
|
|
|
|
|
if (useObjectPooling)
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeObjectPool();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate that all prefabs have Tile components
|
|
|
|
|
|
private void ValidateTilePrefabs()
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < tilePrefabs.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tilePrefabs[i] == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// Check if the prefab has a Tile component
|
|
|
|
|
|
if (tilePrefabs[i].GetComponent<Tile>() == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"Prefab {tilePrefabs[i].name} does not have a Tile component. Adding one automatically.");
|
|
|
|
|
|
// Add the Tile component if it doesn't exist
|
|
|
|
|
|
tilePrefabs[i].AddComponent<Tile>();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
CalculateScreenBounds();
|
|
|
|
|
|
SpawnInitialTiles();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
MoveTiles();
|
|
|
|
|
|
HandleTileDestruction();
|
|
|
|
|
|
HandleTileSpawning();
|
|
|
|
|
|
HandleSpeedRamping();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Calculate height values for all tile prefabs
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void CalculateTileHeights()
|
|
|
|
|
|
{
|
2025-09-16 12:23:25 +02:00
|
|
|
|
foreach (var prefab in tilePrefabs)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (prefab == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Null prefab found in tilePrefabs list!");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
Renderer renderer = prefab.GetComponentInChildren<Renderer>();
|
|
|
|
|
|
if (renderer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_tileHeights[prefab] = renderer.bounds.size.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Fallback in case no renderer is found
|
2025-09-16 15:02:50 +02:00
|
|
|
|
_tileHeights[prefab] = DefaultTileHeight;
|
|
|
|
|
|
Debug.LogWarning($"No renderer found in prefab {prefab.name}. Using default height of {DefaultTileHeight}.");
|
2025-09-16 12:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 15:02:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Initialize the object pool system
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void InitializeObjectPool()
|
|
|
|
|
|
{
|
|
|
|
|
|
// Create the tile pool
|
|
|
|
|
|
GameObject poolGO = new GameObject("TrenchTilePool");
|
|
|
|
|
|
poolGO.transform.SetParent(transform);
|
|
|
|
|
|
_tilePool = poolGO.AddComponent<TrenchTilePool>();
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
// Set up the pool configuration
|
|
|
|
|
|
_tilePool.maxPerPrefabPoolSize = maxPerPrefabPoolSize;
|
|
|
|
|
|
_tilePool.totalMaxPoolSize = totalMaxPoolSize;
|
|
|
|
|
|
|
|
|
|
|
|
// Convert the GameObject list to a Tile list
|
|
|
|
|
|
List<Tile> prefabTiles = new List<Tile>(tilePrefabs.Count);
|
|
|
|
|
|
foreach (var prefab in tilePrefabs)
|
2025-09-16 12:23:25 +02:00
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (prefab != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Tile tileComponent = prefab.GetComponent<Tile>();
|
|
|
|
|
|
if (tileComponent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
prefabTiles.Add(tileComponent);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"Prefab {prefab.name} is missing a Tile component!");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 12:23:25 +02:00
|
|
|
|
}
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
|
|
|
|
|
// Initialize the pool with the tile component list
|
|
|
|
|
|
_tilePool.Initialize(prefabTiles);
|
|
|
|
|
|
|
|
|
|
|
|
// Periodically trim the pool to optimize memory usage
|
|
|
|
|
|
InvokeRepeating(nameof(TrimExcessPooledTiles), 10f, 30f);
|
2025-09-16 12:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Spawn the initial set of tiles
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void SpawnInitialTiles()
|
2025-09-16 12:23:25 +02:00
|
|
|
|
{
|
2025-09-10 12:35:22 +02:00
|
|
|
|
for (int i = 0; i < initialTileCount; i++)
|
|
|
|
|
|
{
|
2025-09-16 12:23:25 +02:00
|
|
|
|
float y = _screenBottom;
|
|
|
|
|
|
// Calculate proper Y position based on previous tiles
|
|
|
|
|
|
if (i > 0 && _activeTiles.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObject prevTile = _activeTiles[_activeTiles.Count - 1];
|
|
|
|
|
|
float prevHeight = GetTileHeight(prevTile);
|
|
|
|
|
|
y = prevTile.transform.position.y - prevHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
SpawnTileAtY(y);
|
2025-09-10 12:35:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Calculate the screen bounds in world space
|
|
|
|
|
|
/// </summary>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void CalculateScreenBounds()
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (_mainCamera == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_mainCamera = Camera.main;
|
|
|
|
|
|
if (_mainCamera == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("No main camera found!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
Vector3 bottom = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 0f, _mainCamera.nearClipPlane));
|
|
|
|
|
|
Vector3 top = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 1f, _mainCamera.nearClipPlane));
|
|
|
|
|
|
_screenBottom = bottom.y;
|
|
|
|
|
|
_screenTop = top.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Move all active tiles upward
|
|
|
|
|
|
/// </summary>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void MoveTiles()
|
|
|
|
|
|
{
|
|
|
|
|
|
float moveDelta = moveSpeed * Time.deltaTime;
|
|
|
|
|
|
foreach (var tile in _activeTiles)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tile != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
tile.transform.position += Vector3.up * moveDelta;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check for tiles that have moved off screen and should be destroyed or returned to pool
|
|
|
|
|
|
/// </summary>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void HandleTileDestruction()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_activeTiles.Count == 0) return;
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
GameObject topTile = _activeTiles[0];
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (topTile == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_activeTiles.RemoveAt(0);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
float tileHeight = GetTileHeight(topTile);
|
|
|
|
|
|
if (topTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer)
|
2025-09-10 12:35:22 +02:00
|
|
|
|
{
|
|
|
|
|
|
_activeTiles.RemoveAt(0);
|
|
|
|
|
|
onTileDestroyed?.Invoke(topTile);
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
|
|
|
|
|
if (useObjectPooling && _tilePool != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Find the prefab index for this tile
|
|
|
|
|
|
int prefabIndex = GetPrefabIndex(topTile);
|
|
|
|
|
|
if (prefabIndex >= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_tilePool.ReturnTile(topTile, prefabIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Destroy(topTile);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Destroy(topTile);
|
|
|
|
|
|
}
|
2025-09-10 12:35:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Check if new tiles need to be spawned
|
|
|
|
|
|
/// </summary>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void HandleTileSpawning()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_activeTiles.Count == 0) return;
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
GameObject bottomTile = _activeTiles[^1];
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (bottomTile == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_activeTiles.RemoveAt(_activeTiles.Count - 1);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
float tileHeight = GetTileHeight(bottomTile);
|
|
|
|
|
|
float bottomEdge = bottomTile.transform.position.y - tileHeight / 2;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
if (bottomEdge > _screenBottom - tileSpawnBuffer)
|
|
|
|
|
|
{
|
2025-09-16 12:23:25 +02:00
|
|
|
|
float newY = bottomTile.transform.position.y - tileHeight;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
SpawnTileAtY(newY);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Handle increasing the movement speed over time
|
|
|
|
|
|
/// </summary>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void HandleSpeedRamping()
|
|
|
|
|
|
{
|
|
|
|
|
|
_speedUpTimer += Time.deltaTime;
|
|
|
|
|
|
if (_speedUpTimer >= speedUpInterval)
|
|
|
|
|
|
{
|
2025-09-16 12:23:25 +02:00
|
|
|
|
moveSpeed = Mathf.Min(moveSpeed + speedUpFactor, maxMoveSpeed);
|
2025-09-10 12:35:22 +02:00
|
|
|
|
_speedUpTimer = 0f;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Spawn a new tile at the specified Y position
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="y">The Y position to spawn at</param>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private void SpawnTileAtY(float y)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (tilePrefabs == null || tilePrefabs.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("No tile prefabs available for spawning!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
int prefabIndex = GetWeightedRandomTileIndex();
|
|
|
|
|
|
GameObject prefab = tilePrefabs[prefabIndex];
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (prefab == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"Tile prefab at index {prefabIndex} is null!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
GameObject tile;
|
|
|
|
|
|
|
|
|
|
|
|
if (useObjectPooling && _tilePool != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
tile = _tilePool.GetTile(prefabIndex);
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (tile == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to get tile from pool!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
tile.transform.position = new Vector3(0f, y, TileSpawnZ);
|
|
|
|
|
|
tile.transform.rotation = prefab.transform.rotation;
|
|
|
|
|
|
tile.transform.SetParent(transform);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Use the prefab's original rotation
|
|
|
|
|
|
tile = Instantiate(prefab, new Vector3(0f, y, TileSpawnZ), prefab.transform.rotation, transform);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
_activeTiles.Add(tile);
|
|
|
|
|
|
_tileLastUsed[prefabIndex] = _spawnCounter++;
|
|
|
|
|
|
onTileSpawned?.Invoke(tile);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 15:02:50 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets a weighted random tile index, favoring tiles that haven't been used recently
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>The selected prefab index</returns>
|
2025-09-10 12:35:22 +02:00
|
|
|
|
private int GetWeightedRandomTileIndex()
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
int prefabCount = tilePrefabs.Count;
|
|
|
|
|
|
List<float> weights = new List<float>(prefabCount);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < prefabCount; i++)
|
2025-09-10 12:35:22 +02:00
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
int lastUsed = _tileLastUsed.TryGetValue(i, out var value) ? value : -prefabCount;
|
2025-09-10 12:35:22 +02:00
|
|
|
|
int age = _spawnCounter - lastUsed;
|
2025-09-16 15:02:50 +02:00
|
|
|
|
float weight = Mathf.Clamp(age, 1, prefabCount * 2); // More unused = higher weight
|
2025-09-10 12:35:22 +02:00
|
|
|
|
weights.Add(weight);
|
|
|
|
|
|
}
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
|
|
|
|
|
float totalWeight = 0f;
|
|
|
|
|
|
foreach (var weight in weights)
|
2025-09-10 12:35:22 +02:00
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
totalWeight += weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float randomValue = Random.value * totalWeight;
|
|
|
|
|
|
for (int i = 0; i < prefabCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (randomValue < weights[i])
|
|
|
|
|
|
{
|
|
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
randomValue -= weights[i];
|
2025-09-10 12:35:22 +02:00
|
|
|
|
}
|
2025-09-16 15:02:50 +02:00
|
|
|
|
|
|
|
|
|
|
return Random.Range(0, prefabCount); // fallback
|
2025-09-10 12:35:22 +02:00
|
|
|
|
}
|
2025-09-16 12:23:25 +02:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the height of a tile based on its prefab or renderer bounds
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tile">The tile to measure</param>
|
|
|
|
|
|
/// <returns>The height of the tile</returns>
|
|
|
|
|
|
private float GetTileHeight(GameObject tile)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (tile == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("Attempted to get height of null tile!");
|
|
|
|
|
|
return DefaultTileHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
// Check if this is a known prefab
|
|
|
|
|
|
foreach (var prefab in tilePrefabs)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (prefab == null) continue;
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
// Check if this tile was created from this prefab
|
|
|
|
|
|
if (tile.name.StartsWith(prefab.name))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_tileHeights.TryGetValue(prefab, out float height))
|
|
|
|
|
|
{
|
|
|
|
|
|
return height;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If not found, calculate it from the renderer
|
|
|
|
|
|
Renderer renderer = tile.GetComponentInChildren<Renderer>();
|
|
|
|
|
|
if (renderer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return renderer.bounds.size.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fallback
|
2025-09-16 15:02:50 +02:00
|
|
|
|
return DefaultTileHeight;
|
2025-09-16 12:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the index of the prefab that was used to create this tile
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tile">The tile to check</param>
|
|
|
|
|
|
/// <returns>The index of the prefab or -1 if not found</returns>
|
|
|
|
|
|
private int GetPrefabIndex(GameObject tile)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (tile == null || tilePrefabs == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
for (int i = 0; i < tilePrefabs.Count; i++)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (tilePrefabs[i] == null) continue;
|
|
|
|
|
|
|
2025-09-16 12:23:25 +02:00
|
|
|
|
if (tile.name.StartsWith(tilePrefabs[i].name))
|
|
|
|
|
|
{
|
|
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Called periodically to trim excess pooled tiles
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TrimExcessPooledTiles()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_tilePool != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_tilePool.TrimExcess();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-10 12:35:22 +02:00
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
2025-09-16 15:02:50 +02:00
|
|
|
|
private void OnDrawGizmosSelected()
|
2025-09-10 12:35:22 +02:00
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
if (!Application.isPlaying)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Only try to calculate this if _screenBottom hasn't been set by the game
|
|
|
|
|
|
Camera editorCam = Camera.main;
|
|
|
|
|
|
if (editorCam != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 bottom = editorCam.ViewportToWorldPoint(new Vector3(0.5f, 0f, editorCam.nearClipPlane));
|
|
|
|
|
|
_screenBottom = bottom.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 12:35:22 +02:00
|
|
|
|
// Draw tile bounds for debugging
|
|
|
|
|
|
Gizmos.color = Color.cyan;
|
|
|
|
|
|
for (int i = 0; i < initialTileCount; i++)
|
|
|
|
|
|
{
|
2025-09-16 15:02:50 +02:00
|
|
|
|
float height = DefaultTileHeight;
|
|
|
|
|
|
if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null &&
|
|
|
|
|
|
_tileHeights.TryGetValue(tilePrefabs[0], out float h))
|
2025-09-16 12:23:25 +02:00
|
|
|
|
{
|
|
|
|
|
|
height = h;
|
|
|
|
|
|
}
|
|
|
|
|
|
Vector3 center = new Vector3(0f, _screenBottom + i * height, 0f);
|
|
|
|
|
|
Gizmos.DrawWireCube(center, new Vector3(10f, height, 1f));
|
2025-09-10 12:35:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|