My Contributions in Endless Runner

//In Coin.cs

private void OnTriggerEnter(Collider other) {
    PlayerMovement player = other.gameObject.GetComponent<PlayerMovement>();
    if(player != null)
    {
        GameManager.Instance.OnScoreIncrease?.Invoke();
        SoundManager.Instance?.PlaySFX(SoundType.CoinPickup);
        Instantiate(coinPickEffect,transform.position,Quaternion.identity);
    }
    base.Destroy();    
}

//In GameManager.cs

//In Initialize method
OnScoreIncrease.AddListener(IncreaseScore);
OnScoreIncrease.AddListener(UpdateScoreText);

//Separate methods
 private void IncreaseScore()
 {
     _score++;
 }

 private void UpdateScoreText()
 {
     _scoreText.text = _score.ToString();
 }
void Update()
{
    Floor firstFloor = _floors[0];
    Transform firstFloorEndPoint = firstFloor.EndPoint;
    float offset = player.transform.position.z - firstFloorEndPoint.position.z;
    if(offset >= spawnDistance)
    {
        Debug.Log("Generating path");
        for(int i = 1; i <= floorsGenerationCount; i++)
        {
            Floor lastFloor = _floors[_floors.Count - 1];
            Transform lastFloorEndPoint = lastFloor.EndPoint;
            
            Floor generatedFloor = PoolManager.Instance.ReuseObject(floor.gameObject,lastFloorEndPoint.position,Quaternion.identity).PoolObject as Floor;
            _floors.Add(generatedFloor);
        
            Transform generatedFloorEndPoint = generatedFloor.EndPoint;
            if(generateObstacles)
            {
                GenerateObstacles(generatedFloor,generatedFloorEndPoint);
            }

            if(generateCoins)
            {
                GenerateCoins(generatedFloor,generatedFloorEndPoint);
            }
        }
        
        SetToOrigin();
        _floors.Remove(firstFloor);
        StartCoroutine(DestroyFloor(firstFloor,floorDestroyTime));       
    }
}

void SetToOrigin()
{
    playerCamera.enabled = false;
    player.transform.position -= Vector3.forward * backwardDistance;
    playerCamera.enabled = true;
    foreach(Floor floor in _floors)
    {
        floor.transform.position -= Vector3.forward * backwardDistance;
        List<PoolObject> things = floor.ThingsOnFloor;
        foreach(PoolObject thing in things)
        {
            if(thing != null)
            {
                thing.transform.position -= Vector3.forward * backwardDistance;
            }
        }
    }
}
private void GenerateObstacles(Floor floor,Transform floorEndPoint)
{
    int randomObstacleCount = Random.Range(1,maxObstaclesPerFloor + 1);
    for(int i = 1; i <= randomObstacleCount; i++)
    {
        int randomSpawnPtIndex = Random.Range(0,spawnPointRefs.Length);

        float positionX = spawnPointRefs[randomSpawnPtIndex].transform.position.x;
        float positionZ = floorEndPoint.position.z - Random.Range(0f,obstacleSpawnLength);
        float positionY = spawnPointRefs[randomSpawnPtIndex].transform.position.y;

        Vector3 spawnPosition = new Vector3(positionX,positionY,positionZ);
        Obstacle obstacle = PoolManager.Instance.ReuseObject(obstaclePrefab.gameObject,spawnPosition,Quaternion.identity).PoolObject as Obstacle;
        floor.AddThing(obstacle);
    }
}

private void GenerateCoins(Floor floor,Transform floorEndPoint)
{
    int randomCoinsCount = Random.Range(1,maxCoinsToGenerate + 1);

    for(int i = 1; i <= randomCoinsCount; i++)
    {
        int randomSpawnPtIndex = Random.Range(0,spawnPointRefs.Length);
        float positionX = spawnPointRefs[randomSpawnPtIndex].transform.position.x;
        float positionZ = floorEndPoint.position.z - Random.Range(0f,obstacleSpawnLength);
        float positionY = spawnPointRefs[randomSpawnPtIndex].transform.position.y;

        Vector3 spawnPosition = new Vector3(positionX,positionY,positionZ);
        Coin coin = PoolManager.Instance.ReuseObject(coinPrefab.gameObject,spawnPosition,Quaternion.identity).PoolObject as Coin;
        floor.AddThing(coin);
    }
    
        
}

private IEnumerator DestroyFloor(Floor floor,float destroyTime)
{
    yield return new WaitForSeconds(destroyTime);
    floor.Destroy();
}
//PoolManager.cs

