Getting a NullReferenceException when accessing a component that I've created and retrieved - c#

First of all, how original of me to post another dreaded
NullReferenceException: Object reference not set to an instance of an object
but I have scoured the web looking for a solution for like 2 hours now and have come up with nothing... Here is are the two scripts i have :
GROUNDED:
using UnityEngine;
using System.Collections;
public class GroundCheck : MonoBehaviour {
private Player player;
void Start()
{
player = GetComponent<Player>();
}
void OnTriggerEnter2D(Collider2D col)
{
player.grounded = true;
}
void OnTriggerExit2D(Collider2D col)
{
player.grounded = false;
}
}
PLAYER:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
public float maxSpeed = 3;
public float speed = 50f;
public float jumpPower = 150f;
public bool grounded;
private Rigidbody2D rb2d;
private Animator anim;
// Use this for initialization
void Start () {
rb2d = gameObject.GetComponent<Rigidbody2D>();
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
anim.SetBool("Grounded", grounded);
anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis("Horizontal")));
}
void FixedUpdate()
{
float h = Input.GetAxis("Horizontal");
rb2d.AddForce((Vector2.right * speed) * h);
if (rb2d.velocity.x > maxSpeed)
{
rb2d.velocity = new Vector2(maxSpeed, rb2d.velocity.y);
}
if (rb2d.velocity.x < -maxSpeed)
{
rb2d.velocity = new Vector2(-maxSpeed, rb2d.velocity.y);
}
}
}
The exact error is:
NullReferenceException: Object reference not set to an instance of an object
GroundCheck.OnTriggerEnter2D (UnityEngine.Collider2D col)
(atAssets/scripts/GroundCheck.cs:15)
Here is my scene:
Here is my boxcollider (if it helps):

If both of the GroundCheck and PLAYER classes are on same GameObject then change the Start() method of GroundCheck class like this:
void Start()
{
player = gameObject.GetComponent<Player>();
}
If they are not on same GameObject then use the following code:
void Start()
{
GameObject playerObj = GameObject.Find("Name of gameObject that player script is in that");
player = playerObj.GetComponent<Player>();
}
In PLAYER class add static modifier to defination of grounded:
public static bool grounded;

Your ground check script isn't on the same object as the player script, that means you can't use getcomponent to get the player script. So you haven't set the player var to anything which is causing the error. Set the player var to the gameobject that has the player script in the editor then in your start method use player.GetComponent();

void OnTriggerEnter2D(Collider2D col) <-- in collider param request gameObject, getcomponent to col is prefered, only control if object collision is player. col.gameObject.getcomponent<Player>().grounded=true;
if(col.Name.Equals("Player")
{
col.gameObject.getcomponent<Player>().grounded=true;
}
I had a similar problem. I hope it's helps
http://docs.unity3d.com/ScriptReference/Collision2D.html
Collider2d have gameobject component, trigger enter get Collider this object.
in http://docs.unity3d.com/ScriptReference/Collider2D.OnCollisionEnter2D.html
see example use in collider (not trigger is only example) to use, acces gameObject.
Not necessary findtag when object(player) is passing for parameter in event OnTriggerEnter, Exit or Stay

Related

The Object you want to instantiate is null. (Error Unity)

I've tried to fix this problem for many days, looked for every result in a web and didn't get any suitable answers to me...
With this problem I can run my game, but it shows up every time I shoot the bullet prefab.
This is a player shooting script, it shows up a problem when I try to Instatiate(bulletRef);
public GameObject bulletRef;
// Start is called before the first frame update
void Start()
{
bulletRef = Resources.Load("Bullet") as GameObject;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Z))
{
// By pressing the button we create an instance of a bullet
Instantiate(bulletRef);
bulletRef.transform.position = new Vector3(transform.position.x + .4f, transform.position.y + .2f, -1);
}
}
I think that those codes look suspicious to me, maybe the roots of this problem are coming out from them
here is a script for bullet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletScript : MonoBehaviour
{
public float speed = 20f;
public int damage = 1;
public Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb.velocity = -transform.up * speed;
}
private void OnTriggerEnter2D(Collider2D collider)
{
Destruction enemy = collider.GetComponent<Destruction>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
}
This is a script for destroying the bullet. I don't personally think that there is an issue with this code, but it is for you to understand how my bullet dissapears
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Destruction : MonoBehaviour
{
public int health = 1;
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
}
}
void Die()
{
Destroy(this.gameObject);
}
private void OnTriggerEnter2D(Collider2D collision)
{
ScoreManager.instance.AddPoint();
}
}
The problem lies in your Update() method of your first script
Instantiate(bulletRef);
bulletRef.transform.position = new Vector3(transform.position.x + .4f, transform.position.y + .2f, -1);
You are instantiating the gameobject bulletRef but not assigning it to any field. Also, you are changing the position of just a reference to the gameobject you just loaded from the resources. You didn't have a reference to the gameobject in the scene, you have a reference to the gameobject in your resources. To get a reference to the gameobject you just instantiated into your scene, assign the instantiated gameobject to a field. But the function Instantiate returns an Object hence we typecast it to GameObject as
GameObject bulletRefObject = Instantiate(bulletRef) as GameObject;
bulletRefObject.transform.position = new Vector3(transform.position.x + .4f, transform.position.y + .2f, -1);

