Search code examples
unity-game-enginerotationgame-physics

Unity: 3D top-down rotate item around player


I'm trying to get an object to always be "in front" of the player, from a top down perspective. Here's screenshots demonstrating what I'm trying to do.

enter image description here

So as you can see, when the blue capsule (player) picks up the green capsule (item), the item correctly hovers in front of the player (indicated by the z-axis blue arrow), but when the player turns in any other direction, the item doesn't follow, and instead stays in exactly the same position relative to the player.

enter image description here

My player controller script looks as follows:

using UnityEngine;

public class PlayerController : MonoBehaviour {

  public float movementSpeed = 10;

  private Rigidbody body;
  private Vector2 movement;

  void Start() {
    body = GetComponent<Rigidbody>();
  }

  void Update() {
    movement.x = Input.GetAxis("Horizontal");
    movement.y = Input.GetAxis("Vertical");
  }

  void FixedUpdate() {
    body.velocity = new Vector3(movement.x * movementSpeed * Time.deltaTime, 0, movement.y * movementSpeed * Time.deltaTime);

    // this is what updates the direction of the blue arrow in the direction of player movement
    if(movement.x != 0 || movement.y != 0) {
      body.rotation = Quaternion.LookRotation(body.velocity);
    }
  }
}

And here's my pickup script (where the item's position is supposed to be updated):

using UnityEngine;

public class Pickup : MonoBehaviour {

  private GameObject item;
  public float carryDistance = 1;

  void OnCollisionEnter(Collision collision) {
    if(collision.gameObject.CompareTag("Item")) {
      item = collision.gameObject;
    }
  }

  void Update() {
    if(item) {
      item.transform.position = transform.position + new Vector3(0, 0, carryDistance);
    }
  }
}

So to reiterate my question: How can I update the item's position such that it's always hovering next to the player on the side of the blue arrow?


Solution

  • You can achieve this by using players transform.forward

    item.transform.position = transform.position + (transform.forward * carryDistance) 
    + (Vector3.up * carryHeight);
    

    Alternatively you can just add empty child gameobject to the player, position it in front of the player and use its transform position and rotation to position the picked up object.

    public class Pickup : MonoBehaviour {
    
      public Transform pickupPositionTransform;
      private GameObject item;
      public float carryDistance = 1;
    
      void OnCollisionEnter(Collision collision) {
        if(collision.gameObject.CompareTag("Item")) {
          item = collision.gameObject;
        }
      }
    
      void Update() {
        if(item) {
          item.transform.position = pickupPositionTransform.position;
          item.transform.rotation = pickupPositionTransform.rotation;
        }
      }
    }