using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ObstaclePool : MonoBehaviour
{
public static ObstaclePool Instance { get; private set; }
private List<GameObject> pooledObstacles;
public List<GameObject> obstaclePrefabs;
private int pooledAmount = 50;
private void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void Start()
{
InitializePool();
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
InitializePool();
}
private void InitializePool()
{
pooledObstacles = new List<GameObject>();
for (int i = 0; i < pooledAmount; i++)
{
int prefabIndex = Random.Range(0, obstaclePrefabs.Count);
GameObject obstacle = Instantiate(obstaclePrefabs[prefabIndex]);
obstacle.name = obstaclePrefabs[prefabIndex].name;
obstacle.SetActive(false);
obstacle.transform.SetParent(transform);
obstacle.transform.position = new Vector2(obstacle.transform.position.x, obstacle.transform.position.y);
pooledObstacles.Add(obstacle);
}
}
public GameObject GetPooledObstacle(int prefabIndex)
{
if (prefabIndex < 0 || prefabIndex >= obstaclePrefabs.Count)
{
return null;
}
for (int i = 0; i < pooledObstacles.Count; i++)
{
if (pooledObstacles[i] != null && !pooledObstacles[i].activeInHierarchy && pooledObstacles[i].name.Contains(obstaclePrefabs[prefabIndex].name))
{
return pooledObstacles[i];
}
}
GameObject newObj = Instantiate(obstaclePrefabs[prefabIndex]);
newObj.name = obstaclePrefabs[prefabIndex].name;
newObj.SetActive(false);
newObj.transform.position = new Vector2(newObj.transform.position.x, newObj.transform.position.y);
pooledObstacles.Add(newObj);
return newObj;
}
public void ReturnToPool(GameObject obstacle)
{
if (obstacle != null)
{
obstacle.SetActive(false);
}
}
}
using System;
using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;
public abstract class ObstacleSpawner : MonoBehaviour
{
protected ObstaclePool obstaclePool;
protected float spawnDelay;
protected float obstacleLifetime;
protected float spawnChance;
public event Action<GameObject> OnObstacleDeactivated;
protected Transform playerBody;
protected float timeSinceLastSpawn = 5.0f;
protected virtual void Start()
{
playerBody = GameObject.FindGameObjectWithTag("PlayerBody").transform;
}
void Update()
{
if (playerBody == null || obstaclePool == null) return;
timeSinceLastSpawn += Time.deltaTime;
if (timeSinceLastSpawn >= spawnDelay)
{
SpawnObstacle();
timeSinceLastSpawn = 0.0f;
}
}
protected virtual void SpawnObstacle()
{
float spawnRoll = Random.value;
if (spawnRoll < spawnChance)
{
Vector2 spawnPosition = GetSpawnPosition();
float checkRadius = GetCheckRadius();
Collider[] overlaps = Physics.OverlapSphere(spawnPosition, checkRadius, LayerMask.GetMask("Default"));
bool isOverlap = false;
foreach (Collider overlap in overlaps)
{
if (overlap.gameObject.CompareTag("Obstacle"))
{
isOverlap = true;
break;
}
}
if (!isOverlap)
{
int prefabIndex = Random.Range(0, obstaclePool.obstaclePrefabs.Count);
GameObject obstacle = obstaclePool.GetPooledObstacle(prefabIndex);
obstacle.transform.position = spawnPosition;
obstacle.SetActive(true);
StartCoroutine(DeactivateAfterDelay(obstacle, obstacleLifetime));
}
}
}
protected virtual Vector2 GetSpawnPosition()
{
return new Vector2(Random.Range(-4.0f, 4.0f), playerBody.position.y + Random.Range(2.0f, 7.0f));
}
protected virtual float GetCheckRadius()
{
return 0.8f;
}
protected virtual IEnumerator DeactivateAfterDelay(GameObject obstacle, float delay)
{
yield return new WaitForSeconds(delay);
OnObstacleDeactivated?.Invoke(obstacle);
obstaclePool.ReturnToPool(obstacle);
}
}