Search Unity

Question Updating path in AStar

Discussion in 'Scripting' started by 4d69636861656c, Aug 1, 2020.

  1. 4d69636861656c

    4d69636861656c

    Joined:
    Dec 9, 2015
    Posts:
    7
    I am using the A* pathfinding in a 2D project and came across an issue. Drawing and updating the path to a target works fine on game objects that I've placed in a scene. However, this is not the case for instantiated prefabs. Path is drawn to the target game object, but it does not update. The original target position remains the point that the path is drawn, even when the target has changed position. Like I mentioned, this is not the case when those prefabs are manually placed in a scene. Has anyone ecountered this issue? I should mention that I'm using a InvokeRepeating() method for updating the path to the target. It is called every 0.5 seconds.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    Share your code. My guess is that you are using a reference to the prefab somewhere where you should be referencing the instance that you instantiated from the prefab.

    Unrelated side note, but coroutines are considered better practice and you will have more type-safety and control over their execution than InvokeRepeating.
     
    4d69636861656c likes this.
  3. 4d69636861656c

    4d69636861656c

    Joined:
    Dec 9, 2015
    Posts:
    7
    Here is my code:
    Code (CSharp):
    1.  
    2. using Pathfinding;
    3. using UnityEngine;
    4.  
    5. public class Enemy : MonoBehaviour
    6. {
    7.     [Header("References")]
    8.     public Transform target;
    9.     // ...
    10.     public GameObject spawnPrefab;
    11.  
    12.     [Header("Common AI Stats")]
    13.     // ...
    14.     public float nextWaypointDistance = 3F;
    15.     public float updatePathRate = 0.5F;
    16.     public float endReachedDistanceOnXAxis = 0.5F;
    17.     public float endReachedDistanceOnYAxis = 0.5F;
    18.     [Range(1.00F, 5.00F)]
    19.     public float safeDistance = 2.00F;
    20.     // ...
    21.  
    22.     [Header("Melee AI Stats")]
    23.     // ...
    24.  
    25.     [Header("Ranged AI Stats")]
    26.     // ...
    27.  
    28.     [Header("Support AI Stats")]
    29.     // ...
    30.  
    31.     [Header("Sounds")]
    32.     // ...
    33.  
    34.     private int _currentHealth;
    35.     private bool _isDead = false;
    36.     private int _currentWaypoint = 0;
    37.     private float _originalMovingSpeed = 0.00F;
    38.     private float _originalJumpCooldownTimer = 0.00F;
    39.     private bool _reachedEndOfPath = false;
    40.     private bool _isJumping = false;
    41.  
    42.     private Vector2 _originalPosition;
    43.     private Animator _animator;
    44.     private Path _path;
    45.     private Seeker _seeker;
    46.     private Rigidbody2D _rigidbody;
    47.     private AudioManager _audioManager;
    48.  
    49.     public float RemainingDistanceX
    50.     {
    51.         get
    52.         {
    53.             return Mathf.Abs(target.position.x - this._rigidbody.position.x);
    54.         }
    55.     }
    56.  
    57.     public float RemainingDistanceY
    58.     {
    59.         get
    60.         {
    61.             return Mathf.Abs(target.position.y - this._rigidbody.position.y);
    62.         }
    63.     }
    64.  
    65.     private void Awake()
    66.     {
    67.  
    68.     }
    69.  
    70.     // Start is called before the first frame update
    71.     void Start()
    72.     {
    73.         // ...
    74.  
    75.         _animator = GetComponentInChildren<Animator>();
    76.         _seeker = GetComponent<Seeker>();
    77.         _rigidbody = GetComponent<Rigidbody2D>();
    78.         _audioManager = FindObjectOfType<AudioManager>();
    79.         Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);
    80.  
    81.         // Generate path to target gameObject.
    82.         InvokeRepeating("UpdatePath", 0.00F, updatePathRate);
    83.  
    84.         // ...
    85.     }
    86.  
    87.     // Update is called once per frame.
    88.     void FixedUpdate()
    89.     {
    90.         // Checks if there is a valid path.
    91.         if (_path == null)
    92.         {
    93.             return;
    94.         }
    95.  
    96.         UpdateGFX();
    97.  
    98.         // Stop movement when the player is nearby or the enemy is playing the attack/hurt animations.
    99.         if (RemainingDistanceX <= endReachedDistanceOnXAxis || _animator.GetCurrentAnimatorStateInfo(0).IsName("Attack") || _animator.GetCurrentAnimatorStateInfo(0).IsName("Hurt"))
    100.         {
    101.             this._rigidbody.velocity = Vector2.zero;
    102.         }
    103.  
    104.         // ...
    105.  
    106.         // Checks waypoints in the path.
    107.         if ((_currentWaypoint >= _path.vectorPath.Count) || (RemainingDistanceX <= endReachedDistanceOnXAxis && RemainingDistanceY <= endReachedDistanceOnYAxis))
    108.         {
    109.             _reachedEndOfPath = true;
    110.             return;
    111.         }
    112.         else
    113.         {
    114.             _reachedEndOfPath = false;
    115.         }
    116.  
    117.         MoveToWaypoint();
    118.     }
    119.  
    120.     private void UpdatePath()
    121.     {
    122.         if (_seeker.IsDone())
    123.         {
    124.             _seeker.StartPath(_rigidbody.position, target.position, OnPathComplete);
    125.         }
    126.     }
    127.  
    128.     private void OnPathComplete(Path path)
    129.     {
    130.         if (!path.error)
    131.         {
    132.             this._path = path;
    133.             _currentWaypoint = 0;
    134.         }
    135.     }
    136.  
    137.     private void MoveToWaypoint()
    138.     {
    139.         // Moving GameObject to Waypoint.
    140.         Vector2 direction = ((Vector2)this._path.vectorPath[_currentWaypoint] - _rigidbody.position).normalized;
    141.         Vector2 force = direction * speed * Time.deltaTime;
    142.  
    143.         _rigidbody.velocity = force;
    144.  
    145.         float distance = Vector2.Distance(this._rigidbody.position, this._path.vectorPath[_currentWaypoint]);
    146.  
    147.         // Checks if gameObject is at Waypoint location and if the distance to the player is low enough to move to the next waypoint and closer to player.
    148.         if (distance < nextWaypointDistance && RemainingDistanceX < safeDistance)
    149.         {
    150.             _currentWaypoint++;
    151.         }
    152.         // If Player is far enough, the enemy will play the idle animation.
    153.         else
    154.         {
    155.             _animator.SetInteger("AnimState", 0);
    156.         }
    157.  
    158.         // --------------------------------------------------------
    159.  
    160.         if (force.x >= 0.01F || force.x <= -0.01F)
    161.         {
    162.             _animator.SetInteger("AnimState", 2);
    163.         }
    164.     }
    165.  
    166.     private void UpdateGFX()
    167.     {
    168.         // ...
    169.     }
    170.  
    171.     private void AttackWithDelay()
    172.     {
    173.         // ...
    174.     }
    175.  
    176.     private void Attack()
    177.     {
    178.         // ...
    179.     }
    180.  
    181.     private void ShootWithDelay()
    182.     {
    183.         // ...
    184.     }
    185.  
    186.     private void Shoot()
    187.     {
    188.         // ...
    189.     }
    190.  
    191.     private void SpawnWithDelay()
    192.     {
    193.         // ...
    194.     }
    195.  
    196.     private void Spawn()
    197.     {
    198.         // ...
    199.     }
    200.  
    201.     public void TakeDamage(int damage)
    202.     {
    203.         // ...
    204.     }
    205.  
    206.     private void InstantiateDamagePopup(int damage)
    207.     {
    208.         // ...
    209.     }
    210.  
    211.     private void Die()
    212.     {
    213.         // ...
    214.     }
    215.  
    216.     private void AggressiveJump()
    217.     {
    218.         // ...
    219.     }
    220.  
    221.     private void UpwardsMove()
    222.     {
    223.         // ...
    224.     }
    225.  
    226.     private void DownwardsMove()
    227.     {
    228.         // ...
    229.     }
    230.  
    231.     private void OnDrawGizmosSelected()
    232.     {
    233.         // ...
    234.     }
    235. }
    236.  
    I removed the methods unrelated to pathfinding.

    I think I understand what you mean. I am setting the target as the player prefab, but I should try to find the Player object in the hierachy instead.

    I will definitely look into it! Thanks for the advice.
     
  4. 4d69636861656c

    4d69636861656c

    Joined:
    Dec 9, 2015
    Posts:
    7
    I managed to fix it by using:
    Code (CSharp):
    1. target = gameObject.transform.Find("/Player(Samurai)");
    (instead of referencing the Player prefab in the Inspector). Thanks for the tip.
     
    Last edited: Aug 1, 2020
    kadircebel_unity and PraetorBlue like this.
  5. kadircebel_unity

    kadircebel_unity

    Joined:
    Jun 29, 2020
    Posts:
    1
    Thanks. That's worked.