Unity2D Melee Combat

I'm new to programming and C#. I'm trying to build a melee system for my platform game following tutorials on yt.
This is my PlayerAttack script:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PlayerAttack : MonoBehaviour {
//[SerializeField] private float attackCooldown;
[SerializeField] private float range;
[SerializeField] private int damage;
[SerializeField] private LayerMask enemyLayer;
public Transform AttackPoint;
//private float cooldownTimer = Mathf.Infinity;
private Animator anim;
private Enemy enemyHealth;
private void Awake()
{
anim = GetComponent<Animator>();
enemyHealth = GetComponent<Enemy>();
}
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
anim.SetTrigger("Attack");
Attack();
Debug.Log("attacking");
}
}
private void OnDrawGizmos()
{
if (AttackPoint == null)
return;
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(AttackPoint.position, range);
}
void Attack()
{
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(AttackPoint.position, range, enemyLayer);
foreach (Collider2D Enemy in hitEnemies)
{
Enemy.transform.GetComponent<Enemy>().TakeDamage(damage);
}
}
}
and this one is the EnemyHealth script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] private int startingHealth;
public int currentHealth;
public Animator anim;
void Start()
{
currentHealth = startingHealth;
}
public void TakeDamage(int _damage)
{
currentHealth = Mathf.Clamp(currentHealth - _damage, 0, startingHealth);
if (currentHealth > 0)
{
//hurt animation
//invulnerability
}
else
{
//die animation
GetComponentInParent<EnemyPatrol>().enabled = false;
GetComponent<EnemyMelee>().enabled = false;
}
}
void Die()
{
if (currentHealth <= 0)
{
Debug.Log("Enemy Dead!");
Destroy(gameObject);
//die animation
}
}
}
I'm getting an error from the Unity editor "object reference not set to an instance of an object" on line 61 of the PlayerAttack:
enter code here
Enemy.transform.GetComponent().TakeDamage(damage);
I checked the scripts names and they are fine, and I checked also if I missed something in the editor , I don't know what's wrong.
When I hit the enemy the game crashes and i get this error.
Thanks
You are trying to call Enemy.transform.GetComponent<Enemy>().TakeDamage(damage); on everything that has collider but some of those objects don't have the Enemy component so you can't call TakeDamage on them. That is where the error comes from. To fix it you have to find only the enemy game objects. To do this you can assign tags to your enemy and check the ones with Enemy tag through the script like this:
foreach (Collider2D Enemy in hitEnemies)
{
if (Enemy.tag == "Enemy")
Enemy.transform.GetComponent<Enemy>().TakeDamage(damage);
}
There is another way to do it without tags which I don't recommend:
foreach (Collider2D Enemy in hitEnemies)
{
if (Enemy.transform.GetComponent<Enemy>() != null)
Enemy.transform.GetComponent<Enemy>().TakeDamage(damage);
}
Check if the player has hit the enemy or not:
foreach (Collider2D hitEnemy in hitEnemies) {
if(hitEnemy.TryGetComponent(out Enemy enemy)) {
enemy.TakeDamage(damage);
}
}
Other than the answer:
In your PlayerAttack.cs script, you have a field enemyHealth which you are trying to get a reference to it using enemyHealth = GetComponent<Enemy>(); in your Awake() method. This doesn't get a reference to it because of Enemy.cs and PlayerAttack.cs scripts are attached to different gameobjects.

Unity Sword Collision Attack

Hey guys I want to make a sword attack. But I get the error of:
NullReferenceException: Object reference not set to an instance of an
object
These are my codes:
My weaponattack script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weaponattack : MonoBehaviour
{
Enemy Enemy;
public float power;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnTriggerEnter(Collider col)
{
if(col.tag == "Enemy")
{
var kılıc = GetComponent<Enemy>();
Enemy.currentHealt -= 10;
Enemy.TakeDamage();
Debug.Log("Düşman Vuruldu");
}
}
}
This is my Enemy Health scrpt:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public float currentHealt;
public float maxHealth;
// Use this for initialization
void Start () {
currentHealt = maxHealth;
}
// Update is called once per frame
void Update () {
}
public void TakeDamage()
{
currentHealt -= 10;
if(currentHealt < 0)
{
die();
}
}
void die()
{
Destroy(gameObject);
}
}
Can you helo em I couldnt understan why these codes are not working why am I getting that error.
I think your problem is in this line here GetComponent<Enemy>(); This needs a game object to get the component of
Enemy = col.GetComponent<Enemy>();
Should be what you're doing
You also may have issue calling your variable Enemy exactly the same as your class Enemy, I would change this to Enemy enemy; and
enemy = col.GetComponent<Enemy>();
respectivley
It seems pretty straightforward. You don't assign an Enemy to Weaponattack and so it's barfing when you first reference Enemy (Enemy.currentHealt). Either make Enemy public or a SerializedField so you can assign it in the Inspector, or however else you want to get an Enemy into Weaponattack.
Also don't name your property the same name as your script (Enemy Enemy). Surprised you didn't get a compile error.
EDIT Based on comments:
Enemy enemy;
public void OnTriggerEnter(Collider col)
{
if(col.tag == "Enemy")
{
var kılıc = GetComponent<Enemy>();
kilic.currentHealt -= 10;
kilic.TakeDamage();
Debug.Log("Düşman Vuruldu");
}
}
This also assumes you have an Enemy attached to your Weaponattack (GetComponent)

