Having issues with transform.Find();

Good Morning

I have this infiltrator enemy in my game that when the player is in range it teleports to a Game Object behind my player. Everything works great when all of my references are filled out. But I have another enemy in my game that summons other enemies to the scene. So when the summoner enemy summons an instantiated infiltrator it is broken. This is because when it is instantiated the Stealth Attack area and the follow this object references are empty.
Here is a picture of the inspector of instantiated Infiltrator

So I know what I need to do, I need to make it so that transforms for Follow This Object and Stealth Attack Area and Player are initialized in the Start(); I feel looked up the correct method to do this, and that is using transform.Find. When I tried this I broke my infiltrator enemy. Here is the code relevant to the problem.

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

using System;

public class InfiltratorStateMachine : MonoBehaviour
{
    private enum InfiltratorStates
    {
        PATROL,
        ATTACK,
        STEALTH,
        TAKE_DAMAGE
    }

    //Exposed Variables
    //----------------------------------------------------------------------

    [SerializeField]
    private Transform sightStart;

    [SerializeField]
    private Transform wallEnd;

    [SerializeField]
    private Transform attackStart;

    [SerializeField]
    private Transform sightEnd;

    [SerializeField]
    private Transform stealthStart;

    [SerializeField]
    private Transform player;

    [SerializeField]
    private Transform stealthAttackArea;

    [SerializeField]
    private LayerMask detectWhat;

    public GameObject[] PickupTypes;

    public GameObject sword;

    public GameObject stealthSword;

    public GameObject followThisObject;

    public GameObject infilitratorTeleport;

    public GameObject Player;

    public GameObject parentDeath;

    public Animator swordAttack;

    public Animator stealthSwordAttack;

    public bool colliding;

    public bool startAttack;

    public bool startStealth;

    public bool facingRight;

    public bool inStealth;

    public float moveSpeed = 5.0f;

    public float stealthTimer = 0.0f;

    public float alphaTimer = .5f;
    //----------------------------------------------------------------------

    //Private Variables
    //----------------------------------------------------------------------
    Infiltrator theEnemy;

    private InfiltratorStates curState;

    int layerMask = 8 << 9;

    private bool hasBeenHit = false;

    Dictionary<InfiltratorStates, Action> fsm = new Dictionary<InfiltratorStates, Action>();


    //----------------------------------------------------------------------
	// Use this for initialization
	void Start ()
    {
        theEnemy = GetComponent<Infiltrator>();

        //Need to fix the transform references for aerial fight and infiltrator https://docs.unity3d.com/ScriptReference/Transform.Find.html
        Player = GameObject.Find("PlayerParent/Player/stealthStrike");
    //This Line breaks my Infiltrator
    Player = followThisObject.transform.Find("PlayerParent/Player/stealthStrike").gameObject;
    //
        facingRight = true;

        inStealth = false;

        fsm.Add(InfiltratorStates.PATROL, PatrolState);

        fsm.Add(InfiltratorStates.STEALTH, StealthState);

        fsm.Add(InfiltratorStates.ATTACK, AttackState);

        fsm.Add(InfiltratorStates.TAKE_DAMAGE, DamageState);

        SetState(InfiltratorStates.PATROL);


	}
	
	// Update is called once per frame
	void Update ()
    {
        fsm[curState].Invoke();
	}

    //Helper Functions
    //----------------------------------------------------------------------
    void SpawnPickup()
    {
       int randIndex = UnityEngine.Random.Range(0, PickupTypes.Length);

       Instantiate(PickupTypes[randIndex], transform.position, transform.rotation);

    }

    void OnTriggerEnter2D(Collider2D col)
    {
        if(col.tag == "PlayerProjectile")
        {
            SetState(InfiltratorStates.TAKE_DAMAGE);
            Destroy(col.gameObject);
        }

        if(col.tag == "PlayerSaber")
        {
            SetState(InfiltratorStates.TAKE_DAMAGE);
        }
    }

    void Vision()
    {
        startAttack = Physics2D.Linecast(sightStart.transform.position, attackStart.transform.position, 1 << LayerMask.NameToLayer("Player"));

        startStealth = Physics2D.Linecast(sightStart.transform.position, stealthStart.transform.position, 1 << LayerMask.NameToLayer("Player"));

        if(startAttack == true)
        {
            SetState(InfiltratorStates.ATTACK);
            //sword.SetActive(true);

            if (startStealth == true)
            {
                SetState(InfiltratorStates.STEALTH);
                sword.SetActive(false);
                //stealthSword.SetActive(true);
            }
        }
        else
        {
            SetState(InfiltratorStates.PATROL);
            sword.SetActive(false);
            stealthSword.SetActive(false);
        }

       
        

        
    }

    void Patrol()
    {
        GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);

        colliding = Physics2D.Linecast(sightStart.transform.position, wallEnd.transform.position, detectWhat);

