Search code examples
unity-game-enginevelocitygameobject

Single controller transferring Rigidbody2D velocity


I am making a Unity game where you are a player but can transform into a ball by pressing the "f" key. The way I do this is with one central gameObject with a script that controls the player, and ball game objects. I have code for the player movement at the beginning but my problem occurs when I switch the game objects. I set one to active, and the other to not active which works. But I can't transfer one gameObject's velocity to the other. Transferring the position works, and I use basically the same method to switch the velocity.

Here is the code:

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

public class TransformerScript : MonoBehaviour
{
    // Player Vars
    public GameObject player;
    public Rigidbody2D playerRB;

    // Ball Vars
    public GameObject ball;
    public Rigidbody2D ballRB;

    public bool playerActive = true;

    
    // Player Movement Vars
    public bool grounded = true;

    public float speed = 5;

    public float jumpHeight = 5;

    float moveVelocity;

    // Collision Detection
    void OnTriggerEnter2D()
    {
        grounded = true;
    }
    void OnTriggerExit2D()
    {
        grounded = false;
    }

    void Start()
    {
        
    }

    void Update()
    {
        // Swaping sprites
        if (Input.GetKeyDown(KeyCode.F))
        {
            // Set player to active
            if (playerActive)
            {
                playerActive = false;
                ball.SetActive(true);
                player.SetActive(false);

                // Transform and velocity
                ball.transform.position = player.transform.position;
                ballRB.velocity = playerRB.velocity;
            }

            // Set ball to active
            else
            {
                playerActive = true;
                ball.SetActive(false);
                player.SetActive(true);

                // Transform and velocity
                player.transform.position = ball.transform.position;
                playerRB.velocity = ballRB.velocity;
            }
        }

        // Player movement
        if (playerActive)
        {
            moveVelocity = 0;

            // Jumping
            if (Input.GetKeyDown(KeyCode.W))
            {
                if (grounded)
                {
                    playerRB.velocity = new Vector2(playerRB.velocity.x, jumpHeight);
                }
            }

            // Left/Right Movement
            if (Input.GetKey(KeyCode.A))
            {
                moveVelocity = -speed;
            }
            if (Input.GetKey(KeyCode.D))
            {
                moveVelocity = speed;
            }

            playerRB.velocity = new Vector2(moveVelocity, playerRB.velocity.y);
        }
    }
}

I can't really think of anything else to try. I can't find any tutorials on this on YouTube or other sources either. Go easy on me I'm new to Unity.


Solution

  • This code is causing your problem:

    ...
    
    // Set player to active
    if (playerActive)
    {
        playerActive = false;
        ball.SetActive(true);
        player.SetActive(false);
    
        // Transform and velocity
        ball.transform.position = player.transform.position;
        ballRB.velocity = playerRB.velocity;
    }
    
    // Set ball to active
    else
    {
        playerActive = true;
        ball.SetActive(false);
        player.SetActive(true);
    
        // Transform and velocity
        player.transform.position = ball.transform.position;
        playerRB.velocity = ballRB.velocity;
    }
    
    ...
    

    Problem: when you deactivate an object with a Rigidbody component:

    • Any velocity it previously had is reset to (0, 0, 0).
    • Any velocity assigned to it when it's still inactive is ignored.

    Solution: I will call the objects "sender object" and "receiver object". The sender object must transfer its own velocity to the receiver object. To solve this problem, you can follow these steps:

    1. Make sure both the sender object and receiver object are active.
    2. Assign the receiver object's velocity with the sender object's velocity value.
    3. Deactivate the sender if you wish.
    ...
    
    if (playerActive)
    {
        playerActive = false;
    
        // 1. Activate the ball object
        ball.SetActive(true);
    
        // 2. Transfer velocity
        ball.transform.position = player.transform.position;
        ballRB.velocity = playerRB.velocity;
    
        // 3. Deactivate the player object
        player.SetActive(false);
    }
    else
    {
        playerActive = true;
    
        // 1. Activate the player object
        player.SetActive(true);
    
        // 2. Transfer velocity
        player.transform.position = ball.transform.position;
        playerRB.velocity = ballRB.velocity;
    
        // 3. Deactivate the ball object
        ball.SetActive(false);
    }
    
    ...
    

    Read more about your problem: