Target location not updating

After completing the ‘Shooting Bullet Visual’ lesson everything seems to be working - except when I first launch the game, select the shoot action, then select a target, the bullet will interpolate from the gun barrel of the selected unit to the global 0, 0, 0 position.

If I then shoot the same target again the bullet will interpolate to the correct location (the target unit)

With further experimentation I’ve found that if I add more enemy units in and switch between shooting either one, the bullet visual will ‘lag’ - as in, it will shoot the previous target, and only shoot the correct target if I shoot it twice.

Note that the other parts of the shooting action - the health being reduced on the selected target, the visual for their health being reduced and the target dying if they reach 0 HP - all work as intended. It is just the bullet visual.

I used a series of debugs to ‘track’ the gridposition from when the target is clicked after selecting the shoot action, to when it is used by the bullet visual script. It has the correct vector 3 all the way up until it actually uses it in the Update of the bullet visual script, at which point it is wrong until I shoot again.

Any ideas?

It’s a little strange. It sounds like you are calling the BulletProjectile.Setup(target) after you’ve shot the bullet, but this doesn’t make sense because the projectile is destroyed after the shot and the next bullet will not ‘remember’ that value. Perhaps share your BulletProjectile, ShootAction and UnitAnimator code and we could track down where things go funny

I suspect this as well… From what youv’e described, it’s like the target location is getting saved somewhere after the bullet is well on it’s way rather than before.

You could chalk this up as a badly aimed “warning shot” (One more move and 0,0,0 gets it!), but likely it’s just two lines juxtaposed somewhere. We’ll know more when we see the scripts @bixarrio mentioned.

Thanks for the responses!

