Make a gameobject's child lerp its position and rotation back to its parent

Hello fellow game developers !

I’m trying to find a way to make a gameobject’s child’s position and rotation to lerp to its parent’s instead of following it instantly.

I tried doing stuff like this :

pl.mesh.position = Vector3.Lerp(pl.mesh.position, transform.position, 0.01f);

But it doesn’t work. (The script is on the parent, and pl.mesh is the child’s gameobject).

Can someone help ?

Thank you !

The child position is its local position i.e. relative to the parent. If its at 0,0,0 then it’s the same as the parent. Your lerp target should be Vector3.zero

Is the parent moving? If so, having this as a child doesn’t make much sense.

for one, we’d need to see the code, to get a better understanding of what you may have wrong. Also use the Code: tab as stated in this post: Using code tags properly

Well I got this so far :

With the oldMeshXX being the value of the pl.mesh.XX at the last frame.

The rotation part works ! But for the position, I’m not sure what to replace the ----- with ?

pl.mesh.position = Vector3.Slerp(oldMeshPos, -----, 15f * Time.fixedDeltaTime);
pl.mesh.rotation = Quaternion.Slerp(oldMeshRot, Quaternion.LookRotation(-transform.up, transform.forward), 15f * Time.fixedDeltaTime);

Ohh I see what you’re saying now, but yeah as Melv stated, all you need to be messing with is the child’s “localPosition”. As if the child were completely on “top” of the parent, it’s local position would be (0, 0, 0). So if the child moves away from parent, it’ll know exactly which way to go from it’s local position(as opposed to Vector3.zero), as direction would just be an inverse of that. Then just lerp that.

Something like this example, you’ll have to play around with it:

void MoveToParent(Transform child)
    {
        float minimumDistance = 1.5f; // to parent
        if (child.localPosition.x > minimumDistance || child.localPosition.z > minimumDistance)
        {
            child.localPosition = Vector3.Slerp(Vector3.zero, child.localPosition, 15f * Time.fixedDeltaTime);
        }
    }

Thanks that worked, but it’s still lacking a thing, and heck, it’s hard to understand how that works.

I have this for the position setting :

pl.mesh.localPosition = Vector3.Slerp(Vector3.zero, pl.mesh.localPosition, 15f * Time.fixedDeltaTime);

The issue is, in reality, I want my child to always be positioned +transform.up * 0.25f - transform.forward * 0.5f relative to the parent (“transform” being the parent transform).

When I try using these or the child’s transform, it gives weird results (that vary depending on the parent rotation).

Basically, with the code I showed above, I have this (the collider is the parent, the purple model is the child):

And I want this (here it’s hardcoded) :

What should I add to the Slerp’s 2nd argument ?

Well transform.up is basically a Vector3 position (0,1,0) and forward is a Vector3 direction (?,?,?) depending on what way it’s rotated.

So I’m having trouble understanding what the ultimate goal is, as I feel you may be attacking this problem the wrong way.

I assumed you had a flying bot of some sort that needs to fly back to it’s parent(player). Looking at your pictures however throws me for a loop?

It’s a climbing action, what you see is the player, climbing on a surface.
I just want to make the mesh reach the position you see on the 2nd picture with a slerp

Ok, as I thought, you’re approaching this the wrong way. As in, if the parent were to move up by 1, the child would have to move down by 1, and then lerp back to the parent. For an instance as this, that just makes no sense to have them grouped(inherited) together.

So I’ll assume the collider(parent) is a physics material, and does special thinking on what surface material it’s on? And is basically like a grab, or push off of said area to move the child upwards?

Hum, yeah ? Basically what you said, when touching surfaces with certain conditions, the climb action script on the parent is enabled.

I mean, can’t this just be done without changing everything ? It’s the last thing I need to have it finished :confused:

I have to say, I actually don’t understand how your solution work ? It does work, it indeed interpolates the child position to the parent’s but how ?
The parent position isn’t involved at all there. What does this actually do ?

Why is it not something like this ?

child.localPosition = Vector3.Slerp(child.localPosition, parent.localPosition, 15f * Time.fixedDeltaTime);

If I understood better maybe I could find a way to make it work the way it is setup ?

Thanks a lot for the help !

EDIT: So I managed to make it work by putting Vector3.back * 0.5f instead of Vector3.zero
It works flawlessly even though I still don’t know why the start is the end and the end the start

EDIT2: No I saw badly, it actually doesn’t work the way I wanted damn.

