- Home /
How to scale a parent without scaling children?
I am trying to scale up an object without scaling it's children. The original scale vectors for both parent and children are (1, 1, 1). The parent is named and tagged differently than the children, but all children are named and tagged the same.
This code works to scale everything (including children) up:
var largeSize : float; // exposed in inspector
function ScaleUp () { var velocity = Vector3.zero; var targetScale = Vector3(largeSize, largeSize, largeSize);
while (transform.localScale != targetScale)
{
transform.localScale = Vector3.SmoothDamp(transform.localScale, targetScale, velocity, 0.5);
yield;
}
}
But I don't want everything scaled up, so I tried to differentiate the children and offset the scaling by scaling them back down. Since for (var child : Transform in transform)
does include the parent transform, I tried to differentiate the children by name or by tag, as follows:
function ScaleUp () { var velocity = Vector3.zero; var targetScale = Vector3(largeSize, largeSize, largeSize); var childScale = Vector3(largeSize/2, largeSize/2, largeSize/2);
while (transform.localScale != targetScale)
{
transform.localScale = Vector3.SmoothDamp(transform.localScale, targetScale, velocity, 0.5);
for (var child : Transform in transform)
{
if (child.gameObject.tag == "ChildSpecificTag")
child.localScale = Vector3.SmoothDamp(child.localScale, childScale, velocity, 0.5);
}
yield;
}
}
This... apparently works, but also catches the parent transform in an if statement it shouldn't be caught in? The result of this code is that no scaling occurs, everything stays the same as it was. But the parent is definitely tagged differently than the children. And also named differently, and the same thing happens (no scaling - or, everything is scaled up and immediately scaled back down) if the if statement is: if (child.gameObject.name != this.gameObject.name)
How can I apply scaling to the parent without scaling the children, or, how can I effectively differentiate the children to offset the scaling?
ETA: I have not tried GetComponent(s)InChildren
because that apparently also returns the same component in the parent, and if the parent can evade an if statement designed to weed it out when returned through Transform in transform
, will it be any different using GetComponent(s)InChildren
?
Answer by Jean-Fabre · Jan 26, 2011 at 06:58 AM
Hi,
I am sure there is a way to get your script working, but I would discourage you from doing it. I would strongly suggest adding a layer of indirection in your hierarchy instead.
Instead of linking your models together and being stuck when willing to scale one independantly, create an empty gameObject name "parent" like so:
-- "parent"
-- "model to scale"
-- "another model"
-- "yet another model"
Everything that you did normally with "model to scale" should now be done via "parent", and for scaling, you simply scale "model to scale" without interfering with the rest of the hierarchy.
I always do that when I need that kind of feature implemented, it's very common for technical assemblies and complex rigs. In assemblies, I even go further and have a layer of indirection of each and every feature rich model, so that I can exchange models, load them on demand, or complex Level of details scripting, basically mess with them without affecting in anyway the actual hierarchy itself.
Hope this helps,
Jean
Ok, so it took me a while to adjust all my scripts so that everything is functioning properly, but it's all working. The one interesting thing I noticed is this - my original "model to scale", when it was the parent object itself, had a collider and rigidbody attached. Of course I had to move the rigidbody to the new "parent" so that it would move correctly, and I left the collider on the "model to scale" so that it would scale along with the model. I removed the script from the "model to scale" and put it on the "parent." [continued below]
However, the script on the "parent" is successfully receiving OnCollision information from the collider that's on its child object. How is that working? Does collision information automatically travel up the hierarchy? Or up /and/ down the hierarchy?
I was expecting to have to attach a script to the "model to scale" object to manually send the collision info to the script on the parent. So, it's working out much easier than anticipated, but I want to really understand the behavior that's going on.
Hi Dylan, make it another question please, then we keep things tidy :) thanks.
Answer by Berenger · Jan 26, 2011 at 08:43 AM
Jean's answer is probably the best way to do it, but I have something else you can try; You can detach children, scale and re-attach them after. It might be costly with a lot of children though. Something like that :
public class ScaleAndParenthood : MonoBehaviour { public float s = 1.0f; private Transform[] children = null;
// We build an array with all children, so we can re attach them later
void Start ()
{
children = new Transform[ transform.childCount ];
int i = 0;
foreach( Transform T in transform )
children[i++] = T;
}
// Update is called once per frame
void Update ()
{
if( s != transform.localScale.x )
{
transform.DetachChildren(); // Detach
transform.localScale = new Vector3( s, s, s ); // Scale
foreach( Transform T in children ) // Re-Attach
T.parent = transform;
}
}
}
Thanks Berenger, I tried this solution too, and it does work. And in my case it is fine since there would only ever be two children to detach / re-attach.
Answer by Rachan · Aug 29, 2017 at 06:15 PM
You can do like this. it's work perfectly for me.
Vector3 scaleTmp = object.transform.localScale;
scaleTmp.x /= parent.localScale.x;
scaleTmp.y /= parent.localScale.y;
scaleTmp.z /= parent.localScale.z;
object.transform.parent = parent;
object.transform.localScale = scaleTmp;
Thank you Rachan! In my case your answer worked great. I had thought of the same technique but was a little bored to dive in math so i figured why not google it and although the "correct" answer seemed to work for a lot of people but it didnt for me (maybe unity fixxed that "hackish" way to do it). However your little piece of code was perfect!
Answer by V-Jankaitis · Jan 12, 2017 at 04:38 PM
if (Size != Old_Size && SphereColider != null) { SphereColider.radius *= Old_Size / Size; } transform.localScale = new Vector3(Size, Size, Size); Old_Size = Size;
important part is "*= Old_Size / Size;" multiply that by child scale and it will keep consistent size
Answer by Rispat-Momit · Sep 07, 2018 at 08:21 PM
Hi there! I figure out this solution :D
Just set this script to your child ;) (It works also in Edit Mode so that you can set up the scale you need.
At the FixeScale set up the size of your child you need and at the parent set your parent model.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class FixedScale : MonoBehaviour {
public float FixeScale =1 ;
public GameObject parent;
// Update is called once per frame
void Update () {
transform.localScale = new Vector3 (FixeScale/parent.transform.localScale.x,FixeScale/parent.transform.localScale.y,FixeScale/parent.transform.localScale.z);
}
}