- Home /
How to limit mousePosition based on distance (2D)
Let's say I have a slingshot system that requires the player to pull to throw but I only manage to limit the player pull back distance by position on screen by using Mathf.Clamp which it will lock the mousePosition within the limited screen position.
Vector2 mosPos = Input.mousePosition;
Vector3 vel = GetForceFrom(_skills.transform.position, Camera.main.ScreenToWorldPoint(mosPos));
Vector3 newLimit = new Vector3 (Mathf.Clamp (vel.x, -10, 10),Mathf.Clamp (vel.y, -10, 0));
How do I write a code that does the limitation on the mousePosition based on the distance? Which do I even use and how do I write it?
Vector3.Distance
Vector3.magnitude
Vector3.sqrMagnitude
I want the limitation to be half circle at the bottom and only able to pull to a certain distance. PS: Sorry if the word I used here are bad or confusing.
UPDATE: to the above code, here's what its look like in full for the Update() since it's void I had to modified the code to test around but it still doesn't limit the pull back range. Any thoughts?
void Update ()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(isSkillsThrown)
return;
if (isPlayerTurn)
{
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast(ray, out hit) && hit.collider.CompareTag("Player"))
{
isPressed = true;
if (!_skills)
createSkills();
isClickOnObj = true;
}
else
{
isClickOnObj = false;
}
}
else if (Input.GetMouseButtonUp(0))
{
isPressed = false;
GameObject[] trajDes;
trajDes = GameObject.FindGameObjectsWithTag("Trajectory");
for (int i = 0; i < trajDes.Length; i++)
{
Destroy(trajDes[i].gameObject);
}
if (isClickOnObj == true)
{
if (!isSkillsThrown)
{
throwSkills();
}
}
//isPressed = true;
//[Remove comment below for unlimited shots]
ManualStart();
}
}
// when mouse button is pressed, cannon is rotated as per mouse movement and projectile trajectory path is displayed.
if(isPressed)
{
//I would like to add the limit here
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 vel = GetForceFrom(_skills.transform.position, mosPos);
Vector3 newLimit = new Vector3 (Mathf.Clamp (vel.x, -10, 10),Mathf.Clamp (vel.y, -10, 0));
Debug.Log("VEL: "+vel+" newLimit: "+newLimit);
Vector3 newVel = newLimit * -1;
setTrajectoryPoints(transform.position, newVel/_skills.GetComponent<Rigidbody>().mass);
}
}
private Vector2 GetForceFrom(Vector3 fromPos, Vector3 toPos)
{
return (new Vector2(toPos.x, toPos.y) - new Vector2(fromPos.x, fromPos.y))* power;
}
I had all the formula correct already but all I need to do left is to place the limit in that specific location which I only know by using Mathf.Clamp and use screen position.
Still unable to find solution or ways to do it. Any ideas? also bumper road.
If we speak on picture, _skills.transform.position is your point A and mosPos is your point B and you just need a relationship as stated in the picture ?
@toromano _skill is my bullet/projectile which starts from A, I wanted to start dragging from point A to Point B (max) while limiting the drag area to half sphere as seen in the picture. Pardon my bad English.
Then you could try something like this:
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 pointA = new Vector2(_skills.transform.position.x,_skills.transform.position.y);
Vector2 diff = mosPos - pointA;
diff = new Vector2(diff.x, $$anonymous$$athf.$$anonymous$$ax(.0f, diff.y)); // make sure y is not positive
float radius = 10.0f;
if(diff.magnitude > radius)
{
diff = diff.normalized * radius;
}
Vector2 pointB = pointA + diff;
Vector2 pointA = new Vector2(_skills.transform.position.x, _skills.transform.position.y);
Vector2 diff = mosPos - pointA;
diff = new Vector2(diff.x, $$anonymous$$athf.$$anonymous$$ax(-5.0f, diff.y));
float radius = 5.0f;
if (diff.magnitude > radius)
{
diff = diff.normalized * radius;
}
Vector2 pointB = pointA + diff;
Vector3 vel = GetForceFrom(_skills.transform.position, pointB);
Vector3 newVel = vel * -1;
setTrajectoryPoints(transform.position, newVel/_skills.GetComponent<Rigidbody>().mass);
@toromano The original code is the usable but opposite of what I expecting. Ins$$anonymous$$d of limiting at the bottom half of the sphere it limit to the top of the sphere. I modified the code a bit, replacing .0f to -5f makes it able to move the below but it also allow the mouse to move at top of the sphere making it a full circle.
Answer by Bunny83 · Nov 23, 2015 at 04:32 AM
All you need to use is Mathf.Min instead of Mathf.Max. Keep the second value to 0f. There's also Vector2.ClampMagnitude which directly does the clamping to a circle:
Vector2 mosPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 pointA = _skills.transform.position;
Vector2 diff = mosPos - pointA;
diff.y = Mathf.Min(0f, diff.y);
float radius = 10.0f;
diff = Vector2.ClampMagnitude(diff, radius);
Vector2 pointB = pointA + diff;
Mathf.Max just returns the greater number while Mathf.Min returns the smaller number. They are implemented literally just like that:
public static float Max(float a, float b)
{
if (a > b)
return a;
return b;
}
public static float Min(float a, float b)
{
if (a < b)
return a;
return b;
}
When using screen coordinates as well as x-y-world coordinates the y value will grow when you go upwards. So you want to limit your y value of your direction to be 0 or less. So Mathf.Min with your y value will just return the y value when it's smaller than 0. If it's greater than 0 it's limited to 0.
A one side boundary could also simply be done like this:
if (diff.y > 0f)
diff.y = 0f;
This would be a tiny bit faster since you save a method call. However such differences are irrelevant.
@Bunny83 , many thanks. I didn't know there is Clamp$$anonymous$$agnitude which made the whole process much more simpler, since I have to replace so many other calculation. The code I provide is just s small part of it only.
Nevertheless, thanks again for the help and some explanation on how to use Clamp$$anonymous$$agnitude. Since the Documentation didn't really provide one and not sure what is going on with just description.
Answer by JoshDangIt · Oct 28, 2015 at 04:47 PM
Try something like this (Untested):
public Vector3 startingPos; //the starting position of the "slingshot" (you may be able to replace this with transform.position)
public float maxPullDistance = 4f; //the max distance you can pull the "slingshot" from the startingPos
Vector3 GetMousePos()
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); //get the current mousPos
if(Vector3.Distance(startingPos, mousePos) <= maxPullDistance)
{
return mousePos;
}
else
{
//we need to make sure mousePos is within maxPullDistance
Vector3 dir = (mousePos - startingPos).normalized;
return startingPos + (dir * maxPullDistance);
}
}
It didn't work. Ins$$anonymous$$d it just release the limitation previously. Now it can pull back as far as your screen goes.
I updated the question with whole Update function.
Your answer
![](https://koobas.hobune.stream/wayback/20220612043015im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
MousePosition with Iso camera movement 1 Answer
What does bounds.sqrdistance do? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Orbital cannon jitters while following/facing mouse position 1 Answer