My Player wont stick to the platform and I can't seem to fin a solution

So I am trying to make the player a child to the moving platform which is being moved by looking for waypoints and going to them. But when I make the player collide with the platform the collision enter is not detecting the player thus not making the player stay on it, it instead glides off.enter image description here
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movePlatform : MonoBehaviour
{
public GameObject[] waypoints;
float rotSpeed;
int current = 0;
public float speed;
float WPradius = 1;
private GameObject target = null;
private Vector3 offset;
public GameObject Player;
CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
//This will make the player a child of the Obstacle
controller.transform.parent = other.gameObject.transform;
}
}
void OnTriggerExit(Collider other)
{
controller.transform.parent = null;
}
// Update is called once per frame
void Update()
{
if (Vector3.Distance(waypoints[current].transform.position, transform.position) < WPradius)
{
current++;
if (current >= waypoints.Length)
{
current = 0;
}
}
transform.position = Vector3.MoveTowards(transform.position, waypoints[current].transform.position, Time.deltaTime * speed);
}
}
This will not make the player a child of the platform:
controller.transform.parent = other.gameObject.transform;
Because here controller is the CharacterController instance, and other refers to the player collider. So they both refers to the player transform in the end.
Replace it by something like
other.transform.parent = transform;
or
controller.transform.parent = transform;
(Here, transform refers to the platform transform.)
If the OnTriggerEnter() is not detecting, check if your collider has isTrigger enabled. Or change the method to OnCollisionEnter().
If you are making a 2D game, switch these methods to the 2D version (=> OnCollisionEnter2D or OnTriggerEnter2D).

How to change a boolean from another script C#

I have 2 script, playerMachanics and enemyBehavior. My enemyBehavior has a boolean that when the boolean is true it moves away from the player. Instead i'm getting the error: "object reference not set to an instance of an object".
I'm sure it means the script can't find the component but i can't quite figure out what's wrong.
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade == true)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = GetComponent<enemyBehavior>();
script.evade = script.evade == true;
}
}
}
I expected that the movementSpeed would go to -4 but now i'm just getting an error.
Calling getComponent by itself will look for the component attached to the parent object of the script, which is the player in this case I think. So it will always return null.
Add
Public GameObject enemy;
to the playerMechanics class and then go into the designer and drag the game object that has the enemyBehavior script attached into it. There are several problems with the onCollisionEnter method. Something like this
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = enemy.GetComponent<enemyBehavior>();
script.evade = false;
}
}
should get you going in the right direction.
Is the enemy behavior on the player object? See here
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
and here
enemyBehavior script = GetComponent<enemyBehavior>();
You need to implement a way to track which enemy instance you are grabbing. Do this by making a variable to hold the enemy script, or by using a singleton on the enemy script (if there is one enemy).
Variable:
public enemyBehaviour enemy;
Singleton:
(enemyBehaviour)
public static enemyBehaviour instance = null;
private static readonly object padLock = new object();
void Awake(){
lock(padLock){
if(instance == null)
instance = this;
}
}
(player)
enemyBehaviour.instance.evade = false;
Look up singletons if you want to learn more.
If I'm right, I think your game mechanics works like this: The player's objective is to collect coins. When they collect one, the enemy near it will come and evade the player.
If that's the case, you should use this:
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
[SerializeField] enemyBehvaior enemy;
void OnCollisionEnter(Collision collision)
{
if (collision.collider.name == "coin")
{
Destroy(collision.collider.gameObject);
enemy.evade = true;
}
}
}
In your code, you wrote 'collision.gameObject.' This refers to the object the script is attached to. If you want to reference to the object that we hit, use 'collision.collider'.
'[SerializeField]' is a unity attribute, which is used to make a field show up in the inspector without making it public.
Just a heads up, if you're using 2D, make sure the method is signatured 'OnCollisionEnter2D(Collision2D collision)'.
I hope I answered your question. :)

Categories

Resources