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.