Attaching an object to another.

Hi, I’m a newbie. I’ve this code for pushing objects:

public class ObstaclePush : MonoBehaviour
{
    [SerializeField]
    private float forceMagnitude;

private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        Rigidbody rigidbody = hit.collider.attachedRigidbody;

        if (rigidbody != null)
        {
            Vector3 forceDirection = hit.gameObject.transform.position - transform.position;
            forceDirection.y = 0;
            forceDirection.Normalize();

            rigidbody.AddForceAtPosition(forceDirection * forceMagnitude, transform.position, ForceMode.Impulse);
        }
    }
}

I want to attach the object1 to object2 when object1 collides with object2 so the object2 stays firm during pushing.

Thank you so much.

You may use Joints if you want the objects to each have their own physics (Rigidbodies).

Alternately you can just parent a bunch of different colliders together to make a composite single physics object, such as making a hammer out of a cylinder and a cube.

2 Likes

Sorry, I didn’t quite understand. Could you show it on the code above if possible?

It’s not code. Read the article.

1 Like

Yes, I finally figured it out. It attaches but not on collision. I still can’t figured it out how the two objects attach together if the collision is detected.

Use AddComponent to add whatever joint you want.

Then set the settings however you want. You can see in the API that all of the settings are exposed (All the same settings that are in the editor):

At the very least, you’ll need to set connectedBody to other object’s rigidbody. You can access this through the collision object that’s passed in to the OnCollisionEnter.

2 Likes

Do you mean like this:

 void OnCollisionEnter(Collision hit)
{
     foreach (ContactPoint contact in hit.contacts)     
     {
         FixedJoint fixedJoint = gameObject.AddComponent<FixedJoint>();
         fixedJoint.anchor = contact.point;
         fixedJoint.connectedBody = hit.rigidbody;
     }
}

and like this:

 Rigidbody rBody = GetComponent<Rigidbody>();
void EnableRagdoll()
{
     rBody.isKinematic = false;
     rBody.detectCollisions = true;
}
void DisableRagdoll()
{
     rBody.isKinematic = true;
     rBody.detectCollisions = false;
}

How can I merge this two stack of codes properly. Could you show it please?

Yes exactly. If I were you, though, I would only make one joint for the whole thing. Making a joint for every contact point seems like it might be needlessly complicated and I wouldn’t be surprised if the physics engine has trouble with it.

1 Like

Here is my project: https://drive.google.com/file/d/1rEmfp7jIqbpINo9oRMI_LZJr8HqlHaES/view?usp=sharing . I applied Fixed Joint on Doozy. I want to attach the Soccer Ball to Doozy when Doozy collides with the ball. On run-time as you can see that the Soccer Ball attaches on the character without detecting if they are collided.

Another problem I noticed with the code that you posted above:

void OnCollisionEnter(Collision hit)
{
     foreach (ContactPoint contact in hit.contacts)    
     {
         FixedJoint fixedJoint = gameObject.AddComponent<FixedJoint>();
         fixedJoint.anchor = contact.point;
         fixedJoint.connectedBody = hit.rigidbody;
     }
}

I assume this attached to your player? OnCollision can be fired-off whenever the player collides with any collider. Could be a wall or the ground, or any other object. Before you add the joint, you want to check and make sure that hit.gameObject is actually the ball that you want attached and not something else. You can do this with a hit.gameObject.CompareTag(), for example.

1 Like

Good morning,
I have added a script called “Stick Ball” and it is the component of the player:

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

public class StickBall : MonoBehaviour
{
  
    void OnCollisionEnter(Collision hit)
    {
        foreach (ContactPoint contact in hit.contacts)
        {
            FixedJoint fixedJoint = gameObject.AddComponent<FixedJoint>();
            fixedJoint.anchor = contact.point;
            fixedJoint.connectedBody = hit.rigidbody;
        }
    }

    Rigidbody rBody = GetComponent<Rigidbody>();
    void EnableRagdoll()
    {
        rBody.isKinematic = false;
        rBody.detectCollisions = true;
    }
    void DisableRagdoll()
    {
        rBody.isKinematic = true;
        rBody.detectCollisions = false;
    }
}

But it gives this error message: “A field initializer cannot reference the non-static field, method or property ‘Component.GetComponent()’”

You need to initialize it in Awake() or later:

Rigidbody rBody;

void Awake()
{
    rBody = GetComponent<Rigidbody>();
}

Thank you. I want to attach the ball to the player when they collide. But the ball doesn’t get attached to the player:

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

public class StickBall : MonoBehaviour
{

    void OnCollisionEnter(Collision hit)
    {
        foreach (ContactPoint contact in hit.contacts)
        {
            FixedJoint fixedJoint = gameObject.AddComponent<FixedJoint>();
            fixedJoint.anchor = contact.point;
            fixedJoint.connectedBody = hit.rigidbody;
        }
    }

    Rigidbody rBody;
    void Awake()
    {
        rBody = GetComponent<Rigidbody>();
    }
    void EnableRagdoll()
    {
        rBody.isKinematic = false;
        rBody.detectCollisions = true;
    }
    void DisableRagdoll()
    {
        rBody.isKinematic = true;
        rBody.detectCollisions = false;
    }
}

I’ve this for pushing the ball but after a few steps the ball moves aside. I want the ball stay firm on player’s feet:

