Halil Cosgun
Halil Cosgun

Reputation: 425

Detecting an object with Raycast2D

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);

        }

Upvotes: 4

Views: 17266

Answers (4)

Emisael Carrera
Emisael Carrera

Reputation: 687

Thanks @анонимно, your answer works pretty good for me, I just was needing to hit a ray with the mousePosition and know if this position hits with some 2D gameObject, such as an sprite.

I'm calling this hit in OnMouseUp() method.

void OnMouseUp(){
    RaycastHit2D ray = Physics2D.GetRayIntersection(Camera.main.ScreenPointToRay(Input.mousePosition));

    if (ray)
    {
        GameObject hittedGameObject = ray.collider.gameObject;

        // Do something else

    }
}

Upvotes: 0

анонимно
анонимно

Reputation: 1

OK! i check all internet, and none understand what people really needs when talking abour raycast2D, i finally find what they need, take, and be happy )) ill try post answer to everywhere so people can easy find it if its need. From camera screen to 2D sprite, sprite should be with any collider, rigidbody on sprite not need.

//create 2 empty places for objects

public RaycastHit2D hit;
public GameObject choosen;

//in update put click on mouse //take Method play by clicking mouse

void Update(){
if (Input.GetKeyDown (KeyCode.Mouse0)) {
    RayCaster ();
    }
}

// create raycast Method

void RayCaster (){
    RaycastHit2D ray = Physics2D.GetRayIntersection(Camera.main.ScreenPointToRay (Input.mousePosition));//making ray and object, taking mouse position on screen from camera
    if(!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject (-1)) {
        if (ray.collider != null) {// for non error, check maybe you hit none collider sprite
            hit = ray;// not hit is our obj from scene, but we cant work with it as an object
            choosen = hit.transform.gameObject;// making hit obj as normal object, now we can work with it like with 3Dobject, not as sprite
        }
    }
}

Then work with choosen obj.

Put script on camera, now everyone will be happy, couse in internet even unity3D community not understand what people really needs with raycast2D, hope maybe in future they will make this function easier ))

Upvotes: 0

Max Yankov
Max Yankov

Reputation: 13277

With the new UI system, you don't have to handle clicks manually like this anymore. Just implement IPointerClickHandler on your MonoBehaviour, and ensure that there's EventSystem and PhysicsRaycaster present in the scene.

Upvotes: 1

rutter
rutter

Reputation: 11452

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.

Upvotes: 7

Related Questions