        this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 1.0f);

        if (colliding == true)
        {
            transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y);
            moveSpeed *= -1;
            facingRight = !facingRight;
        }
    }
    //----------------------------------------------------------------------

    //State Functions
    //----------------------------------------------------------------------
    
    void PatrolState()
    {
        Patrol();
        Vision();
    }

    void StealthState()
    {
        Vision();

        //sword.SetActive(false);

        stealthTimer += Time.deltaTime;

        this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 0.1f);

        

        if (stealthTimer >= 3 && inStealth == false)
        {
            inStealth = true;
            this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 0.1f);
           
            Debug.Log("I should be stealth and you cant see me");
            stealthTimer = 0;

            if(inStealth == true)
            {
               // This section of code makes it so that the infiltrator teleports behind the player and then it will become visable then attack otherwise stealth is false
               infilitratorTeleport.transform.position = followThisObject.transform.position;
               this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 1.0f);
               //<Renderer>().material.color = new Color(1, 1, 1, alphaTimer);
               stealthSword.SetActive(true);
               stealthSwordAttack.GetComponent<Animator>().Play("StealthStrike");
               Debug.Log("STEALTH STRIKE!!");
               inStealth = false;


            }

            else
            {
                inStealth = false;
                stealthSword.SetActive(false);
                sword.SetActive(false);
                this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 1.0f);
            }
        }

        else
        {
            //stealthTimer = 0;
            inStealth = false;
            //this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 1.0f, 1.0f, 1.0f);
        }
    }

Am I using “Player = followThisObject.transform.Find(“PlayerParent/Player/stealthStrike”).gameObject;” wrong? Or should I go about this a different way?

Kindly,

Harpoaian

I’d strongly advise against using transform.Find because it is both slow and brittle. Here are two alternatives:


A. Make the reference to the missing transform available as a public static method or property:

In the first version of this, I forgot to add the static _instance, which prevented the code from compiling.

ComponentAttachedToPlayer :  MonoBehaviour {
   [SerializeField] Transform _playerTransform; // Drag the transform into this field in the inspector
   public static Transform Player {
      get {  return _instance._playerTransform;  } // Be careful to include the '_instance' here
   }
}

and then you can make your InfiltratorStateMachine reference the desired transform with ComponentAttachedToPlayer.Player.

You’ll also need to declare and assign the player _instance with something like this:

static ComponentAttachedToPlayer _instance;

void Awake () {
   _instance = this; // assign the current instance of the `ComponentAttachedToPlayer` to a statically available field
}

B. Pass the player reference to the InfiltratorStateMachine when you instantiate a new enemy:

 // In the method where you instantiate the enemy:
GameObject instantiatedEnemy = Instantiate<GameObject>(_enemyPrefab);
InfiltratorStateMachine fsm = instantiatedEnemy.GetComponent<InfiltratorStateMachine>();
fsm.Initialize(_playerTransform);
//...
// In InfiltratorStateMachine:
public void Initialize (Transform player) {
   Player = player;
}

I am still having issues with this I have 3 errors pop up
error CS0029: Cannot implicitly convert type InfiltratorStateMachine' to PlayerStateMachine’
Assets/The Guardian/Scripts/InfiltratorStateMachine.cs(119,8): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
Assets/The Guardian/Scripts/InfiltratorStateMachine.cs(122,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

I did everything that you said am I misunderstanding something? Here is the updated code so you can see.

Kindly,

Harpoaian

Here is the code that is giving issues
InfiltratorStateMachine

public static PlayerStateMachine _instance;

    Dictionary<InfiltratorStates, Action> fsm = new Dictionary<InfiltratorStates, Action>();


	// Use this for initialization
    void Awake()
    {
        if(_instance == null)
        {
             //Line of code giving issue
            _instance = this;
        }
        else
        {
            Debug.LogError("_instance is already defined");
        }
        
    }
	void Start ()
    {
        theEnemy = GetComponent<Infiltrator>();


        Player = GameObject.Find("PlayerParent/Player/stealthStrike");

        //Error Line
       players.Player;

        //Error Line
        players.StealthStrike;

PlayerStateMachine

public static PlayerStateMachine _instance;



	// GameObject Functions
	// Use this for initialization
    private void Awake()
    {
        health.Initialize();
        spiritEnergy.Initialize();
        nexaStones.Initialize();
    }
	void Start () 
	{
        Beserker = GameObject.Find("BeserkerParent/Beserker");
        thePlayer = player.GetComponent<Player>();

        players = player.GetComponent<PlayerStateMachine>();

        chargingDamage = Beserker.GetComponent<BeserkerStatemachine>();


        health.CurrentVal = 100;

        nexaStones.CurrentVal = 0;

        Bullet.GetResetCharge();

        facingRight = true;

        hasWolfFormUnlocked = true;

        inWolfForm = false;

        fsm.Add (PlayerStates.IDLE, StateIdle);
		fsm.Add (PlayerStates.RUN, StateRun);
		fsm.Add (PlayerStates.ENTER_JUMP, StateEnterJump);
		fsm.Add (PlayerStates.IN_AIR, StateInAir);
		fsm.Add (PlayerStates.USE_WEAPON, WeaponFire);
        fsm.Add (PlayerStates.USE_BEAMSABER, BeamSaberAttack);
        fsm.Add(PlayerStates.TAKE_DAMAGE, DamageState);

		SetState (PlayerStates.IDLE);
	}
	
	// Update is called once per frame
	void Update () 
	{

		fsm [curState].Invoke();
        float horizontal = Input.GetAxis("Horizontal");
       
       

    }


	// Helper Functions
   
    
    public static Transform Player
    {
        get
        {
                   
            return _instance._playerTransform;
            
        }
    }

    public static Transform StealthStrike
    {
        get
        {
                    
            return _instance._stealthStrike;
        }
    }