Raycast not detecting objects

Hi! I am making a grapple gun in unity(not a very good one, im making one with a charactercontroller) and ive been trying to make it using raycasting. However, it doesnt seem to detect object. All objects have a collider and sometimes it works, but then it detects it above the gameObject. Also this is the first time i am using raycasting, so things might not be right.
Grapple gun code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GrappleGun : MonoBehaviour
{
    public LayerMask grappleLayer;
    public GameObject lastHit;
    public Vector3 direction = -Vector3.up;
    private float maxDistance = Mathf.Infinity;
    private float lerpSpeed = 0f;
    private bool grappled = false;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        var ray = new Ray(this.transform.position, this.transform.TransformDirection(Vector3.forward));
        Debug.Log(this.transform.TransformDirection(Vector3.forward));
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, maxDistance, grappleLayer)){
            lastHit = hit.transform.gameObject;
        }
        if (lastHit != null && !grappled && Input.GetMouseButtonDown(0)){
            PlayerPrefs.SetInt("Grappling", 1);
            transform.position = Vector3.Lerp(transform.position, lastHit.transform.position, lerpSpeed);
            lerpSpeed += 0.5f * Time.deltaTime;
            if (lerpSpeed > 1f){
                grappled = true;
            }
        } else if (!Input.GetMouseButton(0)){
            PlayerPrefs.SetInt("Grappling", 0);
            lastHit = null;
        }
    }
}

Player controller:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{

    public CharacterController controller;

    public float speed = 12f;
    public float gravity = -9.81f;
    public float jumpHeight = 1.5f;

    public Transform groundCheck;
    public float groundDistance;
    public LayerMask groundMask;
    public float walkSpeed = 12f;
    public float runSpeed = 20f;
    public Transform spawnParkour;
    public GameObject player;

    Vector3 velocity;
    bool isGrounded;


    void Update()
    {
        if (PlayerPrefs.GetInt("Grappling", 0) != 1){
            Move();
        }
        if (Input.GetKey(KeyCode.R)) {
            transform.position = spawnParkour.position;
            velocity = new Vector3(0f, 0f, 0f);
        }
        if (isGrounded && velocity.y < 0) {
            velocity.y = -2f;
        }
    }

    void Move()
    {
        
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
        if (Input.GetKey(KeyCode.LeftShift)) {
            Debug.Log("sprint");
            speed = runSpeed;
        } else {
            speed = walkSpeed;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        Vector3 move = transform.right * x + transform.forward * z;

        controller.Move(move * speed * Time.deltaTime);
        if (Input.GetButton("Jump") && isGrounded) {
            velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
        }

        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

Camera controller, in case you need it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{

    public float mouseSensitivity = 100f;

    public Transform playerBody;

    float xRotation = 0f;
    // Start is called before the first frame update
    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        playerBody.Rotate(Vector3.up * mouseX);
    }
}

I have read the first script and my guess is that its caused by the lastHit variable. You are storing a GameObject you have hit with the grapple gun and then you are using its origin transform.position as a grappling target. I think it would be better to store the exact hitpoint RaycastHit.point and use that as a grappling target.


Just a few more tips :slight_smile:

You can use simply transform.forward instead of transform.TransformDirection(Vector3.forward)


You can visualize the ray in scene view using Debug.DrawRay()


In the grapple gun Update I would check first for the user input and then do the raycasting since raycasting is pretty computation heavy operation to do each frame. Its actually one of the most costly operation since it has to shoot a ray and then find intersection with the first object it hit in the whole scene. In larger scenes this could drastically lower your FPS.