Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Resolved List gets updated even if I don't call it

Discussion in 'Scripting' started by Sarth04, Jul 21, 2020.

  1. Sarth04

    Sarth04

    Joined:
    Mar 12, 2019
    Posts:
    2
    Hi, I'm creating a kind of tower defense game and this is my script for moving an enemy. It's attached to an enemy that gets spawned after a path is created. It gets List from PathCreator script on start and only there, the list is also private.

    So in my mind - After spawning an enemy, he gets a path and he follows this path even if PathCreator creates a new one because I assign it only on Start.

    This is how I want it to work, but for some reason when I create a new path in PathCreator enemy follows it instead of following the one he got on Start().

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.AI;
    6.  
    7. public class EnemyMover : MonoBehaviour
    8. {
    9.     [HideInInspector] public Grid.Sides side;
    10.  
    11.     List<Waypoint> path = new List<Waypoint>();
    12.  
    13.     NavMeshAgent agent;
    14.  
    15.     int currentwaypoint = 1;
    16.  
    17.     private void Start()
    18.     {
    19.         path = FindObjectOfType<PathCreator>().GetPath(side);
    20.  
    21.         agent = GetComponent<NavMeshAgent>();
    22.     }
    23.  
    24.     private void Update()
    25.     {
    26.         Move();
    27.     }
    28.  
    29.     private void Move()
    30.     {
    31.         if (currentwaypoint == path.Count)
    32.         {
    33.             Destroy(gameObject);
    34.             return;
    35.         }
    36.  
    37.         agent.destination = path[currentwaypoint].transform.position;
    38.         path[currentwaypoint].SetColor(Grid.Sides.top, Color.black);
    39.  
    40.         if (IsDestinationReached())
    41.         {
    42.             SetNextWaypoint();
    43.         }
    44.     }
    45.  
    46.     private void SetNextWaypoint()
    47.     {
    48.         currentwaypoint += 1;
    49.     }
    50.  
    51.     private bool IsDestinationReached()
    52.     {
    53.         if (Vector3.Distance(transform.position, agent.destination) < 1.3f) return true;
    54.         return false;
    55.     }
    56. }
    Code (CSharp):
    1.     public List<Waypoint> GetPath(Grid.Sides getPathSide)
    2.     {
    3.         if (getPathSide == Grid.Sides.top)
    4.         {
    5.             return topPath;
    6.         }
    7.  
    8.         if (getPathSide == Grid.Sides.bottom)
    9.         {
    10.             return bottomPath;
    11.         }
    12.  
    13.         return null;
    14.     }
    This bug isn't going to affect my game in any way because I'm not going to allow new paths get created after enemies start spawning but I'm curious why it's working like that and I'd like to understand it.
     
    Last edited: Jul 21, 2020
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    Lists are reference types. Assigning a List just says "I'm that list over there."

    So after you assign the
    path
    in Start(), if anyone changes the contents of topPath or bottomPath, they are modifying the same path that
    path
    points to.

    If you want to fix it, one way is to make a fresh list in Start():

    Code (csharp):
    1. path = new List<Waypoint>( FindObjectOfType<PathCreator>().GetPath(side));
    EDIT: I bozo-ed the term value vs reference... fixed.
     
    Last edited: Jul 21, 2020
    Sarth04 likes this.
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,835
    List<T>, like all classes in C#, is a reference type. When you assign a value to a List variable, you aren't making a copy of the list, you are just pointing that variable towards some List that already exists. If that List is subsequently modified, the variable will "see" those modifications.
     
    Kurt-Dekker, Joe-Censored and Sarth04 like this.
  4. Sarth04

    Sarth04

    Joined:
    Mar 12, 2019
    Posts:
    2
    It explains a lot, thank you for quick replies