- Home /
Finding distance from pivot point of parent obj
Hello, community!
I am currently using Unity to create some 3D representations of some tools and objects. These scenes allow the user to rotate the object, zoom in and out, and turn off/on any animations it might have.
Also, these objects are usually made up of multiple child objects that make up the innards and such. What I am looking to do is find the distance from the center of the parent object to each individual child object, and then transform.position the child objects by 2x that. The result would be to give off an "expanded view" of the inner workings.
Here is my current code in C#:
void Start()
{
cameraZoom = (maxDistance + minDistance) / 2; //Set camera start distance in the middle of min and max range
Camera.main.orthographicSize = cameraZoom;
savedLocalPos = transform.localPosition;
}
void Update()
{
if (!automate)
HandleInputs();
else if(automate)
Automate();
if (disassemble)
Disassemble();
else if (!disassemble)
transform.localPosition = savedLocalPos;
if(Input.GetAxis("Mouse ScrollWheel") != 0)
cameraZoom = Mathf.Clamp(cameraZoom - Input.GetAxis("Mouse ScrollWheel") * 2,
minDistance, maxDistance);
Camera.main.orthographicSize = cameraZoom;
CalculateObjectRotation();
}
void HandleInputs()
{
if(Input.GetMouseButton(1))
{
xDeg -= Input.GetAxis("Mouse X") * speed;
zDeg -= Input.GetAxis("Mouse Y") * speed;
}
if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
xDeg -= Input.GetAxis("Horizontal") * speed;
zDeg -= Input.GetAxis("Vertical") * speed;
}
}
void Automate()
{
xDeg -= speed * speedMod / 20;
yDeg += speed * speedMod;
zDeg = 0;
}
void Disassemble()
{
transform.localPosition = savedLocalPos * 2;
}
void OnGUI()
{
GUI.skin = customSkin;
if(!automate)
{
if(GUI.Button(new Rect(5,5,110,25), "Engage") && !automate)
automate = true;
}else
{
if(GUI.Button(new Rect(5,5,110,25), "Disengage") && automate)
automate = false;
speedMod = GUI.HorizontalSlider(new Rect(Screen.width/2 - 150, Screen.height - 50, 300, 100), speedMod, speedModMin, speedModMax);
GUI.Box(new Rect(Screen.width/2 - 50, Screen.height - 37, 100, 25),"Speed = " + speedMod.ToString("F2") +"x");
}
if(!disassemble)
{
if(GUI.Button(new Rect(5,35,110,25), "Disassemble") && !disassemble)
disassemble = true;
}else
{
if(GUI.Button(new Rect(5,35,110,25), "Assemble") && disassemble)
disassemble = false;
}
if(GUI.Button(new Rect(5,65,110,25), "Help"))
{
//still working on this pop-up window
}
if(GUI.Button(new Rect(5,95,110,25), "Reset Rotation"))
{
if(automate)
{
xDeg = 0f;
} else xDeg = yDeg = zDeg = 0f;
}
cameraZoom = GUI.VerticalSlider(new Rect(Screen.width - 12, 5, 100, Screen.height - 55), cameraZoom, minDistance, maxDistance);
}
void CalculateObjectRotation()
{
fromRotation = transform.rotation;
toRotation = Quaternion.Euler(yDeg,xDeg,zDeg);
transform.rotation = Quaternion.Lerp(fromRotation, toRotation, Time.deltaTime * lerpSpeed);
}
}
Answer by Owen-Reynolds · Jul 11, 2012 at 07:29 PM
I didn't see the part of the code that appeared to match the question, so this is just a response to the paragraph. You can use localPosition
to read and set the your local position, using the parent's local axis, from it's position.
It works the same way as changing a childed object's position in the Inspector (when you're childed, Unity shows your local-pos in the position slot.) So:
Vector3 savedLocalPos;
Start() { savedLocalPos = transform.localPosition; }
// "blow up" to be twice as far from parent's center:
transform.localPosition = savedLocalPos * 2;
If you don't always want to expand from the center, a cheap trick is to make dummy empties. For example, you want all parts of the handle to expand away from the handle's center (not the mop's center.) Child dummy "handleMount" at the handle, and child handle components to handleMount. LocalPos will now take them away/towards that.
Thanks for you response. Currently this script is attached to only the parent object. Do I need to write a separate script for the children? I've added the updated script to the original post, as of right now nothing happens.
To change one kid, the parent has to "reach down" with something like: transfrom.Find("handle").localPosition= ...;
. To touch all kids, you'd use a foreach
(an example in the Scripting reference.) But, lot of work if you have lots of kids.
Yes, it might be easier to write one more script (one total) that goes on each kid. That way they can each save their starting pos (otherwise the parent would need an array to store then all.) It might have one function: disassemble(float percent) { trans.locPos=savedPos * percent; }
that the parent calls.
Then the parent could use a single Send$$anonymous$$essage(whatever)
. It tells all your kids and grandkids to do whatever() -- no loops needed (disclaimer -- I haven't used Send$$anonymous$$essage.)
Answer by BudgeB · Jan 22, 2013 at 04:01 PM
It's good advice and I've done a similar thing to implement pivots / anchor points, but the important thing is to have one object loop through all the children and update their object. I doubt SendMessage overhead is less than just explicitly looping through the children in a recursive function (which is what I do, once per frame, and only from the "root"). I.e. you don't want every child to update its own children, just one parent do it once per frame so there is no duplicate / redundant processing.
Apologies for the snark, but advising someone they can use a SendMessage message passing when you haven't even used it yourself is bad form. I see this type of non-help ALL the time in these forums.
Your answer
Follow this Question
Related Questions
Camera rotation around player while following. 6 Answers
How to make a game charachter rotate towards you when close enough? 1 Answer
Wrong Camera axis after "zoom" to GameObject 0 Answers
how do I make a joint that fixates the objects distance but lets them rotate freely? 1 Answer
spawned object wont change scale? 1 Answer