public class PoolManager : GenericSingleton<PoolManager>
{
    private Dictionary<int,Queue<ObjectInstance>> _poolDictionary;

    protected override void Awake() {
        base.Awake();
        _poolDictionary = new Dictionary<int, Queue<ObjectInstance>>();
    }

    private void Start() {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    public void CreatePool(GameObject prefab,int poolSize)
    {
        int id = prefab.GetInstanceID();

        if(_poolDictionary.ContainsKey(id) == false)
        {
            _poolDictionary.Add(id,new Queue<ObjectInstance>());
            GameObject poolObjectsContainer = new GameObject(prefab.name + " pool");
            poolObjectsContainer.transform.parent = transform;
            
            for(int i = 0; i < poolSize; i++)
            {
                ObjectInstance objectInPool = new ObjectInstance(Instantiate(prefab) as GameObject,id);
                objectInPool.SetParent(poolObjectsContainer.transform);
                _poolDictionary[id].Enqueue(objectInPool);
                
            }
        }
    }

    /*
    public void ReuseObject(GameObject prefab,Vector3 position,Quaternion rotation)
    {
        int id = prefab.GetInstanceID();

        if(!_poolDictionary.ContainsKey(id))
        {
            Debug.LogError(prefab.name + " Pool not found!!");
            return;
        }


        ObjectInstance objectInPool = _poolDictionary[id].Dequeue();
        objectInPool.Reuse(position,rotation);
        _poolDictionary[id].Enqueue(objectInPool);
    }
    */
    public ObjectInstance ReuseObject(GameObject prefab,Vector3 position,Quaternion rotation)
    {
        int id = prefab.GetInstanceID();

        if(!_poolDictionary.ContainsKey(id))
        {
            Debug.LogError(prefab.name + " pool not found!!");
            return null;
        }

        if(_poolDictionary[id].Count == 0)
        {
            return null;
        }
        ObjectInstance objectInPool = _poolDictionary[id].Dequeue();
        objectInPool.Reuse(position,rotation);
        //_poolDictionary[id].Enqueue(objectInPool);

        return objectInPool;
    }

    public void ReturnObjectToPool(ObjectInstance instance)
    {
        

        if(!_poolDictionary.ContainsKey(instance.MainPrefabID))
        {
            Debug.LogError(instance.GameObject.name + " Pool not found!!");
            return;
        }

        _poolDictionary[instance.MainPrefabID].Enqueue(instance);
    }
    

    public void ClearAllPools()
    {
        foreach(var pair in _poolDictionary)
        {
            Queue<ObjectInstance> poolObjects = pair.Value;

            while(poolObjects.Count > 0)
            {
                poolObjects.Dequeue();
            }
        }

        _poolDictionary.Clear();
        
        GameObject[] allChildren = new GameObject[transform.childCount];

        int i = 0;
        foreach(Transform child in transform)
        {
            allChildren[i] = child.gameObject;
            i++;
        }

        foreach(GameObject child in allChildren)
        {
            Destroy(child);
        }
    }

    private void OnSceneLoaded(Scene scene,LoadSceneMode mode)
    {
        ClearAllPools();
    }
    private void OnDestroy() 
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
}
//ObjectInstance.cs

public class ObjectInstance
{
    GameObject gameObject;
    Transform transform;

    bool hasPoolObjectComponent;
    PoolObject poolObject;

    int mainPrefabID;

    public PoolObject PoolObject { get => poolObject; }
    public GameObject GameObject { get => gameObject; }
    public int MainPrefabID { get => mainPrefabID; }

    public ObjectInstance(GameObject gameObject,int mainPrefabID)
    {
        this.gameObject = gameObject;
        this.transform = gameObject.transform;
        this.gameObject.SetActive(false);
        this.mainPrefabID = mainPrefabID;
        
        PoolObject poolObjectReference = gameObject.GetComponent<PoolObject>();
        if(poolObjectReference != null)
        {
            this.hasPoolObjectComponent = true;
            this.poolObject = poolObjectReference;
            this.poolObject.ObjectInstanceComp = this;
        }
    }

    
    public void Reuse(Vector3 position,Quaternion rotation)
    {
        if(this.hasPoolObjectComponent)
        {
            this.poolObject.Reuse();
        }
        this.gameObject.SetActive(true);        
        this.gameObject.transform.position = position;
        this.gameObject.transform.rotation = rotation;
    }
    

    public void SetParent(Transform parent)
    {
        this.gameObject.transform.parent = parent;
    }
}