- Home /
GetComponent from enemy script to player script sometimes works
Hello. Well, this is a long one.
So I'm making my first game, and I'm in the process of making enemy AI, and I had all set up for the movement of the enemies. Before that, I had made the attacking (player -> enemy) script and animations - using attack points and collision detection - and it worked just fine. But now the Attack() function I made for the player sometimes works and other don't (I get a NullReferenceException Error everytime I hit the enemy), apparently It is an error with the GetComponent that brings the enemy script to the player script. Also, I copied a couple of enemies and tried to hit them; the funny thing is, some of them register the attack, other don't, and this seems to be random, because when I restart Unity I can hit some other enemies and other don't (whereas in previous attempts I could hit 'em). I sincerely don't know what I did wrong, because I haven't touched that function since I made it, and its halting my progress. I'd love to get some help with this :(
The Attack() function:
private void Attack()
{
//This indicates that, if the player is being hurt or is falling, he can't perform an attack.
if(!Animator.GetCurrentAnimatorStateInfo(0).IsTag("5") || !Animator.GetCurrentAnimatorStateInfo(0).IsTag("4"))
{
Debug.Log("Enemy damaged");
Animator.SetTrigger("Attack");
Collider2D[] HitEnemies = Physics2D.OverlapCircleAll(AttackPoint.position, AttackRange, EnemyLayers);
foreach(Collider2D Enemy in HitEnemies)
{
//This is precisely where the error occurs. As far as I know, there's nothing wrong with this, and I have everything labelled correctly.
Enemy.GetComponent<EnemyScript>().TakeDamage(AttackDamage);
}
}
}
The Enemy TakeDamage() function:
public void TakeDamage(int Damage)
{
Debug.Log("Enemy recieved damage");
CurrentHealth -= Damage;
Animator.SetTrigger("Hurt");
if(CurrentHealth <= 0)
{
Die();
}
}
For the whole context, the player script:
public class PlayerScript: MonoBehaviour
{
public float Speed = 3.5f;
public float JumpForce;
public Transform AttackPoint;
public LayerMask EnemyLayers;
private int ColliderDamage = 6;
public float AttackRange = 0.5f;
public int AttackDamage = 20;
private Rigidbody2D Rigidbody2D;
private Animator Animator;
private float Horizontal;
private bool Grounded;
public float KnockBack;
public float KnockBackLength;
public float KnockBackCount;
public bool KnockFromRight;
private void Start()
{
Rigidbody2D = GetComponent<Rigidbody2D>();
Animator = GetComponent<Animator>();
}
private void OnCollisionEnter2D(Collision2D Collision)
{
if (Collision.gameObject.tag == "Enemy" || Collision.gameObject.tag == "Hazard")
{
Debug.Log("Collider Damage Taken");
TakeEnemyDamage(ColliderDamage);
}
}
private void Update()
{
if(Animator.GetCurrentAnimatorStateInfo(0).IsTag("2"))
{
Speed = 0.0f;
return;
} else {
Speed = 3.5f;
}
if(Animator.GetCurrentAnimatorStateInfo(0).IsTag("4"))
{
Speed = 0.0f;
return;
} else {
Speed = 3.5f;
}
if(Animator.GetCurrentAnimatorStateInfo(0).IsTag("5"))
{
Speed = 0.0f;
return;
} else {
Speed = 3.5f;
}
Animator.SetFloat("YVelocity", Rigidbody2D.velocity.y);
Horizontal = Input.GetAxisRaw("Horizontal");
if (Horizontal < 0.0f) transform.localScale = new Vector3(-1.0f, 1.0f, 1.0f);
else if (Horizontal > 0.0f) transform.localScale = new Vector3(1.0f, 1.0f, 1.0f);
Animator.SetBool("Run", Horizontal != 0.0f);
Debug.DrawRay(transform.position, Vector3.down * 0.5f, Color.red);
if (Physics2D.Raycast(transform.position, Vector3.down, 0.5f))
{
Grounded = true;
}
else Grounded = false;
Animator.SetBool("Jumping", !Grounded);
if (Input.GetKeyDown(KeyCode.Space) && Grounded)
{
Jump();
Animator.SetBool("Jumping", true);
}
//Here's the call to the attack function. It works fine.
if (Input.GetKeyDown(KeyCode.F))
{
Attack();
}
}
private void Jump()
{
Rigidbody2D.AddForce(Vector2.up * JumpForce);
}
*//This is where the error appears.
private void Attack()
{
//This indicates that, if the player is being hurt or is falling, he can't perform an attack.
if(!Animator.GetCurrentAnimatorStateInfo(0).IsTag("5") || !Animator.GetCurrentAnimatorStateInfo(0).IsTag("4"))
{
Debug.Log("Enemy damaged");
Animator.SetTrigger("Attack");
Collider2D[] HitEnemies = Physics2D.OverlapCircleAll(AttackPoint.position, AttackRange, EnemyLayers);
foreach(Collider2D Enemy in HitEnemies)
{
//This is precisely where the error occurs. As far as I know, there's nothing wrong with this, and I have everything labelled correctly. Enemy.GetComponent<EnemyScript>().TakeDamage(AttackDamage);
}
}
}*
void OnDrawGizmosSelected()
{
if(AttackPoint == null)
return;
Gizmos.DrawWireSphere(AttackPoint.position, AttackRange);
}
private void FixedUpdate()
{
Rigidbody2D.velocity = new Vector2(Horizontal * Speed, Rigidbody2D.velocity.y);
}
}
And the whole Enemy Script:
public class EnemyScript : MonoBehaviour
{
public Animator Animator;
public LayerMask PlayerLayers;
public bool PlayerInArea
{
get;
private set;
}
public Transform Player
{
get;
private set;
}
private string DetectionTag = "Player";
public int MaxHealth = 80;
int CurrentHealth;
void Awake()
{
Animator = GetComponent<Animator>();
}
void Start()
{
CurrentHealth = MaxHealth;
}
public void TakeDamage(int Damage)
{
Debug.Log("Enemy recieved damage");
CurrentHealth -= Damage;
Animator.SetTrigger("Hurt");
if(CurrentHealth <= 0)
{
Die();
}
}
void Die()
{
Debug.Log("Enemy Died");
Animator.SetBool("Death", true);
GetComponent<Collider2D>().enabled = false;
}
private void OnTriggerEnter2D(Collider2D Other)
{
if(Other.gameObject.tag == "Player")
{
var PlayerAp = Other.gameObject.GetComponent<PlayerScript>();
if(Other.transform.position.x < transform.position.x)
{
PlayerAp.KnockFromRight = true;
} else
{
PlayerAp.KnockFromRight = false;
}
if(Other.CompareTag(DetectionTag))
{
Debug.Log("Player in enemy area");
PlayerInArea = true;
Player = Other.gameObject.transform;
}
}
}
private void OnTriggerExit2D(Collider2D Other)
{
if(Other.CompareTag(DetectionTag))
{
Debug.Log("Player exiting enemy area");
PlayerInArea = false;
Player = null;
}
}
}
Answer by awkwardstreamer · Oct 13, 2021 at 05:18 PM
So if im to understand, your saying GetComponent sometimes doesnt work? the only thing i can think of that would cause this is if the script was on a different object than the animator. If were talking about it detecting a collision triggered event you can increase the quality of your collisions to help. but youll be able to see within the first frame if everything is where its supposed to be, Since GetComponent runs in the Start function its only called once right when it becomes active. It be nice to know which line is giving you an error, but id be willing to guess the issue is starting in line of code
if(!Animator.GetCurrentAnimatorStateInfo(0).IsTag("5") || !Animator.GetCurrentAnimatorStateInfo(0).IsTag("4"))
I would seperate this function, so you just have an straight attack function that gets called IF it meets the requirements. cause right now its basically like you tell it to attack but then after tell it to wait to see who it is, which seems convoluted and prone to issue.
Okay, this is weird. I had an older version of the same project, but the whole layout of the objects and parameters are kind of similar. The difference is that, in the newer version, I had the enemy objects inside a parent object (is that what is called?) so now the same script functions all the time, as intended. I suppose something like that messed up with the tags and layers, so now I will work with that version. Either way, thank you for your help!
I have other suspicion: When I reference the tags for the animations, I used for the controllers of both player and enemy the same tags: "0" for idle, "1" for walking, "2" for attack, etc... So maybe when I sayed "if Animator tag "5" (Hurt), then don't enable attack", but in the same function (Attack()) I call the components of the enemy script, possibly calling along the animator controller of the enemy? I don't know, but I need to test this hypothesis.