I'm working on simple strategy game mechanics. I have a Barracks prefab. When I add the Barracks on the scene and click on the Barracks, I receive an NullReferenceException
error:
NullReferenceException: Object reference not set to an instance of an object PlacementController.Update () (at Assets/Scripts/PlacementController.cs:64)
The error is received when I try to reach collider name of the Barracks using Raycast2D.
Barracks prefab has a Box Collider2D collider(trigger is checked) and its tag is "Building" and its layer is "Buildings". It has a rigidbody2D component and it is a kinematic rigidbody.
I can not figure out this problem. Please help me.
Thanks for your time.
using UnityEngine;
using System.Collections;
public class PlacementController : MonoBehaviour
{
private Buildings buildings;
private Transform currentBuilding;
private bool _hasPlaced;
public LayerMask BuildingsMask;
public void SelectBuilding(GameObject g)
{
_hasPlaced = false;
currentBuilding = ((GameObject)Instantiate(g)).transform;
buildings = currentBuilding.GetComponent<Buildings>();
}
bool CheckPosition()
{
if (buildings.CollidersList.Count > 0)
{
return false;
}
return true;
}
// Update is called once per frame
void Update () {
Vector3 m = Input.mousePosition;
m = new Vector3(m.x, m.y, transform.position.z);
Vector3 p = GetComponent<Camera>().ScreenToWorldPoint(m);
if (currentBuilding != null && !_hasPlaced)
{
currentBuilding.position = new Vector3(p.x,p.y,0);
if (Input.GetMouseButtonDown(0))
{
if (CheckPosition())
{
_hasPlaced = true;
}
}
}
else
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = new RaycastHit2D();
Ray2D ray2D = new Ray2D(new Vector2(p.x,p.y), Vector3.down );
//Ray2D ray = new Ray(transform.position,new Vector3(p.x,p.y,p.z));
if (Physics2D.Raycast(new Vector2(p.x,p.y),Vector3.down,5.0f,BuildingsMask) )
{
Debug.Log(hit.collider.name); //error
}
}
}
}
------------------ I am sharing answer, and thanks for your help --------------------
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
RaycastHit2D hit = new RaycastHit2D();
Ray2D ray2D = new Ray2D(new Vector2(p.x,p.y), Vector3.down );
hit = Physics2D.Raycast(new Vector2(p.x, p.y), Vector3.forward, 5.0f, BuildingsMask);
Debug.Log(hit.collider.name);
}
Unity has two physics engines, which are very similar, but this is one area where they are different in a subtle and confusing way.
The 3D engine offers Physics.Raycast
, which returns true
on hit, or false
otherwise, and allows you to pass a RaycastHit
by reference if you need to know more about the hit.
The 2D engine offers Physics2D.Raycast
, which instead returns a RaycastHit2D
on hit, or null
otherwise. The way your code is written, the hit
you access is not the same hit that was returned by the raycast call.
So, you need something closer to this:
RaycastHit2D hit = Physics2D.Raycast(...); //edit in your raycast settings
if (hit) {
//do something with the hit data
}
(You may notice that RaycastHit2D
has an implicit conversion to bool
.)
Unity had only the 3D engine for a long time, so a lot of older documentation will talk as if that's the only one. Watch out for that.