Search code examples
c#unity-game-enginepositiongame-physicsrigid-bodies

Why does this strange jittering occur?


I have a scene in which the player can pick up and drop objects, as well as move and look around.

All player objects are children of an empty game object "MainCharacter":

MainCharacter >
    Capsule (With RigidBody and PlayerMoveScript) >
        PlayerBase (empty - used for checking if grounded)
        MainCamera >
            Hands(With PickUpDrop script)

The object I pick up Lerps to my Hands position, however after my capsule collides with any walls there is a strange jittering which I cannot work out how to fix!!

Heres the .exe:GameTest Heres the data folder : Data

Here are the scripts:

Pick Up and Drop Script:

public bool handsFull = false;

    public float distanceMax = 20f;

    public Transform handPosition;

    public LayerMask canPickUp;

    public GameObject taggedGameObject;

    public bool colliderTriggered;

    public bool bounds;

    public PickedUpObject pickedUpScript;

    public Rigidbody player;

    // Use this for initialization
    void Start () {

        print(FindClosestPickup().name);
        handPosition = transform;
        pickedUpScript = null;

    }

    // Update is called once per frame
    void Update () {


                if (Input.GetKeyDown (KeyCode.E) && !bounds) {
                        if (Physics.CheckSphere (handPosition.position, 2f, canPickUp)) {

                                if (handsFull) {
                                        Drop ();
                                }

                                if (!handsFull) {
                                        PickedUp ();
                                }

                handsFull = !handsFull;

                        }
                }

                if (handsFull) {
                        RotateMovePickedUpObject();
                }   


        }



    private void PickedUp(){

        //Closest object to top of list
        taggedGameObject = (GameObject)FindClosestPickup();

        taggedGameObject.collider.isTrigger = true;



        taggedGameObject.rigidbody.useGravity = false;
        taggedGameObject.rigidbody.isKinematic = true;

        pickedUpScript = taggedGameObject.GetComponent<PickedUpObject> ();

        Debug.Log ("Pick Up");


    }

    private void RotateMovePickedUpObject(){

        //Rotate

        if(Input.GetKeyDown(KeyCode.End)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 0, 45);
        }
        if(Input.GetKeyDown(KeyCode.Delete)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 45, 0);
        }
        if(Input.GetKeyDown(KeyCode.PageDown)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(0, -45, 0);
        }
        if(Input.GetKeyDown(KeyCode.Home)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 0, -45);
        }
        if(Input.GetKeyDown(KeyCode.PageUp)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(-45, 0, 0);
        }
        if(Input.GetKeyDown(KeyCode.Insert)){
            taggedGameObject.transform.localRotation *= Quaternion.Euler(45, 0, 0);
        }

        taggedGameObject.transform.position = Vector3.Lerp(taggedGameObject.transform.position, handPosition.position, (1 - Mathf.Exp( -20 * Time.smoothDeltaTime )) * 10);

    }


    private void Drop(){

        taggedGameObject.collider.isTrigger = false;

        taggedGameObject.rigidbody.useGravity = true;
        taggedGameObject.rigidbody.isKinematic = false;

        taggedGameObject = null;

        Debug.Log ("Drop");

        pickedUpScript = null;

    }

    private GameObject FindClosestPickup() {

        //Find closest gameobject with tag
        GameObject[] gos;
        gos = GameObject.FindGameObjectsWithTag("pickup");
        GameObject closest = null;
        float distance = Mathf.Infinity;
        Vector3 position = transform.position;

        foreach (GameObject go in gos) {
            Vector3 diff = go.transform.position - position;
            float curDistance = diff.sqrMagnitude;
            if (curDistance < distance) {
                closest = go;
                distance = curDistance;
            }
        }

        return closest;
    }

}

The Picked Up Objects Script:

public PickUpDrop pickUpScript;
    public GameObject thisOne;
    public Color thecolor;
    public bool inObject;

    // Use this for initialization
    void Start () {
        thisOne = this.gameObject;
    }

    // Update is called once per frame
    void Update () 
    {
        thecolor = thisOne.renderer.material.color;

    if (pickUpScript.taggedGameObject != thisOne)
        {
            gameObject.renderer.material.color = Color.gray;
        }

    if (pickUpScript.taggedGameObject == thisOne)
        {
            Color color = renderer.material.color;
            color.a = 0.5f;
            renderer.material.color = color;
        }
    }

    void OnTriggerEnter ()
    {
        if (thisOne == pickUpScript.taggedGameObject)
        {
            inObject = true;
            pickUpScript.bounds = true;
            gameObject.renderer.material.color = Color.red;

        }
    }

    void OnTriggerExit()
    {
        if(thisOne == pickUpScript.taggedGameObject)
        {
            inObject = false;
            pickUpScript.bounds = false;
            gameObject.renderer.material.color = Color.gray;        
        }
    }

}

Solution

  • taggedGameObject.transform.position = Vector3.Lerp(taggedGameObject.transform.position, handPosition.position, (1 - Mathf.Exp( -20 * Time.smoothDeltaTime )) * 10);
    

    This line will keep moving the object towards the hand's position. If you have a rigidbody attached to the game object you're moving then the physics acting on that object during the physics calculation will conflict with the manual movement of the object during the Update function.

    It depends on what you would like to happen when this conflict occurs as to the solution. If you simply want the 'jittering' to stop and still be able to hold objects against other physical objects, then use this;

    taggedGameObject.rigidbody.AddForce( ( taggedGameObject.transform.position - handPosition.position ) * force );
    

    This will keep all interactions with the rigidbody. You'll have to tweak the force you move the object with, and perhaps disable gravity on the tagged game object while it's in the players hands. But it should have the desired effect.