I can’t seem to uploaded the scripts as attachments, so hopefully it’s OK to just paste them in here…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletProjectile : MonoBehaviour
{

    [SerializeField] private TrailRenderer trailRenderer;
    [SerializeField] private Transform bulletHitVFXPrefab;

    [SerializeField] private Vector3 targetPosition;
    [SerializeField] private Vector3 targetPosition2;
    public void Setup(Vector3 _targetPosition)
    {
        //Debug.Log("target position parameter is " + _targetPosition);
        targetPosition2 = _targetPosition;
        this.targetPosition = _targetPosition;
        //Debug.Log("Target position is " + this.targetPosition);
    }

    private void Update()
    {
        targetPosition = targetPosition2;

        //Debug.Log(targetPosition);
        Vector3 moveDir = (targetPosition - transform.position).normalized;

        float distanceBeforeMoving = Vector3.Distance(transform.position, targetPosition);

        float moveSpeed = 200f;
        transform.position += moveDir * moveSpeed * Time.deltaTime;

        float distanceAfterMoving = Vector3.Distance(transform.position, targetPosition);

        //distanceBeforeMoving < distanceAfterMoving

        if (distanceBeforeMoving < distanceAfterMoving)
        {
            transform.position = targetPosition;

            trailRenderer.transform.parent = null;
            Destroy(gameObject);

            Instantiate(bulletHitVFXPrefab, targetPosition, Quaternion.identity);
        }
    }

}

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class ShootAction : BaseAction
{
    public event EventHandler<OnShootEventArgs> OnShoot;

    public class OnShootEventArgs : EventArgs
    {
        public Unit targetUnit;
        public Unit shootingUnit;
    }
    

    private enum State
    {
        Aiming,
        Shooting,
        Cooloff,
    }
    private State state;



    private int maxShootDistance = 7;
    private float stateTimer;

    private Unit targetUnit;

    private bool canShootBullet;

    private void Update()
    {
        if (!isActive)
        {
            return;
        }

        stateTimer -= Time.deltaTime;      

        switch (state)
        {
            case State.Aiming:
                Vector3 aimDirection = (targetUnit.GetWorldPosition() - unit.GetWorldPosition()).normalized;
                float rotateSpeed = 10f;
                transform.forward = Vector3.Lerp(transform.forward, aimDirection, rotateSpeed * Time.deltaTime);
                break;
            case State.Shooting:
                if (canShootBullet)
                {
                    Shoot();
                    canShootBullet = false;
                }
                break;
            case State.Cooloff:                
                break;
        }

        if (stateTimer < 0)
        {
            NextState();
        }
    }

    private void NextState()
    {
        switch (state)
        {
            case State.Aiming:
                state = State.Shooting;
                float shootingStateTime = 0.1f;
                stateTimer = shootingStateTime;
                break;
            case State.Shooting:
                state = State.Cooloff;
                float coolOffStateTime = 0.5f;
                stateTimer = coolOffStateTime;
                
                break;
            case State.Cooloff:
                ActionComplete();
                break;
        }

       // Debug.Log(state);
    }

    private void Shoot()
    {
        OnShoot?.Invoke(this, new OnShootEventArgs {
            targetUnit = targetUnit, 
            shootingUnit = unit 
        });
        targetUnit.Damage(40);
    }

    public override string GetActionName()
    {
        return "Shoot";
    }

    public override List<GridPosition> GetValidActionGridPositionList()
    {
        GridPosition unitGridPosition = unit.GetGridPosition();
        return GetValidActionGridPositionList(unitGridPosition);
    }


    public List<GridPosition> GetValidActionGridPositionList(GridPosition unitGridPosition)
    {
        List<GridPosition> validGridPositionList = new List<GridPosition>();

        

        for (int x = -maxShootDistance; x <= maxShootDistance; x++)
        {
            for (int z = -maxShootDistance; z <= maxShootDistance; z++)
            {
                GridPosition offsetGridPosition = new GridPosition(x, z);
                GridPosition testGridPosition = unitGridPosition + offsetGridPosition;

                if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition))
                {
                    continue;
                }

                int testDistance = Mathf.Abs(x) + Mathf.Abs(z);
                if (testDistance > maxShootDistance)
                {
                    continue;
                }


                if (!LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition))
                {
                    //grid position is empty, no Unit
                    continue;
                }

                Unit targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(testGridPosition);

                if (targetUnit.IsEnemy() == unit.IsEnemy())
                {
                    //Both units on same 'team'
                    continue;
                }

                validGridPositionList.Add(testGridPosition);
            }
        }
        return validGridPositionList;
    }

    public override void TakeAction(GridPosition gridPosition, Action onActionComplete)
    {
        targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(gridPosition);
        //Debug.Log(targetUnit.name);

       // Debug.Log("Aiming");

        state = State.Aiming;
        float aimingStateTime = 1f;
        stateTimer = aimingStateTime;

        canShootBullet = true;

        ActionStart(onActionComplete);
    }   

    public Unit GetTargetUnit()
    {
        return targetUnit;
    }

    public int GetMaxShootDistance()
    {
        return maxShootDistance;
    }

    public override EnemyAIAction GetBestEnemyAIAction(GridPosition gridPosition)
    {
        Unit targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(gridPosition);



        return new EnemyAIAction
        {
            gridPosition = gridPosition,
            actionValue = 100 + (int)MathF.Round((1- targetUnit.GetHealthNormalized()) * 100f),
        };
    }

    public int GetTargetCountAtPosition(GridPosition gridPosition)
    {
        return GetValidActionGridPositionList(gridPosition).Count;
    }

}

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UnitAnimator : MonoBehaviour
{
    [SerializeField] Animator animator;

    [SerializeField] Transform bulletProjectilePrefab;
    [SerializeField] Transform shootPointTransform;


    private void Awake()
    {
        if(TryGetComponent<MoveAction>(out MoveAction moveAction))
        {
            moveAction.OnStartMoving += MoveAction_OnStartMoving;
            moveAction.OnStopMoving += MoveAction_OnStopMoving;
        }

        if(TryGetComponent<ShootAction>(out ShootAction shootAction))
        {
            shootAction.OnShoot += ShootAction_OnStartShooting;
        }
    }

    private void MoveAction_OnStartMoving(object sender, EventArgs e)
    {
        animator.SetBool("isWalking", true);
    }

    private void MoveAction_OnStopMoving(object sender, EventArgs e)
    {
        animator.SetBool("isWalking", false);
    }

    private void ShootAction_OnStartShooting(object sender, ShootAction.OnShootEventArgs e)
    {
        animator.SetTrigger("Shoot");

        Transform bulletProjectileTransform = Instantiate(bulletProjectilePrefab, shootPointTransform.position, Quaternion.identity);

        BulletProjectile bulletProjectile = bulletProjectilePrefab.GetComponent< BulletProjectile>();

        Vector3 targetShootAtPosition = e.targetUnit.GetWorldPosition();

        targetShootAtPosition.y = shootPointTransform.position.y;
       
        bulletProjectile.Setup(targetShootAtPosition);
    }

}

Not quite sure why you are setting two targetPositions in BulletProjectile, it doesn’t seem necessary. targetPosition2 is not needed because it serves no purpose.


The problem is in the UnitAnimator.ShootAction_OnStartShooting:

BulletProjectile bulletProjectile = bulletProjectilePrefab.GetComponent<BulletProjectile>();

You are updating the prefab’s script instead of the instantiated script. Initially the prefab doesn’t have a target, so it points to (0,0,0). Now you change that to this target, but you are ‘shooting’ the instantiated bullet which was created before the change and is still pointing at (0,0,0). The next time you instantiate the prefab, it is now pointing at the previous target because you changed the value in the prefab, so the newly instantiated bullet is ‘shooting’ at the old target. You should be updating the instantiated version

BulletProjectile bulletProjectile = bulletProjectileTransform.GetComponent<BulletProjectile>();

Also, sharing the scripts like this is what we expected. No need to attach the scripts, just paste the code. You did good

Ah, forgot about the targetPosition2 - that was part of my very late night debugging.

And the solution worked! Thank you so much. I’m going to blame intellisense for that one (:

Pasting is correct, and good job getting them formated. With the scripts pasted in, we can cut and paste to show (and fix) the errors more meaningfully.

Intellisense’s autocomplete gathers everything that makes sense in that context and puts it up there in some order that makes sense, but it often puts the wrong thing first.

This particular error (Getting a component to initialze off of the prefab instead of the instance) is a fairly common problem. It’s happened to me plenty of times over the years.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms