1
\$\begingroup\$

I'm new to Unity and I've made a game in which I can make the levels using prefabs quickly, but I found that making Enemies in prefabs isn't a good idea because they can't follow or interact with the player. What is the best way to make Enemies spawn as soon as the level generates without having to individually create every single one?

Player Code (or at least the instance variables without the methods):

public class PlayerPhys : MonoBehaviour
{
[SerializeField] private float m_JumpForce = 400f;                          
[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f;          
[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f;
[SerializeField] private bool m_AirControl = true;                         
[SerializeField] private LayerMask m_WhatIsGround;                          
[SerializeField] private Transform m_GroundCheck;                           
[SerializeField] private Transform m_CeilingCheck;                          
[SerializeField] private Collider2D m_CrouchDisableCollider;                

const float k_GroundedRadius = .2f;
private bool m_Grounded;
const float k_CeilingRadius = .2f;
private Rigidbody2D m_Rigidbody2D;
private bool m_FacingRight = true;
private Vector3 m_Velocity = Vector3.zero;

[Header("Events")]
[Space]

public UnityEvent OnLandEvent;

[System.Serializable]
public class BoolEvent : UnityEvent<bool> { }

public BoolEvent OnCrouchEvent;
private bool m_wasCrouching = false;

private Animator m_Anim;

Transform playerGraphics;

Enemy prefab code I have so far:

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

public class EnemyAttack : MonoBehaviour
{
    public int health = 1;

    // Update is called once per frame
    void Update()
    {
        // Destroy this if killed
        if (health <= 0)
        {
            Destroy(gameObject);
        }
    }

    // Take damage
    public void TakeDamage(int damage)
    {
        health -= damage;
    }
}

I used this Brackeys tutorial to create levels, and all I'm confused about is how I can make it so that the level creator can create enemies which can interact with the player. I wish he went over how he made prefabricated coins able to be picked up by the player

\$\endgroup\$
12
  • 2
    \$\begingroup\$ What would prevent your enemies in prefabs from following or interacting with the player? That sounds like the root issue we should sort out. \$\endgroup\$
    – DMGregory
    Jun 1 at 18:53
  • \$\begingroup\$ Agree with DMG... sounds like a good use of prefabs to me. \$\endgroup\$
    – Almo
    Jun 1 at 18:56
  • \$\begingroup\$ why they not following / interacting with player? How are you making enemies now? \$\endgroup\$
    – ShoulO
    Jun 1 at 19:27
  • \$\begingroup\$ I'm guessing the enemies need a reference to the player object, and ScratchEnjoyer isn't sure how to assign that reference automatically either on start-up or when instantiating the prefab in the scene. It's hard to know for sure unless they edit their question to give us more details though. \$\endgroup\$
    – DMGregory
    Jun 1 at 19:48
  • \$\begingroup\$ @ScratchEnjoyer are you using tags? they are very useful in detecting who is player, who is enemy.. \$\endgroup\$
    – ShoulO
    Jun 1 at 20:15
1
\$\begingroup\$

To get a reference to the player. I normally add to my scene an empty game-object called 'GAME_MANAGER' or similar. Attach to this a script with similar name GameManager.cs for example.

Inside GameManager.cs there are several ways we can get a reference to the player in the scene. Personally I like to spawn (ie. gameObject.Instantiate(playerPrefab)) the player in the GameManager. But I'll assume you have your player dragged into the scene so you don't have any reference. Well one way to make a reference to the existing player in the scene is to use Find (https://docs.unity3d.com/ScriptReference/GameObject.Find.html)

Here is a little example code:

GameManager.cs

public class GameManager : MonoBehaviour
{
     PlayerPhys Player;

     void Start()
     {
         Player = GameObject.Find("EXACT PLAYER NAME").GetComponent<PlayerPhys>();
           
         // A different way is to FindObjectByType, it will return the first object it finds with a PlayerPhys component attached 
         Player = FindObjectOfType<PlayerPhys>();
     }
     
     
}

I also make my GameManager class a singleton. https://refactoring.guru/design-patterns/singleton/csharp/example

This way you can easily use this player reference from other scripts for example your enemies.

A very quick intro of how to make GameManager.cs into a singleton is as follows:

public class GameManager : MonoBehaviour
{
     public static GameManager singleton_instance;
     public PlayerPhys Player;

     void Start()
     {
         if (singleton_instance == null)
             singleton_instance =  this;
         else
             Destroy(this);
         Player = GameObject.Find("EXACT PLAYER NAME").GetComponent<PlayerPhys>();
     }
     
     
}

Disclaimer: I am not an expert. Just a indie game dev wannabe you has picked up tricks as I go. Others here can give much more technical and precise help/advice. That said if you have questions about what I wrote here, I will do my best to answer for you.

EDIT: An example of finding the player from within another script such as Enemy.cs:

public class Enemy : MonoBehaviour
{
     void Update()
     {
          // ensure 'Player' in GameManager.cs is declared as public
          Vector3 player_position = GameManager.singleton_instance.Player.tranform.position;
     }
}
\$\endgroup\$
11
  • \$\begingroup\$ So what you're saying (summed up) is, I should create a Game Manager which is of type singleton, so that any object in the game can use it for reference? Can you give me an example line of code that I could write within the Enemy prefab code that would be able to obtain the Player variable from GameManager? \$\endgroup\$ Jun 3 at 3:12
  • \$\begingroup\$ Sure. I've updated my answer. Hope it helps. If you get stuck ask some more and I will try to help (I'll be back online tomorrow) \$\endgroup\$ Jun 3 at 3:29
  • \$\begingroup\$ My God you are a life saver. Thank you so much! \$\endgroup\$ Jun 3 at 3:57
  • \$\begingroup\$ you're very welcome. It's nice for me to be the one helping someone here rather than the other way round every time :D \$\endgroup\$ Jun 3 at 13:21
  • \$\begingroup\$ technically I think we haven't created a GameManager 'of type' singleton. What we did was add a public static reference to itself. It is of type GameManager. Also you will want to make sure you only ever have one GameManager which persists though all scenes. Don't really want to have this spawning on every scene you make. But just keep playing and learning and when you get stuck again try to ask here another concise question about that specific problem if/when they arise. Happy coding! \$\endgroup\$ Jun 3 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.