- Home /
NullReferenceException. GetComponent dose not work properly
Hi, i am kind of new to Unity and i ran into a problem. I think part of the problem is that GetComponent dosent work the way it should be .
There are 2 Classes that inherit my MoveObjekt Class, those two are the Enemy and the Player Class. For the enemys the script works (to a certain extent) , but if it is used by the player the start funktion does not seem to get my components.
I am getting the following error , each time i press a key to move the player: NullReferenceException: Object reference not set to an instance of an object MovingObjekt.move (Int32 xDir, Int32 yDir, UnityEngine.RaycastHit2D& hit) (at Assets/Scripts/MovingObjekt.cs:42) MovingObjekt.attemptMove[Wall] (Int32 xDir, Int32 yDir) (at Assets/Scripts/MovingObjekt.cs:87) Player.attemptMove[Wall] (Int32 xDir, Int32 yDir) (at Assets/Scripts/Player.cs:38) Player.Update () (at Assets/Scripts/Player.cs:77)
Here are my C# scripts that i think are involved in the problem:
GameManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public float turnDelay = .1f;
public static GameManager instance = null;
public BoardManager boardScript;
public int playerFoodPoints = 100;
[HideInInspector]
public bool playersTurn = true;
public int level = 3;
private List<Enemy> enemies;
private bool enemiesMoving;
private void Awake()
{
Debug.Log("inside gamemanager awake\n");
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
enemies = new List<Enemy>();
boardScript = GetComponent<BoardManager>();
initGame();
}
void initGame()
{
enemies.Clear();
boardScript.setupScene(level);
}
// Update is called once per frame
void Update()
{
if (playersTurn || enemiesMoving)
{
return;
}
StartCoroutine(moveEnemies());
}
public void addEnemyToList(Enemy script)
{
enemies.Add(script);
}
public void gameOver()
{
enabled = false;
}
IEnumerator moveEnemies()
{
enemiesMoving = true;
yield return new WaitForSeconds(turnDelay);
if (enemies.Count == 0)
{
yield return new WaitForSeconds(turnDelay);
}
for (int i = 0; i < enemies.Count; i++)
{
enemies[i].moveEnemy();
yield return new WaitForSeconds(enemies[i].moveTime);
}
playersTurn = true;
enemiesMoving = false;
}
}
MovingObjekt script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public abstract class MovingObjekt : MonoBehaviour
{
public float moveTime = 0.1f;
public LayerMask blockingLayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start()
{
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
Debug.Log("rb2D:" + rb2D + "\n");
Debug.Log("boxCollider:" + boxCollider + "\n");
}
protected bool move(int xDir, int yDir, out RaycastHit2D hit)
{
Debug.Log("in move funktion\n");
Vector2 start = transform.position;
Vector2 end = start + new Vector2(xDir, yDir);
if (boxCollider != null)
{
Debug.Log("in move. boxcollider:" + boxCollider + "\n");
}
if (rb2D != null)
{
Debug.Log("in move. rb2D:" + rb2D + "\n");
}
//deactivate the boxcollider of the moving objetkt so that the linecast will not collide with the objekt it self
boxCollider.enabled = false;
Debug.Log("boxcollider enabled inside move??" + boxCollider.enabled + "\n");
//linecast casts an imaginary line between 2 points and checks if there is a collision on the set line
//hit will store informations about the objekt that collided with the linecast
hit = Physics2D.Linecast(start, end, blockingLayer);
boxCollider.enabled = true;
//hit.transform is null if the raycast didnt collide on the blockingLayer
if (hit.transform == null)
{
//start to move the objekt towards its destination
StartCoroutine(smoothMovement(end));
return true;
}
//if the linecast did detect a collision
return false;
}
protected IEnumerator smoothMovement(Vector3 end)
{
//calculate the remaining distance between the start position and the end position
float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
//moves the objekt towards its destination(end) . float.Epsilon has a value near 0.
while (sqrRemainingDistance > float.Epsilon)
{
//calculates the new position for the movement towards its destination(end)
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
//moves the Rigidbody2D to its new Position
rb2D.MovePosition(newPosition);
//calculate the new remaining distance between the objekts Rigidbody2D and its destination(end)
sqrRemainingDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected virtual void attemptMove<T>(int xDir, int yDir)
where T : Component
{
Debug.Log("inside movingobjekt.player.attemtmove\n");
//if the move funktion is detecting a collision , the information about the collision objekt is stored in the hit variable
RaycastHit2D hit;
bool canMove = move(xDir, yDir, out hit);
//no collision detected
if (hit.transform == null)
{
return;
}
T hitComponent = hit.transform.GetComponent<T>();
if (!canMove && hitComponent != null)
{
onCantMove(hitComponent);
}
}
protected abstract void onCantMove<T>(T component)
where T : Component;
}
Player script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MovingObjekt
{
//damage the player deals to a wall on a single chop
public int wallDamage = 1;
//food points the player gains by picking up food
public int pointsPerFood = 10;
public int pointsPerSoda = 20;
public float restartLevelDelay = 1f;
private Animator animator;
private int food;
// Use this for initialization
protected override void Start()
{
animator = GetComponent<Animator>();
food = GameManager.instance.playerFoodPoints;
}
private void OnDisable()
{
GameManager.instance.playerFoodPoints = food;
}
protected override void attemptMove<T>(int xDir, int yDir)
{
Debug.Log("player.attemtmove" + food + "\n");
food--;
base.attemptMove<T>(xDir, yDir);
RaycastHit2D hit;
checkIfGameOver();
GameManager.instance.playersTurn = false;
}
private void checkIfGameOver()
{
if (food <= 0)
{
GameManager.instance.gameOver();
}
}
// Update is called once per frame
void Update()
{
if (!GameManager.instance.playersTurn)
{
return;
}
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw("Horizontal");
vertical = (int)Input.GetAxisRaw("Vertical");
//prevent diagonal movement
if (horizontal != 0)
{
vertical = 0;
}
if (horizontal != 0 || vertical != 0)
{
attemptMove<Wall>(horizontal, vertical);
}
}
protected override void onCantMove<T>(T component)
{
Wall hitWall = component as Wall;
hitWall.damageWall(wallDamage);
animator.SetTrigger("playerChop");
}
private void restart()
{
Application.LoadLevel(Application.loadedLevel);
}
public void loseFood(int loss)
{
animator.SetTrigger("playerHit");
food -= loss;
checkIfGameOver();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Exit")
{
Invoke("restart", restartLevelDelay);
enabled = false;
}
else if (other.tag == "Food")
{
food += pointsPerFood;
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
food += pointsPerSoda;
other.gameObject.SetActive(false);
}
}
}
Enemy script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MovingObjekt
{
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipMove = true;
// Use this for initialization
protected override void Start()
{
GameManager.instance.addEnemyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
base.Start();
}
protected override void attemptMove<T>(int xDir, int yDir)
{
if (skipMove)
{
skipMove = false;
return;
}
base.attemptMove<T>(xDir, yDir);
skipMove = true;
}
public void moveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
{
//short form of an if{}else{}
yDir = target.position.y > transform.position.y ? 1 : -1;
}
else if (Mathf.Abs(target.position.y - transform.position.y) < float.Epsilon)
{
xDir = target.position.x > transform.position.x ? 1 : -1;
}
//move in the general direktion towards the player
attemptMove<Player>(xDir, yDir);
}
protected override void onCantMove<T>(T component)
{
Player hitPlayer = component as Player;
animator.SetTrigger("EnemyAttack");
hitPlayer.loseFood(playerDamage);
}
}
Thanks in advance :) , i hope i posted enough information to solve this problem.
Hi, does the gameObject have a BoxCollider2D Component attached? If not, then you should change
boxCollider = GetComponent<BoxCollider2D>();
to
boxCollider = AddComponent<BoxCollider2D>();
Yes both prefabs do have a Rigidbody2D and a BoxCollider2D attached.
Answer by Stefan97 · Aug 03, 2017 at 08:40 PM
Ok , i got it now xD. I forgot to call the base start funktion in my player script so the components wount be referenced in the variable , thats why im getting a null pointer .
Problem solved. But any way thanks for your help guys :)
Answer by cgarossi · Aug 03, 2017 at 11:34 AM
if(hit.transform == null)
try
if(hit == null)
instead. You can't talk to a transform if it's parent is null.
No that is not the case. It gives a warning that says something like : the result is always false. But i found this on google:
RaycastHit2D hit;
hit = Physics2D.Linecast(start, end, blockingLayer);
if (hit)
this should work, but dose not solve my problem with the player not moving.