Search code examples
c#unity-game-enginegame-developmentgame-physicsgame-engine

Unity Put Item System


I have a head object in my player object, I have a hand object in my head object and when the player looks at an item in the direction of the head object and presses the E key, it takes the item to the child of the hand object and moves it, but when I press the F key, I want it to leave it in the position I look at. I wrote a code for this, the code works properly, but sometimes the item goes to the specified location first and immediately goes back to the hand object and falls to the ground. Can someone help...

using UnityEngine;

public class Player : MonoBehaviour
{
    Rigidbody rb;

    float horizontalAxis;
    float verticalAxis;
    float mouseHorizontal;
    float mouseVertical;
    public float moveSpeed;
    public float mouseSensivity;
    float mouseLimitX = 70;
    GameObject head;
    GameObject hand;
    CharacterController controller;
    public Material outlinerMaterial;

    // Bools
    bool running = false;
    bool cursorLock = false;
    bool grounded = false;
    bool holding = false;

    // Abilities

    float runSpeed;
    float holdDistance = 4f;

    // Holding System

    Renderer objectRenderer = null;
    Material[] originalMaterials = null;
    bool isLookingObject = false;
    GameObject lookingItem = null;
    GameObject holdingItem = null;
    Quaternion lookingItemRotation;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        runSpeed = 0.7f;
        moveSpeed = 1f + runSpeed;
        mouseSensivity = 500f;
        head = GameObject.Find("Head");
        hand = GameObject.Find("Hand");
        head.transform.localEulerAngles = Vector3.zero;
        CursorLock();

    }

    void FixedUpdate()
    {
    }

    private void Update()
    {
        GetCharAxis();
        if (cursorLock)
        {
            InputController();
            MouseLook();
            HoldingControl();
            Movement();
            DebugList();
        }
    }
    private void LateUpdate()
    {
        if (holding)
        {
            holdingItem.transform.position = hand.transform.position;
            holdingItem.transform.localRotation = lookingItemRotation;
        }
    }

    void GetCharAxis()
    {
        horizontalAxis = Input.GetAxisRaw("Horizontal");
        verticalAxis = Input.GetAxisRaw("Vertical");
        mouseHorizontal = Input.GetAxis("Mouse X");
        mouseVertical = Input.GetAxis("Mouse Y");
    }

    void MouseLook()
    {
        Vector3 currentRotation = head.transform.localEulerAngles;

        float newRotationX = currentRotation.x - mouseVertical * Time.deltaTime * mouseSensivity;
        float newRotationY = currentRotation.y + mouseHorizontal * Time.deltaTime * mouseSensivity;

        newRotationX = Mathf.Repeat(newRotationX + 180f, 360f) - 180f;
        newRotationX = Mathf.Clamp(newRotationX, -mouseLimitX, mouseLimitX);

        head.transform.localEulerAngles = new Vector3(newRotationX, newRotationY, 0);
    }

    void Movement()
    {
        Vector3 moveDirection = head.transform.forward * verticalAxis + head.transform.right * horizontalAxis;
        moveDirection.y = 0f;
        moveDirection.Normalize();
        rb.Move(rb.position + moveDirection * moveSpeed * Time.fixedDeltaTime, Quaternion.identity);
    }
    void HoldingControl()
    {
        RaycastHit hit;
        if (Physics.Raycast(head.transform.position, head.transform.forward, out hit, holdDistance))
        {
            if (hit.collider.gameObject.CompareTag("Item") && holding == false)
            {
                if (lookingItem != hit.collider.gameObject)
                {
                    ResetLookingObject();

                    lookingItem = hit.collider.gameObject;
                    lookingItemRotation = lookingItem.transform.localRotation;
                    objectRenderer = lookingItem.GetComponent<Renderer>();

                    if (objectRenderer != null)
                    {
                        SetOutlineMaterial();
                    }
                }
            }
            else
            {
                ResetLookingObject();
            }
        }
        else
        {
            ResetLookingObject();
        }
    }

    void ResetLookingObject()
    {
        if (isLookingObject && lookingItem != null)
        {
            objectRenderer.materials = originalMaterials;
            lookingItem = null;
            objectRenderer = null;
            isLookingObject = false;
            originalMaterials = null;
        }
    }

    void SetOutlineMaterial()
    {
        originalMaterials = objectRenderer.materials;
        Material[] newMaterials = new Material[originalMaterials.Length + 1];
        for (int i = 0; i < originalMaterials.Length; i++)
        {
            newMaterials[i] = originalMaterials[i];
        }
        newMaterials[originalMaterials.Length] = outlinerMaterial;
        objectRenderer.materials = newMaterials;
        isLookingObject = true;
    }
    bool CursorLock()
    {
        if (cursorLock == false)
        {
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
            cursorLock = true;

        }
        else if (cursorLock == true)
        {

            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
            cursorLock = false;
        }
        return cursorLock;
    }
    void InputController()
    {
        if (grounded)
        {
            HandleRunning();

            if (Input.GetKey(KeyCode.Space))
            {
                rb.AddRelativeForce(new Vector3(0, 100, 0));
                grounded = false;
            }

            HandleItemInteraction();
        }
    }

    void HandleRunning()
    {
        if (Input.GetKey(KeyCode.LeftShift) && !running)
        {
            running = true;
            moveSpeed += runSpeed;
        }
        else if (!Input.GetKey(KeyCode.LeftShift) && running)
        {
            running = false;
            moveSpeed -= runSpeed;
        }
    }

    void HandleItemInteraction()
    {
        if (holdingItem != null && holding && Input.GetKey(KeyCode.F))
        {
            PutItem();
        }

        if (Input.GetKey(KeyCode.E) && lookingItem != null && isLookingObject && !holding)
        {
            PickupItem();
        }
        else if (Input.GetKey(KeyCode.Q) && holding)
        {
            DropItem();
        }
    }

    void PutItem()
    {
        RaycastHit hit;
        if (Physics.Raycast(head.transform.position, head.transform.forward, out hit, holdDistance))
        {
            Debug.Log("PutItem work");
            holdingItem.transform.SetParent(null);
            Rigidbody ItemRB = holdingItem.gameObject.GetComponent<Rigidbody>();
            ItemRB.isKinematic = false;
            ItemRB.gameObject.transform.position = hit.point + new Vector3(0,0.02f,0);
            holding = false;
            holdingItem = null;
        }
        else
        {
            Debug.Log("PutItem error");
        }
    }
    void PickupItem()
    {
        Debug.Log("PickupItem work");
        lookingItem.gameObject.transform.SetParent(hand.transform, false);
        lookingItem.gameObject.GetComponent<Rigidbody>().isKinematic = true;
        Transform childTransform = hand.gameObject.transform.GetChild(0).GetComponent<Transform>();
        childTransform.localPosition = Vector3.zero;
        holdingItem = lookingItem;
        ResetLookingObject();
        holding = true;
    }

    void DropItem()
    {
        Debug.Log("DropItem work");

        holdingItem.transform.SetParent(null);
        Rigidbody ItemRB = holdingItem.gameObject.GetComponent<Rigidbody>();
        ItemRB.isKinematic = false;
        ItemRB.gameObject.transform.rotation = ItemRB.gameObject.transform.localRotation;
        holding = false;
        holdingItem = null;
        ResetLookingObject();
    }
    private void DebugList()
    {
        print($"Holding = {holding},\n LookingItem = {lookingItem}");
    }
    private void OnCollisionExit(Collision other)
    {
        if (other.gameObject.CompareTag("Floor"))
        {
            grounded = false;
        }
    }
    private void OnCollisionStay(Collision other)
    {

        if (other.gameObject.CompareTag("Floor"))
        {
            grounded = true;
        }
    }
}

Solution

  • Use FixedUpdate for any functions that involve the physics system. For example, Movement(), HoldingControl(), InputController() and HandleItemInteraction().

    Calling physics functions in Update/LateUpdate could be causing your issue.