Object Pooling Problem in Tower Defense Game

25 Views Asked by At

I'm trying to make a tower defense game and I'm new to programming. I try to implement Object Pooling for placing towers, showing towers when hovering (when you hover your mouse over a tile it shows a tower), and shooting. This is my first implementation of object pooling and I'm stuck at this point.

My problem is this; everything works fine with pool, everything is instantiated at the beginning of the game and tower placement and showing tower when hovered works fine. But when I try to shoot arrow at the placed tower the problem occurs. The tower is placed when i click the mouse and it cycles through enemies in the scene and calculates distance and if the distance is less than the given amount the tower looks at the enemy. After that it shoots the arrow at the enemy's location. When it hits the enemy it gets deactivated. It works fine for the first tower that I place. However, when I place another tower after the arrow hit the enemy and it got deactivated, the second tower's arrow keeps shooting to the same enemy that the first tower is facing even if the second tower is not in range of the enemy. Like the arrow keeps thinking that it belongs to the first tower.

I imagine that it has something to do with object pooling and the mechanic of it, but I couldn't figure a solution for this problem. I've been at this for three days now and didn't have any luck.

What I want is this. When I click and create a tower, it gets an arrow from the pool. And if the enemy comes close it shoots the arrow either at the location of the enemy, or straight forward because the tower is already facing it.

This is the part responsible for calculating distance of the enemy, looking at the enemy and shooting. This script is on the tower.

void LookAtTarget()
    {

        enemies = GameObject.FindGameObjectsWithTag("Enemy");

        for (int i = 0; i < enemies.Length; i++)
        {
            if (enemies[i] == null || !enemies[i].activeInHierarchy) { return; }


            float distance = Vector3.Distance(enemies[i].transform.position, transform.position);


            if (distance < aimRange)
            {
                canShoot = true;

                target = enemies[i].transform;
                transform.LookAt(enemies[i].transform);
                //shoot target

                pooledArrow.transform.position = Vector3.MoveTowards(pooledArrow.transform.position, target.position, projectileSpeed * Time.deltaTime);

            }
            else
            {
                canShoot = false;
            }

        }

    }

This is the whole script of the above:

public class Tower : MonoBehaviour
{
    [SerializeField] GameObject arrow;
    [SerializeField] GameObject arrowParent;


    [SerializeField] float aimRange;
    [SerializeField] float projectileSpeed;
    [SerializeField] float projectileDmg;
    [SerializeField] float shootingSpeed;
    [SerializeField] float shootingDelay;


    ObjectPool objectPool;
    GameObject pooledArrow;
    Transform target;

    public bool canShoot;

    GameObject[] enemies;

    [SerializeField] GameObject currentArrow;

    private void Start()
    {
        objectPool = FindObjectOfType<ObjectPool>();
        GetArrow();
    }

    void Update()
    {
        LookAtTarget();

    }

    void LookAtTarget()
    {

        enemies = GameObject.FindGameObjectsWithTag("Enemy");

        for (int i = 0; i < enemies.Length; i++)
        {
            if (enemies[i] == null || !enemies[i].activeInHierarchy) { return; }


            float distance = Vector3.Distance(enemies[i].transform.position, transform.position);


            if (distance < aimRange)
            {
                canShoot = true;

                target = enemies[i].transform;
                transform.LookAt(enemies[i].transform);
                //shoot target

                pooledArrow.transform.position = Vector3.MoveTowards(pooledArrow.transform.position, target.position, projectileSpeed * Time.deltaTime);

            }
            else
            {
                canShoot = false;
            }

        }

    }
    public void ClearReference()
    {
        pooledArrow = null;
    }

    void GetArrow()
    {
        target = null;
        canShoot = false;
        pooledArrow = null;
        pooledArrow = objectPool.GetWeaponBallistaArrow();
        pooledArrow.SetActive(true);
        pooledArrow.transform.position = transform.position + Vector3.up * 2;
    }

This is the object pooling script. I assume this script is fine:

public class ObjectPool : MonoBehaviour { 

    [SerializeField] GameObject weaponBallistaPrefab; 
    [SerializeField] int weaponBallistaPoolSize;
    [SerializeField] GameObject weaponBallistaArrowPrefab;
    [SerializeField] int weaponBallistaArrowPoolSize;

    [SerializeField] GameObject weaponBallistaHoverPrefab;
    [SerializeField] int weaponBallistaHoverPoolSize;



    List<GameObject> weaponBallista = new List<GameObject>();
    List<GameObject> weaponBallistaArrow = new List<GameObject>();
    List<GameObject> weaponBallistaHover = new List<GameObject>();




    private void Awake()
    {
        PopulatePool(weaponBallista, weaponBallistaPoolSize, weaponBallistaPrefab);
        PopulatePool(weaponBallistaHover, weaponBallistaHoverPoolSize, weaponBallistaHoverPrefab);
        PopulatePool(weaponBallistaArrow, weaponBallistaArrowPoolSize, weaponBallistaArrowPrefab);

    }


    void PopulatePool(List<GameObject> objectList, int objectPoolSize, GameObject objectPrefab)
    {

        for (int i = 0; i < objectPoolSize; i++)
        {
            GameObject weapon = Instantiate(objectPrefab, gameObject.transform);
            objectList.Add(weapon);
            objectList[i].SetActive(false);
        }
    }


    public GameObject GetWeaponBallista()
    {
        if (weaponBallista == null) { return null; }

        for (int i = 0; i < weaponBallista.Count; i++)
        {
            if (!weaponBallista[i].activeInHierarchy)
            {
                return weaponBallista[i];
            }

        }
        return null;
    }

    public GameObject GetWeaponBallistaHover()
    {
        if (weaponBallistaHover == null) { return null; }

        for (int i = 0; i < weaponBallistaHover.Count; i++)
        {
            if (!weaponBallistaHover[i].activeInHierarchy)
            {
                return weaponBallistaHover[i];
            }

        }
        return null;
    }

    public GameObject GetWeaponBallistaArrow()
    {
        if (weaponBallistaArrow == null) { return null; }

        for (int i = 0; i < weaponBallistaArrow.Count; i++)
        {
            if (!weaponBallistaArrow[i].activeInHierarchy)
            {
                return weaponBallistaArrow[i];
            }

        }
        return null;
    }

And this script sits on the arrows it only deactivates the arrow when collides with enemy:

public class Projectile : MonoBehaviour
{
  
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Enemy"))
        {
            gameObject.SetActive(false);
        }
    }
}

Here is the link to github if you want to see the project yourself:

https://github.com/TahaSimsk/MyTowerDefense

I've tried to move the arrow with a lot of different methods. But whenever I try to reach the target or something from tower script it fails.

0

There are 0 best solutions below