Open a Door Front and Back in Unity3D similar to A

2019-07-29 16:02发布

问题:

I am attempting to implement a feature similar to Amnesia: The Dark Descent's that makes the player hold down the mouse button and drag forwards or backwards on a door in order to open it (if you are not familiar see Door Example at about 36:30).

I have the following code, and it sort of works, but the opening is jittery and bounces back and forth a bit, and I cannot figure out if I'm using transform.Rotate incorrectly:

    if (previousMousePosition == garbageVector) // if this is the first frame, create a reference for previousMousePosition
        previousMousePosition = Input.mousePosition;
    else
    {
        // else find the difference and rotate
        rotationAmount = (Input.mousePosition.x - previousMousePosition.x);
        if (rotationAmount < 0)
            this.transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime);
        else if (rotationAmount > 0)
            this.transform.Rotate(Vector3.down * rotationSpeed * Time.deltaTime);

    }

Note: this script is attached to the door in question.

Also, my code doesn't take into account which side of the door the player is on when it comes to determining rotation. Does anyone have any tips on where I might start with that?

回答1:

The code in your question is too small to accomplish that. Any ways you can easily do that by changing the transform.localEulerAngles. The code I attached in this answer can do that. T test the the script, follow direction below. This also describe how to determine front and back doors.

1.Create a simple Cube named name it Door.

2.Remove the Box Collider that is automatically attached to the newly created cube/Door.

3. Select the Door, Right click on and click "Create Empty". Rename that new GameObject to FrontCollider. Make sure that FrontCollider is now the child of Door GameObject.

4.Select FrontCollider, add BoxCollider to it. Position the Collider to the front of the Door(Front of camera).

5.Duplicate FrontCollider and rename the new GameObject BackCollider. Then move the BackCollider GameObject to the back of the Door GameObject. The best way to make sure that it aligns well is if the z position of the FrontCollider is -2, set the z position of BackCollider to 2. So all you do is change the z position of FrontCollider and BackCollider colliders to be opposite of each other.

5.Create an empty GameObject and name it Door Parent Make sure it is not a child of any GameObject. We need to use this GameObject to change the pivot point of the Door to the left. So that the Door will actually rotate like a door (one side)instead of around the center of itself.

6.Use the Move Tool and Move the Door Parent Gameobject to the left side of the Door. Do NOT rotate it. Just move it. Once you think that wherever the Door Parent is now located is where the Door should rotate around, attach the Door Script below to the Door Parent GameObject not the Door GameObject.

7.Drag the FrontCollider GameObject to the frontDoorCollider slot in the script. Drag the BackCollider GameObject to the backDoorColliderin slot in the script. That's it.

When standing in front of the door, click, hold and move the mouse down, it will PULL the door open. Moving it up will close it.

When stading in the back of the door, click, hold and move the mouse up, it will PUSH the door open. Moving it up will close it.

public class Door : MonoBehaviour
{
    public float ySensitivity = 300f;
    public float frontOpenPosLimit = 45;
    public float backOpenPosLimit = 45;

    public GameObject frontDoorCollider;
    public GameObject backDoorCollider;

    bool moveDoor = false;
    DoorCollision doorCollision = DoorCollision.NONE;


    // Use this for initialization
    void Start()
    {
        StartCoroutine(doorMover());
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Debug.Log("Mouse down");

            RaycastHit hitInfo = new RaycastHit();
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo))
            {
                if (hitInfo.collider.gameObject == frontDoorCollider)
                {
                    moveDoor = true;
                    Debug.Log("Front door hit");
                    doorCollision = DoorCollision.FRONT;
                }
                else if (hitInfo.collider.gameObject == backDoorCollider)
                {
                    moveDoor = true;
                    Debug.Log("Back door hit");
                    doorCollision = DoorCollision.BACK;
                }
                else
                {
                    doorCollision = DoorCollision.NONE;
                }
            }
        }

        if (Input.GetMouseButtonUp(0))
        {
            moveDoor = false;
            Debug.Log("Mouse up");
        }
    }

    IEnumerator doorMover()
    {
        bool stoppedBefore = false;
        float yRot = 0;

        while (true)
        {
            if (moveDoor)
            {
                stoppedBefore = false;
                Debug.Log("Moving Door");

                yRot += Input.GetAxis("Mouse Y") * ySensitivity * Time.deltaTime;


                //Check if this is front door or back
                if (doorCollision == DoorCollision.FRONT)
                {
                    Debug.Log("Pull Down(PULL TOWARDS)");
                    yRot = Mathf.Clamp(yRot, -frontOpenPosLimit, 0);
                    Debug.Log(yRot);
                    transform.localEulerAngles = new Vector3(0, -yRot, 0);
                }
                else if (doorCollision == DoorCollision.BACK)
                {
                    Debug.Log("Pull Up(PUSH AWAY)");
                    yRot = Mathf.Clamp(yRot, 0, backOpenPosLimit);
                    Debug.Log(yRot);
                    transform.localEulerAngles = new Vector3(0, yRot, 0);
                }
            }
            else
            {
                if (!stoppedBefore)
                {
                    stoppedBefore = true;
                    Debug.Log("Stopped Moving Door");
                }
            }

            yield return null;
        }

    }


    enum DoorCollision
    {
        NONE, FRONT, BACK
    }
}