- Home /
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);
}
}
Try debugging the if (Raycast) statement... Add this Debug.Log(hit.tranform.name)
to it and see what happens
Answer by MarekRimal · Jun 01 at 09:52 AM
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 :)
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.
Hi, thanks for you help, i applied your suggestions to my code and now i have seem to notice the raycast only detects objects if the player is around the same y coordinate as the player. I have tried finding a fix for this but i cant seem to find anything. My current grappling code: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class GrappleGun : MonoBehaviour
{
public LayerMask grappleLayer;
public Vector3 lastHit;
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()
{
RaycastHit hit;
if (Input.GetMouseButtonDown(0)){
if (Physics.Raycast(transform.position, transform.forward, out hit, maxDistance, grappleLayer)){
lastHit = hit.point;
Debug.Log("grapple");
if (lastHit != null && !grappled){
PlayerPrefs.SetInt("Grappling", 1);
transform.position = Vector3.Lerp(transform.position, lastHit, lerpSpeed);
lerpSpeed += 0.5f * Time.deltaTime;
if (lerpSpeed > 1f){
grappled = true;
}
} else if (!Input.GetMouseButton(0)){
PlayerPrefs.SetInt("Grappling", 0);
lastHit = Vector3.zero;
}
}
} else {
PlayerPrefs.SetInt("Grappling", 0);
}
}
}
You want to Raycast only once and then do the Lerping elsewhere. Just take the hitPoint and move the Lerp code outside of the Raycast if. You are probably getting different hitPoint in each frame and since you are moving the gun in y direction it misses after a few hits.
If you are interested, this is a perfect scenario to use a coroutine. Check them out. Its something like another Update loop which runs asynchronously. You can start the coroutine when you hit with the Raycast and do the Lerping inside the couroutine.