private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        Rigidbody rigidbody = hit.collider.attachedRigidbody;

        if (rigidbody != null)
        {
            Vector3 forceDirection = hit.gameObject.transform.position - transform.position;
            forceDirection.y = 0;
            forceDirection.Normalize();

            rigidbody.AddForceAtPosition(forceDirection * forceMagnitude, transform.position, ForceMode.Impulse);
        }
    }

Just check the tutorials on youtube they explain things better than I would (also not the thing I know best in Unity).

1 Like

I’ve checked tutorials on Youtube,I’m not succeeded in finding a video which satisfies my needs. So I found this:

 public void OnCollisionEnter(Collision col)
     {
         col.gameObject.transform.parent = Player.transform;
         if (col.transform.tag == "Player")
         {
             transform.parent = col.transform;
         }
     }

However it notifies me with this error message : “The name ‘identifier’ does not exist in the current context” though I have a object called Player.

I have this for the Player:

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

public class Player : MonoBehaviour
{
    private Ball ballAttachedToPlayer;

    public Ball BallAttachedToPlayer { get => ballAttachedToPlayer; set => ballAttachedToPlayer = value; }
    // Start is called before the first frame update

And this for the Ball:

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

public class Ball : MonoBehaviour
{
    private bool stickToPlayer;
    [SerializeField] private Transform transformPlayer;
    float speed;
    Vector3 previousLocation;
     Player scriptPlayer;

    public bool StickToPlayer { get => stickToPlayer; set => stickToPlayer = value; }
    // Start is called before the first frame update
    void Start()
    {
       scriptPlayer = transformPlayer.GetComponent<Player>;
    }

    // Update is called once per frame
    void Update()
    {
        if (!StickToPlayer)
        {
            float distanceToPlayer = Vector3.Distance(transformPlayer.position, transform.position);
            if (distanceToPlayer < 0.5)
            {
                stickToPlayer = true;
                scriptPlayer.BallAttachedToPlayer = this;
            }
        }
    }
}

It gives me this error: “Cannot convert method group ‘Identifier’ to non-delegate type ‘Player’. Did you intend to invoke the method?”

You’ve made a typo line 17. Look for examples of calling GetComponent and compare them with your code.

1 Like

I finally made it when player collide with ball the ball attaches to the player. Now I want the player kick the ball. I’ve arranged this stack of code that I attached it to Player:

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

public class ShootBall : MonoBehaviour
{
    private Ball ballAttachedPlayer;
    [SerializeField]
 
    public Ball BallAttachedToPlayer { get => ballAttachedPlayer; set => ballAttachedPlayer = value; }
 
void Update()
    {
        if (Input.GetKey("k"))
        {
            if (ballAttachedPlayer != null)
         
                ballAttachedPlayer.StickToPlayer = false;
         
                Rigidbody rigidbody = ballAttachedPlayer.transform.gameObject.GetComponent<Rigidbody>();
                rigidbody.AddForce(transform.forward * 20f, ForceMode.Impulse);

            ballAttachedPlayer = null;
        }
    }
}

And I have this attached to Ball object:

public class Ball : MonoBehaviour
{
    [SerializeField] private Transform transformPlayer;
    private bool stickToPlayer;
    private Transform playerBallPosition;
    float speed;
    Vector3 previousLocation;
    ShootBall shootBall;

    public bool StickToPlayer;
    // Start is called before the first frame update
    void Start()
    {
        playerBallPosition = transformPlayer.Find("BallLocation");
        shootBall = transformPlayer.GetComponent<ShootBall>();
    }

    // Update is called once per frame
    void Update()
    {
        if (!stickToPlayer)
        {
            float distanceToPlayer = Vector3.Distance(transformPlayer.position, transform.position);
            if (distanceToPlayer < 0.5)
            {
                stickToPlayer = true;
                shootBall.BallAttachedToPlayer = this;
            }
        }
        else
        {
            Vector2 currentLocation = new Vector2(transform.position.x, transform.position.z);
            speed = Vector2.Distance(currentLocation, previousLocation) / Time.deltaTime;
            transform.position = playerBallPosition.position;
            transform.Rotate(new Vector3(transformPlayer.right.x, 0, transformPlayer.right.z), speed, Space.World);
            previousLocation = currentLocation;
        }
    }
}

The ball doesn’t get kicked in runtime. It gives this error: “Object reference not set to an instance of an object (at ShootBall.cs:28).”
What should I do.

Thank you so much…

Be careful of the if statements:

            if (ballAttachedPlayer != null)
        
                ballAttachedPlayer.StickToPlayer = false;
        
                Rigidbody rigidbody = ballAttachedPlayer.transform.gameObject.GetComponent<Rigidbody>();
                rigidbody.AddForce(transform.forward * 20f, ForceMode.Impulse);
            ballAttachedPlayer = null;

it is interpreted like that:

            if (ballAttachedPlayer != null) ballAttachedPlayer.StickToPlayer = false;      
            Rigidbody rigidbody = ballAttachedPlayer.transform.gameObject.GetComponent<Rigidbody>();
            rigidbody.AddForce(transform.forward * 20f, ForceMode.Impulse);
            ballAttachedPlayer = null;

And this is how you trigger a no reference error. So you need to enclose the code block like so:

            if (ballAttachedPlayer != null) {        
                ballAttachedPlayer.StickToPlayer = false;
        
                Rigidbody rigidbody = ballAttachedPlayer.transform.gameObject.GetComponent<Rigidbody>();
                rigidbody.AddForce(transform.forward * 20f, ForceMode.Impulse);
                 ballAttachedPlayer = null;
             }
1 Like