i’m basically trying to get a yellow rectangle (controlled by the mouse ) to rotate around the red circle point and facing it aswell …
As you can see in the gif below , its working (at the beginning) , but when i get the mouse closer to the red circle , the rectangle follows it ( due to the use of clampMagnitude i guess) . And i would like to keep a fixed between the two objects (with a defined value) .
I dont want the yellow rectangle to get "close " to the red circle .
If anyone can help me i would be grateful
ps : the first code is used to manage the rotation around the object and the second one is used to face the circle at runtime .
Script used to rotate around the circle : [u](attached to the “yellow rectangle” game object)[/u]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstTry : MonoBehaviour
{
[SerializeField] Transform targetObject; // reference to the object we rotate around (the red circle)
float maxLength = 2.5f;
void Update()
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 5;
currentPosition = Camera.main.ScreenToWorldPoint(mousePosition);
currentPosition = center.position + Vector3.ClampMagnitude(currentPosition - center.position, maxLength);
transform.position = currentPosition; //set YellowTab position
}
}
Script used to "look at " the circle : (attached to “red circle” game object)
public class LookAtObject : MonoBehaviour
{
[SerializeField] Transform target;
Vector2 lastRotation;
void Update()
{
Vector2 direction = target.position - transform.position;
transform.rotation = Quaternion.FromToRotation(Vector3.down, direction);
}
}
( Sorry there is an error in my first message , the “LookAtObject” script is attached to the yellow rectangle game object not to the red circle game object )
if M is mouse position, R is red dot position, and Y is the yellow object that has a pivot in the middle
then you just need d to define a fixed distance, for example d = 2
then
you can get direction between R and M by
var dir = (M.pos - R.pos).normalized;
this is simply a vector that represents that gap from R to M, but rescaled to a length of 1.
Y object should be placed at d times that much from R
its rotation depends on its own position in space, so if its original rotation (identity) was so that it was looking right
var orient = (Y.pos - R.pos).normalized; // aka facing normal
Y.rot = Quaternion.FromToRotation(Vector3.right, orient);
edit: typos
edit2: if something’s opposite to what you wanted, you can always flip things around, see if that works, i.e. B-A instead of A-B, or you can simply put a minus in front of any vector variable.
public class FirstTry : MonoBehaviour
{
float distanceFromCenter = 5.0f; // "distanceFromCenter " is "d" in your explanation
private Vector3 currentPosition;
[SerializeField] Transform center;
void Update()
{
Vector3 mousePosition = Input.mousePosition;
currentPosition = Camera.main.ScreenToWorldPoint(mousePosition);
var dir = (currentposition - center.position).normalized;
transform.position = center.position + distanceFromCenter * dir;
}
}
The code should looks like this ? correct me if im wrong ?
Its working on runtime , but it basically giving me the same resultat as my first try .
That give me a ClampMagnitude “effect” : when i drag the mouse away from the center at the distance defined by “distanceFromCenter” then the Yellow Rectagnle doesnt follow the mouse ( thats good) , but when i get my mouse closer from the center then the rectangle is following while it’s supposed to remain at a "5.0f " distance
using UnityEngine;
public class ForumMouse : MonoBehaviour {
[SerializeField] Vector2 _redDot; // R
[SerializeField] GameObject _quad; // Y
[SerializeField] [Min(0.1f)] float _distance; // d
void Update() {
var mp = toVector2(Camera.main.ScreenToWorldPoint(Input.mousePosition)); // M
var dir = (mp - _redDot).normalized;
var objPos = _redDot + _distance * dir;
var objOrient = (objPos - _redDot).normalized;
_quad.transform.localPosition = toVector3(objPos);
_quad.transform.localRotation = Quaternion.FromToRotation(Vector3.right, toVector3(objOrient));
}
Vector2 toVector2(Vector3 v) => new Vector2(v.x, v.y);
Vector3 toVector3(Vector2 v) => new Vector3(v.x, v.y, 0f);
}
Plop a simple quad object directly into the scene, and dragndrop it to the corresponding field. Hit play and change values.
Also observe these little Vector2 ↔ Vector3 conversion utils, they make your life much easier, and your intent much clearer. Without them weird algebraic bugs will crop up and you also can’t tell which is which at a glance.
And you can now very easily change the whole setup to work in another plane, for example XZ.
first we get that red arrow from R to M
it is of arbitrary length, who knows where the mouse is, right
then we normalize that, that means it’s divided by its length (so it becomes unit)
so we get dir, that little red arrow next to R
then we multiply that with our distance 2 and get the light blue arrow
but to actually get to that point you need to account for the position of R itself
and that’s the dashed line, that’s what you get when you add the two
now that we have Y’s position, we get light blue arrow from R to Y again
by doing (R - Y).normalized
can you see how we can optimize this code and not do things twice?
anyway from that point on, we have a facing normal and we can find the angle
edit:
haven’t shown the angle properly, it’s actually measured 90 degrees further to the right for this particular case. absolute angles are always measured from the positive X line.
this change is good because you want to avoid normalization (and similarly magnitude) as much as possible. it’s not the slowest thing ever, but it’s the slowest thing among other stuff we did with that code, including quaternion shenanigans. do note that these things are also unavoidable, so it’s not a bad code, we just tend to minimize it.
also try not to use transform.position and transform.rotation directly if you can help it. these two have their uses, but if you can, use localPosition and localRotation instead.
It does convert from vector3 to vector2 by transplanting coordinates in such a way to make them consistent with the XY plane. I.e. removing the last, z coordinate is all it does.
It’s not implicit if you have to call it explicitly. Implicit conversion is a “silent” one (i.e. seemingly non-provoked by your code). Internally, Unity declares implicit conversion between the two, which is okay when you want Vector2 → Vector3, but by someone’s mistake also does this in the opposite direction, which is against common logic (and official recommendations), because in this case you also implicitly lose z. Just try disabling those two functions, and the code will likely still work, but completely bugged.
When you work in 2D but still use 3D API, the best you can do is to make little converters such as these, so you can maximize your control over explicit conversions. In other words, do not rely on implicit ones, even though they “work”. I wish there was a way to simply disable them, because it’s much better to have a compiler error than a deeply nested error in math.
That would be explicit conversion. But I opted against it, because it shows intent with more clarity, and allows you to switch things around. Maybe you want new Vector3(v.x, 0f, v.y) for example.
This would be implicit, it does the same thing as above (because both Vector types declare such implicit operators, it’s not something you can normally do in C#).
Finally, observe that I sanitize my coordinates on input, work entirely in 2D, then convert back to 3D only when it’s done and I need to use API to send them back.
var mp = toVector2(Camera.main.ScreenToWorldPoint(Input.mousePosition)); // convert mouse to 2D
var dir = (mp - _redDot).normalized; // everything is 2D here
var objPos = _redDot + _distance * dir; // everything is 2D here
var objOrient = -dir; // everything is 2D here
_quad.transform.localPosition = toVector3(objPos); // 3D
_quad.transform.localRotation = Quaternion.FromToRotation(Vector3.right, toVector3(objOrient)); // 3D