toficofi
toficofi

Reputation: 593

How do I make raycast from the cursor without using the physics system?

I'm building to WebGL and have disabled the physics system in Package Manager to reduce build size. I'm now in a position where I want to find where on a plane a raycast fired from the cursor, lands. See diagram:

Diagram

Can I do this without the physics system, or will I be required to include it and the couple of mb it adds to the current build size of 5mb?

Upvotes: 0

Views: 1049

Answers (1)

derHugo
derHugo

Reputation: 90679

You could use a Plane.Raycast

using UnityEngine;

public class GetRaycast : MonoBehaviour
{
    Camera camera;

    public Transform PlaneTransform;
    public Transform Player;

    // Start is called before the first frame update
    private void Start()
    {
        camera = Camera.main;
    }

    // Update is called once per frame
    private void Update()
    {
        if (!Input.GetMouseButtonDown(0)) return;

        // you just need any 3 points inside of the plane and provide them
        // in clockwise order (so the normal points upwards)
        // for the raycast this actually wouldn't matter
        var plane = new Plane(PlaneTransform.position, PlaneTransform.position + PlaneTransform.forward, PlaneTransform.position + PlaneTransform.right);

        // get ray for mouseposition
        var ray = camera.ScreenPointToRay(Input.mousePosition);
        // enter will be the distance between the ray origin and the hit plane
        if (!plane.Raycast(ray, out var enter)) return;

        // GetPoint returns the position along the raycast in
        // the given distance from the ray origin
        Player.position = ray.GetPoint(enter) + Vector3.up * 0.1f;
    }
}

However, a huge disadvantage of this method however is that the generated plane is infinite so the raycast detection doesn't end at the limits of the actual plane so you would have to clamp that "manually" again.

You could do this in this simple example where the plane is flat in the world like

public class GetRaycast : MonoBehaviour
{
    Camera camera;

    public MeshFilter PlaneTransform;
    public Transform Player;

    // Start is called before the first frame update
    private void Start()
    {
        camera = Camera.main;
    }

    // Update is called once per frame
    private void Update()
    {
        if (!Input.GetMouseButtonDown(0)) return;

        // you just need any 3 points inside of the plane and provide them
        // in clockwise order (so the normal points upwards)
        // for the raycast this actually wouldn't matter
        var plane = new Plane(PlaneTransform.transform.position, PlaneTransform.transform.position + PlaneTransform.transform.forward, PlaneTransform.transform.position + PlaneTransform.transform.right);

        // get ray for mouseposition
        var ray = camera.ScreenPointToRay(Input.mousePosition);
        // enter will be the distance between the ray origin and the hit plane
        if (!plane.Raycast(ray, out var enter)) return;

        // GetPoint returns the position along the raycast in
        // the given distance from the ray origin
        var hitPosition = ray.GetPoint(enter);

        // check if hitposition is within the Plane mesh
        // mesh.bounds returns the bounding box of the mesh but
        // unscaled. lossyScale is the overall scale in the scene
        // also taking all parent scales into account
        if (hitPosition.x < PlaneTransform.mesh.bounds.min.x * PlaneTransform.transform.lossyScale.x
            || hitPosition.x > PlaneTransform.mesh.bounds.max.x * PlaneTransform.transform.lossyScale.x
            || hitPosition.z < PlaneTransform.mesh.bounds.min.z * PlaneTransform.transform.lossyScale.z
            || hitPosition.z > PlaneTransform.mesh.bounds.max.z * PlaneTransform.transform.lossyScale.z)
        {
            return;
        }

        Player.position = hitPosition + Vector3.up * 0.1f;
    }
}

Now the player should only get set to the new position if the click was inside of the Plane.

enter image description here


Originally I thought you deactivated the Physics package which is experimental and is more about rigidbody and mass collisions. And not related to Physics.Raycast which is part of the UnityEngine.

After your comment I understand you actually deactivate the Built-In Physics.

Otherwise you still would be able to simply use Physics.Raycast like e.g.

using UnityEngine;

public class GetRaycast : MonoBehaviour
{
    Camera camera;

    public Transform Player;

    // Start is called before the first frame update
    private void Start()
    {
        camera = Camera.main;
    }

    // Update is called once per frame
    private void Update()
    {
        if (!Input.GetMouseButtonDown(0)) return;

        if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out var hit)) return;

        // I just make it float a little to avoid mesh overlaps
        Player.position = hit.point + Vector3.up * 0.1f;
    }
}

Upvotes: 3

Related Questions