Parenting and transferring child objects

Hey guys,

Currently trying to flesh out the last big component of my game, but having trouble.

I need to parent an object to player one and make it so that if player 1 collides with player 2 the child object transfers over to player 2.

Believe me. I’ve been digging deep on this one. Could use some help from beyond!!!

Thanks in advance. I HAVE no code right now. I’m really stumped.

Well I would imagine it would include pairing OnCollisionEnter (or 2d equivalent) and Transform.SetParent in some manner.

2 Likes

this is where I meant to post the code I’m using for this question. Here it is. Still doesn’t seem to be working

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeBall_02 : MonoBehaviour
{
    public GameObject child;
    public Transform Player_02;


    private void OnCollisionEnter(UnityEngine.Collision collision)
    {
        if (collision.gameObject.name == "Player_01")
        {
            child.transform.SetParent(Player_02, true);
        }
    }
}

Well, get to debugging, same as Kurt posted in your other thread. “It doesn’t seem to be working” isn’t the point at which you start posting on the forums - it’s the point at which you start debugging.

2 Likes

I really just need a way to differentiate between players. Any help would be appreciated.

Got something working here … not behaving as smoothly as I would like. The transfer of the child object is kind of rocky.

Must be because I’m updating the parent to be true every frame. Hmm …

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class BallCarrier : MonoBehaviour
{
    public GameObject child;
    public Transform parent;
    public Transform newParent;

    // Update is called once per frame
    void Update()
    {
        child.transform.SetParent(parent, true);
    }

    private void OnCollisionEnter(UnityEngine.Collision collision)
    {
        if (collision.gameObject.name == "Player_02")
            child.transform.SetParent(newParent, true);
        child.transform.SetParent(parent, false);
    }
}

Yeah! Still here, brothers and sisters. Gotta get that child under control!!!

Just looking for some tips on how to limit the motion of the child object, given the above script

You will need to be a lot more specific. Are you trying to make it so that, when two players touch, the ball moves from a specific spot on one player to a specific spot on another player?

As-is, the ball will just get attached to the other player at whatever position it happened to be in when they touched.

If that’s what you want, I’d suggest adding empty gameobjects representing where the player’s hands are and parenting the ball to that. Then, you can lerp the ball’s local position towards Vector3.zero to make it snap to the second player’s hand.

Whilst re-applying WorldPosition to the child every frame.
There are many instances in which it’s easy to create some fun ‘race-conditions’ there.

You’re not ‘updating the parent to be true’.
You’re re-parenting it to that parent, and doing this whilst keeping the current worldspace-position (that’s what the ‘true’ (bool worldPositionStays) does).
https://docs.unity3d.com/ScriptReference/Transform.SetParent.html

Thus, every frame you’re:

  1. Setting the Current Parent in child to NULL
  2. Applying the parent’s WorldSpace-Position, -Rotation & -Scale to your LocalToParent-Transform to calculate the new Transformation-Matrix for the child (since it no longer has a parent).
  3. Re-setting the Parent to what it actually was before
  4. Creating a new LocalToParent-Matrix to fit to the current LocalToWorld-Matrix.

tl;dr don’t reparent (with worldPositionStays) every frame.

Well. The “ball” just designates “possession”. So, I switched over to an empty game object and it’s working as I want it to.

Have a new problem, however. I want to set it up so that if player_01 collides with player_02 ON target_01, we get a result. Specifically the parent of the child object changes. And that’s fine. They each work independently, just not together.

Here’s what I’ve been working with. I don’t quite know if this is even possible within the limits of unity. The script is written for player 01, the place is the target, and player 2 is the second condition

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class BallCarrier : MonoBehaviour
{
    public GameObject child;
    public Transform parent;
    public Transform newParent;

    void Start()
    {
        child.transform.SetParent(parent, true);
    }
        private void OnCollisionStay(UnityEngine.Collision collision)
        {

            if ((collision.gameObject.name == "Plane") && (collision.gameObject.name == "Player_02"))
           
            {
            child.transform.SetParent(newParent, true);
    }
   

           

    }
}

Maybe this is what you’re looking for. It requires a collider, a rigidbody, and this script on each player. I added a one second wait coroutine to keep the ball from instantly passing back and forth if they continue to collide in quick succession.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallCarrier : MonoBehaviour {

    public Transform ball;
    public Transform myTransform;
    public Transform otherPlayer;
    [HideInInspector] public bool hasBall = false;
    bool waiting = false;

    void Start () {

        if (myTransform.gameObject.name == "Player 1") {
            ball.transform.SetParent (myTransform);
            hasBall = true;
        }
        if (myTransform.gameObject.name == "Player 2") {
            hasBall = false;
        }

    }

    void OnCollisionEnter (Collision collider) {

        if (collider.transform == otherPlayer && hasBall && !waiting) {
            ball.SetParent (otherPlayer);
            hasBall = false;
            BallCarrier ballCarrier = otherPlayer.GetComponent <BallCarrier> ();
            ballCarrier.hasBall = true;
            StartCoroutine (ballCarrier.Wait ());
            StartCoroutine (Wait ());
        }  
    }

    IEnumerator Wait () {

        waiting = true;
        yield return new WaitForSeconds (1f);
        waiting = false;

    }

}
1 Like

Oh wow! Thank a lot. This gives me a lot to work with. Been scratching my head. Not a lot of answers out there for this one.

I’ll get back and let you know how I do with this!

Damn. Thanks for all the effort. That’s some beautiful script. Can’t image building something like that in a million years.

Got another problem, if you’re interested. I’m full of problems. Lol.

I’ve got to get the collision between player 01 and player 02 to happen (or “register”) on a certain “place” (for example). Just a target region. Player 01 can only steal possession of the ball from player 02 on designated targets (and vice versa)

I’ve messed with adding two conditions to an OnCollisionStay command. (so that player 01 collides with the target at the same time that player 2 collides with the target, and then the exchange of the ball occurs). But that seems to have some problems …?

Add a collider without a renderer to the target location and put the script on it instead of the player. On the players hand or wherever. Good luck!

1 Like

Gosh darn! Can I swear on this forum!

You son of a gun!

You did it! You freaking did it!

Never in a million years, would I …

That was the last component of my game. Can’t say I didn’t bust my rump the last couple of weeks learning how to code. But this is one hurdle where I’ll be VERY happy to accept some helping hands.

Can’t thank you enough.

1 Like

Beautiful. Love this stuff