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

Question Multiple 'Enemy's treated as the same

Discussion in 'Scripting' started by Tempy111, Feb 22, 2023.

  1. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    I think this is the right section ^_^ always a great start..

    I've got a maze game which has a couple of enemies which hunt through the maze to try to find the player before the player collections it's required number of items. While both enemies look different (just a texture swap) they run the same code, which I have entitled 'Fox_AI'. this deals with the chasing which is simple, mostly just using the navmesh stuff to make the destination the players transform, and always chase after it. I would have expected that each enemy Gameobject would treat the script file as a unique copy for that GO so that when the code self references, i should only apply to the current enemy, but it's clearly applying to both of them. this seams to lead to one enemy not having a clue where to go and some other weird things..

    the setup part of the script just uses 'GetComponent' to reference itself.. I'm not sure if i'll fully explained myself clearly but.. hopefully it's something..
     
  2. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    It does.
    Well this is most likely due to shared resources. (Static variables or shared assets such as Materials).


    You'd need to post some code and be more detailed in your issue if you're looking for more help.
     
    Bunny83 likes this.
  3. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    mm.. shouldn't really be too much in the way of shared resources.. textures are unqiue for each enemy, variables are mostly all stored in the scrip file. of course, that is kinda shared but if it's unique to the one it's attached to, it shouldn't be shared.. though the mesh itself, inside the game object, is the same..
     
  4. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Again: Without knowing 'what' you're applying, 'where' and 'how', it's kind of hard to find out more about this issue.
     
  5. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    Ah, sorry.. didn't see the bit which said about the code.

    it's not fantastic code.. I'm not too use to unity and haven't done C in.. some time, but i've attached the Fox_AI script which seams to be the trouble.

    Sorry for the mess in it ^_^
     

    Attached Files:

  6. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Posted Code below. Please use Code-Tags whenever posting code: Using code tags properly - Unity Forum

    Code (CSharp):
    1.  using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Fox_AI : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     Transform _destination;
    9.     static UnityEngine.AI.NavMeshAgent _navMeshAgent;
    10.    
    11.     public float turnSpeed = 20f;
    12.     public float curSpeed=1f;
    13.     public int TargetX;
    14.     public int TargetY;
    15.     public GameObject PlayRef;
    16.     public int DizzyCountdown;
    17.     public LivesCount LivesNum;
    18.     public GameObject GameOverScreen;
    19.     //public VidPlayer VP;
    20.    
    21.     public Fox_AI ScriptThis;
    22.     public UIManager UIScript;
    23.     public Animator play_Animator;
    24.     Animator m_Animator;
    25.     Rigidbody m_Rigidbody;
    26.     AudioSource m_AudioSource;
    27.      Vector3 m_Movement;
    28.      Quaternion m_Rotation = Quaternion.identity;
    29.      Material OriginalFrame;
    30.      Material BlinkFrame;
    31.      int Lives;
    32.    
    33.      public string Colour = "Red";
    34.      public bool Dizzy = false;
    35.     // Start is called before the first frame update
    36.     void Start()
    37.     {
    38.        // _navMeshAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
    39.        // SetDestination();
    40.        m_Animator = GetComponent<Animator>();
    41.        //play_Animator = PlayRef.GetComponent<Animator>();
    42.        m_Rigidbody = GetComponent<Rigidbody>();
    43.        m_AudioSource = GetComponent<AudioSource>();
    44.      
    45.        //Set Inital Target X and Y for testing reasons
    46.        TargetX = 4; //one tile to the Left of the starting position
    47.        TargetY = 5;
    48.        //InvokeRepeating("NEMMove",1,1);
    49.        ScriptThis = (Fox_AI) GetComponent(typeof(Fox_AI));
    50.      
    51.        //Inital colour setup
    52.        //This is because it seams to display the 'default' red fox for a little bit before it flips to the
    53.        //white texture when first encountered in a map
    54.         Material NormalFrame = Resources.Load<Material>("Materials/FoxTex1");
    55.         if (Colour == "Red"){
    56.             NormalFrame = Resources.Load<Material>("Materials/FoxTex1");
    57.         } else if (Colour == "White"){
    58.             NormalFrame = Resources.Load<Material>("Materials/FoxTex2");
    59.         }
    60.         //
    61.         Mesh mesh = GetComponent<Mesh>();
    62.         SkinnedMeshRenderer meshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
    63.         //get info on current Material
    64.         meshRenderer.material = NormalFrame;
    65.     }
    66.     public void Activation()
    67.     {
    68.         _navMeshAgent = PlayRef.GetComponent<UnityEngine.AI.NavMeshAgent>();
    69.         SetDestination();
    70.     }
    71.     void SetDestination()
    72.     {
    73.        // _navMeshAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
    74.         if (_destination != null)
    75.         {
    76.             Vector3 targetVector = _destination.transform.position;
    77.             _navMeshAgent.SetDestination(targetVector);
    78.         }
    79.     }
    80.     // Update is called once per frame
    81.     void FixedUpdate()
    82.     {
    83.         bool Won = play_Animator.GetBool("Won");
    84.         //Debug.Log("Has the Player won? - " + Won);
    85.         bool Dizzy = m_Animator.GetBool("isDizzy");
    86.         if (Won){
    87.             GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
    88.             m_Animator.SetBool("isWon", true);
    89.             //Debug.Log("Foxes won or Lost!");
    90.         } else {
    91.             if (!Dizzy){
    92.               Vector3 targetVector = _destination.transform.position;//PlayRef.transform.position;
    93.               _navMeshAgent.SetDestination(targetVector);
    94.            }
    95.          }
    96.     }
    97.     //Back to title
    98.     void DizzyEnding()
    99.     {
    100.         m_Animator.SetBool("isDizzy", false);
    101.         Material NormalFrame = Resources.Load<Material>("Materials/FoxTex1");
    102.         if (Colour == "Red"){
    103.             NormalFrame = Resources.Load<Material>("Materials/FoxTex1");
    104.         } else if (Colour == "White"){
    105.             NormalFrame = Resources.Load<Material>("Materials/FoxTex2");
    106.         }
    107.         //
    108.         Mesh mesh = GetComponent<Mesh>();
    109.         SkinnedMeshRenderer meshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
    110.         //get info on current Material
    111.         meshRenderer.material = NormalFrame;
    112.         GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = true;
    113.        
    114.     }
    115.      void OnTriggerEnter(Collider other)
    116.     {
    117.         if (other.tag == "Player")
    118.         {
    119.             if(m_Animator.GetBool("isDizzy") == false){
    120.             GameObject Play = GameObject.Find("Kinky_Player");
    121.             PlayerMovement PM = Play.GetComponent<PlayerMovement>();
    122.             PM.Pause = true;
    123.             Lives = LivesNum.Lives;
    124.                 if (PM.PowerUpTime > 0){
    125.                     Debug.Log("Kinky Power!");
    126.                     //Play video of Kinky on Red Fox
    127.                     if (Colour == "Red"){
    128.                         VidPlayer.LoadVideo("KinkyOnRedFox");
    129.                     } else if (Colour == "White"){
    130.                         VidPlayer.LoadVideo("KinkyOnWhiteFox");
    131.                     }
    132.                 } else {          
    133.                     if (Lives > 0){
    134.                     if (Colour == "Red"){
    135.                         VidPlayer.LoadVideo("RedFoxOnKinky");
    136.                     } else if (Colour == "White"){
    137.                         VidPlayer.LoadVideo("WhiteFoxOnKinky");
    138.                     }
    139.                         LivesNum.Lives -=1;
    140.                     } else {
    141.                           //GameOver
    142.                           GlobalVars.BGM.Stop();
    143.                           Time.timeScale = 0;
    144.                           UIScript.showGOv();
    145.                           //GameOverScreen.SetActive(true);
    146.                          
    147.                     }
    148.                     //Play video of Red Fox on Kinky
    149.                     //Minus 1 to Kinky 'lifes'
    150.                     //check to see if more then 0 lives left
    151.               }
    152.               Debug.Log("Fox Hits Player!");
    153.               m_Animator.SetBool("isDizzy",true);
    154.               Material DizzyFrame = Resources.Load<Material>("Materials/FoxTexDizzy");  
    155.               if (Colour == "Red"){
    156.                   DizzyFrame = Resources.Load<Material>("Materials/FoxTexDizzy");
    157.                 } else if (Colour == "White"){
    158.                   DizzyFrame = Resources.Load<Material>("Materials/FoxTex2Dizzy");
    159.                 }
    160.               //
    161.               Mesh mesh = GetComponent<Mesh>();
    162.               SkinnedMeshRenderer meshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
    163.               //get info on current Material
    164.               meshRenderer.material = DizzyFrame;
    165.               GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
    166.               Invoke("DizzyEnding",6f);
    167.             }
    168.         }
    169.     }
    170.    
    171.     void NEMMove()
    172.     {
    173.     //Function to move a NEM Character
    174.     //first work out where on the grid the NEM is
    175.         Vector3 NEMPos = transform.position;
    176.         float NEMX = NEMPos.x;
    177.         float NEMY = NEMPos.z;
    178.         float TileX = 0;
    179.         float TileY = 0;
    180.         Vector3 currentAngle;
    181.         //That above bit should get the X and Y (z) values for the NEM position
    182.         //now to calculate the tile position
    183.         //I think tile 'cubes' are 10x10 now..
    184.        // Debug.Log("X =" + NEMX);
    185.         if(((NEMX%10-5) == 0) && ((NEMY%10)-5 == 0)){
    186.             TileX = Mathf.Floor((NEMX-5)/10)+1;
    187.             TileY = Mathf.Floor((NEMY-5)/10)+1;
    188.             Debug.Log("Current X = " +TileX);
    189.             Debug.Log("Current Y = " +TileY);
    190.           //  Debug.Log("On the Tile!");
    191.         } else {
    192.             //Something else?
    193.             //Debug.Log("Not on the tile?!?");
    194.         }
    195.         if (TargetX == TileX && TargetY == TileY){
    196.             //NEM has arrived at TargetX and TargetY tile
    197.             Debug.Log("On Target");
    198.             //Calulate new TargetX and TargetY
    199.         }
    200.         //Need to get Current Rotation of Character
    201.         currentAngle = transform.localEulerAngles;
    202.         //Debug.Log(currentAngle.z);
    203.         if (currentAngle.y == 0){
    204.             if (TargetY > TileY){
    205.                 //if the NEM is currently Down from the Target Tile
    206.                 m_Rigidbody.velocity = transform.forward * curSpeed;
    207.                 // transform.forward(curSpeed);
    208.                 //Move forward by the current Speed
    209.                 Debug.Log("Forward!");
    210.             }
    211.             if (TargetX < TileX){
    212.                 transform.localEulerAngles = new Vector3(currentAngle.x,270,currentAngle.z);
    213.                 Debug.Log(transform.localEulerAngles.y);
    214.                 //turn West
    215.             } else if (TargetX > TileX){
    216.                 transform.localEulerAngles = new Vector3(currentAngle.x,90,currentAngle.z);
    217.                 Debug.Log(transform.localEulerAngles.y);
    218.                 //turn East
    219.             }
    220.         } else if (currentAngle.y == 90){
    221.             if (TargetY < TileY){
    222.                 //Turn South
    223.                 transform.localEulerAngles = new Vector3(currentAngle.x,180, currentAngle.z);
    224.                 Debug.Log(transform.localEulerAngles.y);
    225.             } else if (TargetY > TileY){
    226.                 //Turn North
    227.                 transform.localEulerAngles = new Vector3(currentAngle.x,0, currentAngle.z);
    228.                 Debug.Log(transform.localEulerAngles.y);
    229.             }
    230.             if (TargetX > TileX){
    231.                 m_Rigidbody.velocity = transform.forward * curSpeed;
    232.                 Debug.Log("Forward!");
    233.             }
    234.         } else if (currentAngle.y == 180){
    235.             if (TargetY < TileY){
    236.                 m_Rigidbody.velocity = transform.forward * curSpeed;
    237.                 Debug.Log("Forward!");
    238.             }
    239.             if (TargetX < TileX){
    240.                 //Turn West
    241.                 transform.localEulerAngles = new Vector3(currentAngle.x,270,currentAngle.z);
    242.                 Debug.Log(transform.localEulerAngles.y);
    243.             } else if (TargetX > TileX){
    244.                 //Turn East
    245.                 transform.localEulerAngles = new Vector3(currentAngle.x,90,currentAngle.z);
    246.                 Debug.Log(transform.localEulerAngles.y);
    247.             }
    248.         } else if (currentAngle.y == 270){
    249.             if (TargetY > TileY){
    250.                 //Turn South
    251.                 transform.localEulerAngles = new Vector3(currentAngle.x,0,currentAngle.z);
    252.                 Debug.Log(transform.localEulerAngles.y);
    253.             } else if (TargetY < TileY){
    254.                 //Turn North
    255.                 transform.localEulerAngles = new Vector3(currentAngle.x, 180,currentAngle.z);
    256.                 Debug.Log(transform.localEulerAngles.y);
    257.             }
    258.             if (TargetX < TileX){
    259.                 m_Rigidbody.velocity = transform.forward * curSpeed;
    260.                 Debug.Log("Forward!");
    261.                 //move forward by current speed
    262.             }
    263.         }
    264.     }
    265. }
     
    Bunny83 likes this.
  7. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    Frank was right on the money: you've used the static modifier when declaring the _navMeshAgent variable.

    Static members are associated with the type itself, rather than a specific instance of the type. So, there is only one _navMeshAgent, and everyone is trying to share it.

    Perhaps you did this because you wanted to be able to access the agent from other places? Even then, it would make a lot more sense to grab the agent from a specific enemy, I suspect!
     
  8. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Some things I can see here:
    public Fox_AI ScriptThis;
    Completely useless, as it's simply a self-reference. If you already have the object, finding 'itself' is kind of pointless..

    static UnityEngine.AI.NavMeshAgent _navMeshAgent;
    This NavMeshAgent is static, and thus shared across all instances of Fox_AI. Not sure if intended? (though I think it might be seeing how SetDestination is set up).

    Material X = Resources.Load<Material>()
    I believe this will load the exact same Material-Instance every time. Changes applied to any of them will apply to all. You might want to do a
    new Material(Resources.Load<Material>())
    instead.
     
    Kurt-Dekker and chemicalcrux like this.
  9. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    Ugh.. okay.. I see now ^_^ thanks. I'll do some changes and see what happens.

    also.. yeah.. I'm used to only posting code snippets via code tags on forums, more then large blocks of code.. WIll remember for future use, thanks
     
  10. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    mm.. removed that static bit for the _navMeshAgent setup.. when there is one enemy, it's fine.. but when there is two.. they kinda seam to want to run away from the player.. weird..
     
  11. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,382
    Try playing with the avoidance priority on your navmesh agents. Try lowering one but not the other. Also, make sure your navmesh is up-to-date and doesn't need to be re-baked.
     
  12. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    okay. Problem i have with the baking stuff is it's a dynamically build maze.. after the level is generated with the walls/blocks on the surface, i do run the BuildNavMesh function and that seams to set it up fine.
    Anyway.. I'll try tweaking the avoidence thing, though personally, doesn't really matter much if enemies hit each other..
     
  13. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    ah ha.. yeah.. reducing one's priority gets that one working, but then the other one won't do much cause of the other's priority being lower then it.. mm.. and can't have them both with the same priority.. atleast i know what the problem is now, I can try to look into that. thanks ^_^
     
  14. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,382
    You can set the avoidance priority of both of them to the same amount too, if you want. I was just worried they'd stuck, depending on your level geometry. Imagine two people trying to get on the bus at the same time and they won't fit through the door. One person will always stop and let the other person go first so it's never really a problem.

    You can also set them both to not avoid each other at all, but then they may cluster-up.
     
  15. Tempy111

    Tempy111

    Joined:
    Apr 26, 2021
    Posts:
    32
    mm.. interesting.. when both at 50, they seamed to avoid..

    I found the problem though.. ¬_¬ radius.. for some.. reason things are a bit small but either way, the radius for object avoidance seamed to be the problem which kept the enemies too far apart. all fixed now ^_^

    thanks.