Home > Software engineering >  How would I clamp the distance of a LineRender being drawn from a game object towards my cursor?
How would I clamp the distance of a LineRender being drawn from a game object towards my cursor?

Time:03-24

Gameplay shot of the line render

I am creating a mini golf game where the player clicks and drags to shoot the ball. Currently, I have a line that show the direction and power of the shot. I'm not quite sure how I would clamp the distance (aka the power) of the line render while still keeping the correct direction. I also want to sync the length of the line render with the power meter ui in the bottom left corner of the picture. I've provided my code below:

private void ProcessAim()
{
    if (!isAiming || !isIdle) {
        return;
    }        
    
    worldPoint = CastMouseClickRay();
    if (!worldPoint.HasValue) {return;}

    DrawLine(worldPoint.Value);
}

private void Shoot(Vector3 worldPoint)
{
    // Disabling the aiming
    isAiming = false;
    lineRenderer.enabled = false;

    Vector3 horizontalWorldPoint = new Vector3(worldPoint.x, transform.position.y, worldPoint.z);

    Vector3 direction = (horizontalWorldPoint - transform.position).normalized;
    float strength = Vector3.Distance(transform.position, horizontalWorldPoint);
    rb.AddForce(direction * strength * shotPower);
}

private void DrawLine(Vector3 worldPoint) 
{
    Vector3[] positions = { transform.position, worldPoint };

    lineRenderer.SetPositions(positions);
    lineRenderer.enabled = true;
}

private Vector3? CastMouseClickRay()
{
    // Grabs the x and y coords and the clipPlane of the camera
    Vector3 screenMousePosFar = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.farClipPlane);
    Vector3 screenMousePosNear = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);

    // Converts to in-game
    Vector3 worldMousePosFar = Camera.main.ScreenToWorldPoint(screenMousePosFar);
    Vector3 worldMousePosNear = Camera.main.ScreenToWorldPoint(screenMousePosNear);
    Vector3 direction = (worldMousePosFar - worldMousePosNear).normalized;
    
    // Casting a ray between the two clipPlanes of the camera at the x and y coords to see if it hit any colliders
    RaycastHit hit;
    if (Physics.Raycast(worldMousePosNear, worldMousePosFar - worldMousePosNear, out hit, float.PositiveInfinity)) 
    {
        return hit.point;
    } 
    else 
    {
        return null;
    }
}

CodePudding user response:

You are looking for Vector3.ClampMagnitude

You could use it e.g. in

private void DrawLine(Vector3 worldPoint) 
{
    // get vector from your position towards worldPoint 
    var delta = worldPoint - transform.position;
    // clamp the distance
    delta = Vector3.ClampMagnitude(delta, YOUR_DESIRED_MAX_DISTANCE);

    // assign back
    worldPoint = transform.position   delta;

    Vector3[] positions = { transform.position, worldPoint };

    lineRenderer.SetPositions(positions);
    lineRenderer.enabled = true;
}

Btw in CastMouseClickRay you should rather simply use Camera.ScreenPointToRay

// you should cache Camera.main!
private Camera mainCamera;

private Vector3? CastMouseClickRay()
{
    // you should cache Camera.main as it is expensive!
    if(!mainCamera) mainCamera = Camera.main;

    // simple as that you get the mouse ray
    var ray = mainCamera.ScreenPointToRay(Input.mousePosition);
    if (Physics.Raycast(ray, out var hit))
    {
        return hit.position;
    }
    else
    {
        return null;
    }
}

Or if you really rather actually wanted to do what your comment says

 // Casting a ray between the two clipPlanes of the camera at the x and y coords to see if it hit any colliders

then you would not use a Raycast with infinite distance but rather a Physics.Linecast

if (Physics.Linecast(worldMousePosNear, worldMousePosFar, out var hit))

Returns true if there is any collider intersecting the line between start and end.

  • Related