Hello! I’m very new here and I have not much clue regarding programming and stuff. However, I’m annoyed by the fact that raycasts go through walls for some reason? For instance, I’ve been following a little tutorial to get me started and stuff, but then I noticed my raycast just… heading through the wall?
I did browse around the Discussions and other sites, but I’m just so confused because the layer seems to be set correctly??
The code:
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerInteract : MonoBehaviour
{
private Camera cam;
[SerializeField]
private float distance = 4f;
[SerializeField]
private LayerMask mask;
private PlayerUI playerUI;
private InputManager inputManager;
// Start is called before the first frame update
void Start()
{
cam = GetComponent<PlayerLook>().cam;
playerUI = GetComponent<PlayerUI>();
inputManager = GetComponent<InputManager>();
}
// Update is called once per frame
void Update()
{
playerUI.UpdateText(string.Empty);
Ray ray = new Ray(cam.transform.position, cam.transform.forward);
Debug.DrawRay(ray.origin, ray.direction * distance);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, distance, mask))
{
if(hitInfo.collider.GetComponent<Interactable>() != null)
{
Interactable interactable = hitInfo.collider.GetComponent<Interactable>();
playerUI.UpdateText(interactable.promptMessage);
if (inputManager.OnFoot.Interact.triggered)
{
interactable.BaseInteract();
}
}
}
}
}
In the inspector:
All walls are in the Default layer, the keypad does have the Interactable layer. Everything has a collider.
I hope I posted this in the right section, I’m very new here and the layout of the discussions page is rather confusing.
Try to put a Debug.Log within your raycast-if, to see what component was hit and on what layer it was on. Make sure your Interactable collider doesnt stick through the wall, which would explain why it can be hit from behind. If you begin your raycast while your player is “within the wall”, the actual wall object is not “hit”, and as such it might reach the interactable panel from behind.
Alternatively, if you really want to make sure your interactable panels are only interacted with from the front, you could compare the normal of the hit with the orientation of the panel. However, this should not be necessary when you fix the initial problem.
Also, a little nitpicking performance optimization: GetComponent is a slow operation. You can cache that result, so that you only call it once. Try this:
private void Update()
{
playerUI.UpdateText(string.Empty);
Ray ray = new Ray(cam.transform.position, cam.transform.forward);
Debug.DrawRay(ray.origin, ray.direction * distance);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, distance, mask))
{
Debug.Log($"The following object was hit: '{hitInfo.collider.gameObject.name}' on layer '{hitInfo.collider.gameObject.layer}'");
Interactable interactable = hitInfo.collider.GetComponent<Interactable>();
if(interactable != null)
{
playerUI.UpdateText(interactable.promptMessage);
if (inputManager.OnFoot.Interact.triggered)
{
interactable.BaseInteract();
}
}
}
}
Does not print when any other object is hit other than the keypad. When it does, it prints exactly what it is told to print. The following object was hit: Keypad on layer 6.
May I ask where this is going? It does not solve the problem of the raycast going through walls.
This is debugging, to see whether the raycast is actually hitting your object and what else it hits. Since the wall is not hit, make sure your collision matrix is setup correctly and check whether the raycast starts within the wall.
Make sure that your gameobject in layer what you determinate in inspector at Player Interact (Script).
Also if you put rigidbody component to some parent object, RaycastHit will intercept that object.
It’s most likely not passing through the wall. It just looks like that because you’re drawing the ray (line 5) before you actually check if it hits anything (line 7). Here’s code corrected to first cast the ray and then restrict the distance the line travels based off of whether it hits an obstacle.
private void Update()
{
playerUI.UpdateText(string.Empty);
Ray ray = new Ray(cam.transfrom.position, cam.transform.forward);
RaycastHit hitInfo;
bool hit = Physics.Raycast(ray, out hitInfo, distance, mask);
float drawDistance = hit ? hitInfo.distance : distance;
Debug.DrawRay(ray.origin, ray.direction * drawDistance, Color.red);
if (hit)
{
Debug.Log($"The following object was hit: '{hitInfo.collider.gameObject.name}' on layer '{hitInfo.collider.gameObject.layer}'");
Interactable interactable = hitInfo.collider.GetComponent<Interactable>();
if(interactable != null)
{
playerUI.UpdateText(interactable.promptMessage);
if (inputManager.OnFoot.Interact.triggered)
{
interactable.BaseInteract();
}
}
}
}
Yes raycast will go through wall because you cast your Ray with mask.
if (Physics.Raycast(ray, out hitInfo, distance, mask))
And as you can see, mask was set for Interactable.
So ray will hit only things on this layer.
If walls are on default, ray will go through them.
Why? Because calling GetComponent is quite expensive, so your tutorial button was assign for diffrent layer.
As a result: Ray will hit something less frequently. And when Ray hit something, it will be for sure worth calling GetComponent on it.