Because parent.localPosition makes no sense, for one… The childs local is always (0,0,0) from parent, unless you offset it. So if player(parent) is at (123,0,789) in world space(which would be the same as it’s local), the child if right on top of him would have a local of (0,0,0) from parent. Because when using hierarchy of objects, that’s all they need to know.

Now am I saying that there would never be a use for a child object to give its world position? No, it might actually be needed in some cases, except yours…

Thinking on your whole setup, there’s no reason for you to have a child or parent move in relation to how the other moves. Unless you were making some real-physics based VR game like “Cliffhanger”. You only need one object(the player) and according to what surface he’s on moves at a set speed accordingly(or in bursts to pretend like he’s climbing).

You may be thinking of how animations make things “look like” they’re actually doing something, but there not. Animations are just pre-recorded mesh movements that only work in a case-by-case basis. So if your trying to approach this action in your game, applying real-life physics to a game, you’re gonna do nothing but give yourself headaches.

Trust me, I know, one of my projects is a human mesh that literally uses it’s feet to move, with contact of a load bearing foot. And moves it’s body in relation to it’s surroundings, along with it’s head, arms, and hands. It’s the most ambitious project I ever took on, and it’s been placed to the far back burner for now(due to headaches), lol…

But games really use simple logic, and the developer himself is a magician to make you think otherwise, when you see things act like they’re really thinking. It’s all pre-made, and recorded…

However, with how crazy AI is getting, it won’t be long before I can have AI run my human mesh, just like it’s a real boy!

But just keep it simple for now. :slight_smile:

From what I’ve seen, and the people I talked to, I thought it was a good setup to have a character be a gameobject with children such as the mesh, the sounds, the effects etc.

It usually works well, and the mesh follows the parent all the time except for this bit because of this :

This is without any position/rotation lerp on the mesh (I can’t lerp the parent position because then the raycasts fire on the wrong places and everything’s a mess, and I’ve already spent too much time on this action for my own sanity) :

9251079--1293501--bandicam-2023-08-26-00-05-02-504.gif

With a rotation lerp I get this :
9251079--1293504--bandicam-2023-08-26-00-04-09-781.gif

And my goal is this (bad quality, but basically it lerps position and rotation) :
9251079--1293507--bandicam-2023-08-26-00-08-26-841.gif

I think I can’t use the localPosition of the mesh, I need to save the global position of the mesh on the previous frame, every frame and lerp on this but it doesn’t work and I can’t figure out why.

I do this every frame :

prevMeshPosition = pl.mesh.position;
pl.mesh.position = Vector3.Slerp(prevMeshPosition, transform.position, 15f * Time.fixedDeltaTime);

Why doesn’t this work ? I mean, I’m litterally setting the mesh position regardless of the parent right ? (sort of)

At some point in time it’s at position (x, y, z), I save that in prevMeshRotation, and then say “mesh position is now wherever the prevMeshRotation is + a lerp step to the parent’s global position”.
And repeat, again and again.

Do you know how to make this work somehow ?

Plus, I do exactly that for the rotation, and it works no problem :

 Quaternion prevMeshRotation = pl.mesh.rotation;
pl.mesh.rotation = Quaternion.Slerp(prevMeshRotation, Quaternion.LookRotation(-transform.up, transform.forward), 15f * Time.fixedDeltaTime);

Why is position different ?

Ok, so I completely misunderstood you, I thought you had the parent using a collider to move with the child staying still, then the child moving to compensate new position(like a hand pulling up a climber up a cliff). So way off on my part, sorry!

Yes, it’s perfectly fine to have a empty gameObject that uses the child mesh as the player in game. I do that all the time.

So in this case, you already have the parent using the surface normal, awesome! Now all you need to do is actually get the child’s world rotation(ironic, I know) so it knows to stand straight up, regardless of incline parent is on. That would be Vector3.up(if the world is normal up/down).

So you do want to slerp from the (child)world previous rotation, to world up. Except for climbing up a vertical as the example shows, that’s almost like a 45 degree angle.

As far as your child position, that looks fine *

Hey, thanks for all the replies ! Now I have to ask, and I hope I’m not pushing it, but it’s been hours of trying and failing and my eyes genuinely hurt. Would you mind telling me the formula for this please ?

But you’ll notice in that example, the child doesn’t move from it’s position(from parent), all it does is change its rotation due to the surface angle it’s on. Magic!

It would look very similar to this:

pl.mesh.rotation = Quaternion.Slerp(parentRotation, Quaternion.Euler(Vector3.up), 15f * Time.fixedDeltaTime);

I don’t have a testable setup right now, so the parentRotation might need changed to something else, but the second parameter definitely needs to be world up(Vector3.up).

was error, might need to refresh page ^