- Home /
Why does Raycast2D always return non-null?
I'm trying to make it so that when you click on an object it executes a function in a script attached to that object (although at the moment I'm simply having it print a string to the console as a test). However, I noticed that no matter where I clicked on the screen it was returning a RaycastHit2D even if there wasn't an object with a collider there. Also, when I would click on an object, the transform, collider, and rigidbody values of the returned RaycastHit2D are null.
Here's my code (the code directly related to the mouse clicking is at the bottom):
using UnityEngine;
using System.Collections;
public class PlayerController : Ghost {
float speedx;
float speedy;
bool dead = false;
[HideInInspector]
public bool faceRight = true;
RaycastHit2D hitobject;
void OnTriggerEnter2D(Collider2D item) {
if (item.gameObject.tag == "possessable") {
item.gameObject.GetComponent<PossessableObject> ().isPossessable = true;
}
}
void OnTriggerExit2D(Collider2D item) {
if (item.gameObject.tag == "possessable") {
item.gameObject.GetComponent<PossessableObject> ().isPossessable = false;
}
}
void Flip ()
{
// Switch the way the player is labelled as facing.
faceRight = !faceRight;
// Multiply the player's x local scale by -1.
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
protected override void OnUpdate() {
speedx = rigidbody2D.velocity.x;
speedy = rigidbody2D.velocity.y;
anim.SetFloat ("Speedx", Mathf.Abs(speedx));
anim.SetFloat ("Speedy", speedy);
anim.SetBool ("Dead", dead);
if (speedx > 0 && !faceRight) {
Flip();
}
else if (speedx < 0 && faceRight) {
Flip();
}
_motor.TargetMoveForceX = 0;
_motor.TargetMoveForceY = 0;
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) {
_motor.TargetMoveForceX = moveForce;
}
else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) {
_motor.TargetMoveForceX = -moveForce;
}
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) {
_motor.TargetMoveForceY = moveForce;
}
else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) {
_motor.TargetMoveForceY = -moveForce;
}
if (Input.GetMouseButtonDown(0)) {
hitobject = Physics2D.Raycast(Input.mousePosition, Vector2.zero);
if (hitobject != null) {
//GameObject hit = hitobject.collider.gameObject;
//print(hit.name);
if (hitobject.collider == null) {
print("yolo");
}
}
/*if(hitobject.transform.gameObject.tag == ("possessable")) {
//hitobject = Physics2D.Raycast(Input.mousePosition, Vector2.zero);
//hitobject.collider.gameObject.GetComponent<PossessableObject> ().possessionEvent();
renderer.enabled = false;
}*/
}
}
}
I'm presu$$anonymous$$g the output is one "yolo" for every click?
Yes. If the ray intersects an object's collider, and the collider associated with the returned raycasthit2d is null, then it outputs a single "yolo". For some reason this always happens no matter where I click.
What you're trying to do doesn't make sense.
First of all, RaycastHit2D is a struct type. This means it is a value type, and thus cannot be null.
But that's not your biggest problem. Your biggest problem is that the case where the Ray hits something, but the collider it has hit is null, will never occur. If a collider is "null", it means, "this collider does not exist". But you just hit that collider, because otherwise the RaycastHit2D wouldn't have returned that result. Therefore, the collider must exist, and therefore the collider in a RaycastHit2D cannot be null if a collision happens.
In fact, if you want to detect if a ray did not hit anything, you check if the collider is null, as the only way this can be the case is if the ray did not intersect a collider.
What you are trying to do doesn't make sense. If you want it to print an output if it's collided with something, then just use:
if (hitobject.collider != null)
{
print("yolo");
}
Similarly if you want it to print the output if it doesn't collide with anything, then use:
if (hitobject.collider == null)
{
print("yolo");
}
It's that simple. You may want to brush up on exactly what null
means, because I'm not sure you know.
In short, all objects that are not primitive types or structs are referenced by pointers to that object. This is just a number that says: "look at this address in memory to find this object". There is a special value, however, which is null
, that means "there is no address pointing to this object", which you can think of as meaning: "this object does not exist".
As per the docs for Physics2D.Raycast
:
This function returns a RaycastHit object when a collider is hit by the ray or null otherwise.
RaycastHit2D
is therefore not a struct
.
I thought the same thing initially, but Physics2D
doesn't follow the same conventions as it's 3d counterpart.
Ah, I must be misinformed (I haven't much experience with the 2D libraries). I found a page saying it was a struct. You are correct that the direction vector is probably the issue.
I read the docs too, but must have skipped over that line by accident. I'll convert it to a comment myself.
Your problem is that you're using Vector2.zero
as your direction vector. You can't have a ray going nowhere. $$anonymous$$athematically that would create all sorts of infinities in ray-line intersection tests.
I changed the the Vector.zero as suggested, and chose Vector.up, but the results were exactly the same. Following something I saw on a forum thread, I changed the actual raycasting to:
`Physics2D.Raycast(new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x,Camera.main.ScreenToWorldPoint(Input.mousePosition).y), Vector2.zero, 0f);`
While eli$$anonymous$$ating the problems that led me to create this question, this causes the ray to be cast from the camera ins$$anonymous$$d of the origin given it (always returning a hit on my Player object, as the camera follows the Player). This results in a completely different problem of not being able to cast where it needs to. I might decide to go with a different approach I've found to work for my purposes unless someone has a solution to this new issue.
Answer by idbrii · Sep 27, 2014 at 03:17 PM
@Hoeloe is correct that RaycastHit2D is a struct so it's a value type. From the Physics2D.Raycast documentation:
This function returns a RaycastHit object with a reference to the collider that is hit by the ray (the collider property of the result will be NULL if nothing was hit).
(It looks like the documentation has been updated since @Benproductions1's comment.)
Being a value type means it can never be null. If you compare it to null, you'll get a warning like this:
warning CS0472: The result of comparing value type `UnityEngine.RaycastHit2D' with null is `true'
The RaycastHit2D documentation says to just check the result directly (which uses the "implicit conversion operator converting to bool"):
RaycastHit2D result = Physics2D.Linecast(start, end, seeTargetMask);
if (result)
{
// Find something we can hurt.
Kill(result.transform.gameObject);
}
I think that's clearer than checking the collider.