admin管理员组

文章数量:1387301

I'm trying to rotate the object, that were detected by my raycast. I use the Lerp function, but it doesn't work as I want and I don't know why. I saw the same question, but the problem was that the lerp function was used in the start function, instead of the update function. My function seemed to be running in an update, so I don't understand what the problem is. I'm relatively new to unity, so maybe the answer is obvious, but not for me.

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using static UnityEngine.GraphicsBuffer;

public class PlayerInteraction : MonoBehaviour
{
    [Header("Camera settings")]
    public Camera playerCamera;


    [Header("Raycast")]
    private Ray cameraRay;
    private Vector3 rayStartPosition = new Vector3(Screen.width / 2, Screen.height / 2, 0);
    private float lengthOfRay = 5f;
    private RaycastHit raycastedObject;
    private string objectTag;
    private GameObject hittedObject;


    [Header("Interaction")]
    private KeyCode interactionKey = KeyCode.E;

    [Header("Door settings")]
    private Quaternion startRotation;
    private Quaternion targetOpen;

    void Start()
    {

    }

    void Update()
    {
        RotationOfObject();

    }




    public void RotationOfObject()
    {
        cameraRay = playerCamera.ScreenPointToRay(rayStartPosition);

        if (Physics.Raycast(cameraRay, out raycastedObject, lengthOfRay) && Input.GetKeyDown(interactionKey))
        {
            hittedObject = raycastedObject.collider.gameObject;

            startRotation = hittedObject.transform.rotation;
            targetOpen = new Quaternion(hittedObject.transform.rotation.x, hittedObject.transform.rotation.y + 90f, hittedObject.transform.rotation.z, 0);

            hittedObject.transform.rotation = Quaternion.Lerp(startRotation, targetOpen, 0.01f);
        }
    }
}

I'm trying to rotate the object, that were detected by my raycast. I use the Lerp function, but it doesn't work as I want and I don't know why. I saw the same question, but the problem was that the lerp function was used in the start function, instead of the update function. My function seemed to be running in an update, so I don't understand what the problem is. I'm relatively new to unity, so maybe the answer is obvious, but not for me.

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using static UnityEngine.GraphicsBuffer;

public class PlayerInteraction : MonoBehaviour
{
    [Header("Camera settings")]
    public Camera playerCamera;


    [Header("Raycast")]
    private Ray cameraRay;
    private Vector3 rayStartPosition = new Vector3(Screen.width / 2, Screen.height / 2, 0);
    private float lengthOfRay = 5f;
    private RaycastHit raycastedObject;
    private string objectTag;
    private GameObject hittedObject;


    [Header("Interaction")]
    private KeyCode interactionKey = KeyCode.E;

    [Header("Door settings")]
    private Quaternion startRotation;
    private Quaternion targetOpen;

    void Start()
    {

    }

    void Update()
    {
        RotationOfObject();

    }




    public void RotationOfObject()
    {
        cameraRay = playerCamera.ScreenPointToRay(rayStartPosition);

        if (Physics.Raycast(cameraRay, out raycastedObject, lengthOfRay) && Input.GetKeyDown(interactionKey))
        {
            hittedObject = raycastedObject.collider.gameObject;

            startRotation = hittedObject.transform.rotation;
            targetOpen = new Quaternion(hittedObject.transform.rotation.x, hittedObject.transform.rotation.y + 90f, hittedObject.transform.rotation.z, 0);

            hittedObject.transform.rotation = Quaternion.Lerp(startRotation, targetOpen, 0.01f);
        }
    }
}

Share Improve this question edited Mar 17 at 17:12 ipodtouch0218 3,3709 gold badges14 silver badges29 bronze badges asked Mar 17 at 16:51 dmitry rubanovdmitry rubanov 251 silver badge5 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

Your rotation logic is indeed inside of Update, but it's also inside the Input.GetKeyDown(interactionKey) and Physics.Raycast checks- rotation is only possible on the single frame where you pressed the interaction key.

What you'd want to do instead is keep track of where the door should be, probably through the use of a boolean isOpen; variable, and move it towards that destination inside of Update (without it being inside of the if statement that contains the raycast/key checks). Quaternion.RotateTowards is great for this.

As well, we should also move the door-opening logic to its own behaviour attached to the door itself, instead of having the PlayerInteraction class also be responsible for rotating the door.

For example:

public class PlayerInteraction : MonoBehaviour
{
    // ... your other variables here

    public void Update() {
        // Check for interaction
        if (Input.GetKeyDown(interactionKey))
        {
            TryInteractWithObject();
        }
    }
    
    public void TryInteractWithObject()
    {
        Ray cameraRay = playerCamera.ScreenPointToRay(rayStartPosition);

        if (Physics.Raycast(cameraRay, out raycastedObject, lengthOfRay))
        {
            GameObject hitObject = raycastedObject.collider.gameObject;

            // Try to find the "interactable" attached to the object hit
            // by the raycast. If the object isn't "interactable", this
            // if statement will not run.
            if (hitObject.TryGetComponent(out IInteractableObject interactable))
            {
                interactable.Interact();
            }
        }
    }
}

And for the door, we can make a new Door MonoBehaviour, along with an IInteractableObject interface. This interface will allow any new behaviour to be "interactable" by simply inheriting from the interface (and implementing Interact()), not just the door:

public interface IInteractableObject
{
    // This function will be called when a player interacts with this object.
    void Interact();
}

public class Door : MonoBehaviour, IInteractableObject
{
    [SerializeField] private float doorRotationSpeed = 500f; // In degrees per second
    private Quaternion initialRotation, targetRotation;
    private bool isOpen;

    public void Start()
    {
        initialRotation = transform.rotation;
        targetRotation = transform.rotation;
    }

    public void Update()
    {
        // Slowly rotate towards our desired rotation
        transform.rotation = Quaternion.RotateTowards(
            transform.rotation,
            targetRotation,
            doorRotationSpeed * Time.deltaTime);
    }

    public void Interact()
    {
        // Invert the "isOpen" boolean
        isOpen = !isOpen;
        
        if (isOpen)
        {
            // Door is now open- add 90 degrees on the Y axis.
            targetRotation = initialRotation * Quaternion.AngleAxis(90, Vector3.up);
        }
        else
        {
            // Door is now closed- reset to starting rotation
            targetRotation = initialRotation;
        }
    }
}

An alternative to putting the rotation logic in Update would be putting it in a Coroutine, but I recommend doing it this way first, so you can learn the pattern of starting something once and continuing it across Update calls.

本文标签: cWhy the object doesn39t rotate smoothlyStack Overflow