当脚本附加到多个对象时旋转单个对象

Rotation of a single object when script is attached to multiple objects

我在 Unity 中有一个游戏,我在其中添加了三个对象(立方体、圆柱体、胶囊)。对于这些游戏对象,我添加了一个脚本,当他们按下左键单击和 x、y 或 z 时,它们会沿轴旋转,从而沿各自的轴旋转对象。但是当我尝试旋转单个对象时,其他对象也会旋转。如何在不影响其他对象的情况下旋转每个对象。

if (Input.GetMouseButton(0) && Input.GetKey(KeyCode.Z))
{
    transform.RotateAround(transform.position, transform.forward, Time.deltaTime * 90f);
}
if (Input.GetMouseButton(0) && Input.GetKey(KeyCode.X))
{
    transform.RotateAround(transform.position, transform.right, Time.deltaTime * 90f);
}
if (Input.GetMouseButton(0) && Input.GetKey(KeyCode.Y))
{
    transform.RotateAround(transform.position, transform.up, Time.deltaTime * 90f);
}

尝试输入条件分别为 Input.GetKey(KeyCode.X)Input.GetKey(KeyCode.Y)Input.GetKey(KeyCode.Z) 的三个单独的单一行为:

if (Input.GetMouseButton(0) && Input.GetKey(KeyCode.X)) { 
    transform.RotateAround(transform.position, transform.forward, Time.deltaTime * 90f); 
}

transform 适用于 Monobehvaiour 附加到的游戏对象的转换,因此如果您将脚本附加到许多游戏对象,则该逻辑适用于所有游戏对象。

您需要制作 3 个不同的 Monobehaviours 并分别处理输入逻辑,或者制作一个全局 Monobehaviour 旋转处理程序,在其中为每个游戏对象保留一个引用,以便您可以处理每个变换分别。

我假设您要实现的目标是

  • 用鼠标光标单击对象并按住
  • 然后使用相应的键旋转此对象。

你实际上只需要一个脚本,不是在每个对象上,而是场景中的一个(比如中央控制器)

public class ObjectRotator : MonoBehaviour
{
    [SerializeField] private Camera _camera;

    //Optionally if you only want to hit objects on (a) certain layer(s)
    //[SerializeField] private LayerMask layers;

    private void Awake ()
    {
        if(!_camera) _camera = Camera.main;
    }

    private void Update ()
    {
        if(Input.GetMouseButton(0))
        {
            // Shoot a Raycast from the mouse position into your scene to check if you hit an object
            var ray = _camera.ScreenPointToRay(Input.mousePosition);
            if(Physics.Raycast(ray, out var hit)
            // or if using the layer mask
            //if(Physics.Raycast(ray, out var hit, float.positiveInfinity, layers)
            {
                if (Input.GetKey(KeyCode.Z))
                {
                    // Instead of using RotateAround rather use Rotate which rotated around this object's 
                    // pivot position anyway. By default it is in local space so also no need for transform.forward etc
                    hit.transform.Rotate(Vector3.forward * Time.deltaTime * 90f);
                }
                if (Input.GetKey(KeyCode.X))
                {
                    hit.transform.Rotate(Vector3.right * Time.deltaTime * 90f);
                }
                if (Input.GetKey(KeyCode.Y))
                {
                    hit.transform.Rotate(Vector3.up * Time.deltaTime * 90f);
                }
            }
        }
    }
}

注意:要求您的目标对象具有碰撞器(和选定的图层)


作为替代方案,如果您更愿意使用每个对象一个脚本的解决方案,您可以使用例如

public class Rotation : MonoBehaviour
{
    // This is called by Unity when the mouse is going down while hovering this object's collider
    private void OnMouseDown ()
    {
        // Start the RotationRoutine
        StartCoroutine (RotationRoutine());
    }

    // This is called when the mouse button goes up while hovering this object's collider
    private void OnMouseUp()
    {
        // To simplify things just stop any routine started by this behavior
        StopAllCoroutines ();
    }

    // Also stop when the mouse leaves this object's collider while still being pressed
    private void OnMouseExit()
    {
        StopAllCoroutines ();
    }

    private void RotationRoutine()
    {
        // Whut?! No worries ;) This is fine in a Coroutine as soon as you "yield" somewhere inside
        while(true)
        {
            if (Input.GetKey(KeyCode.Z))
            {
                transform.Rotate(Vector3.forward * Time.deltaTime * 90f);
            }
            if (Input.GetKey(KeyCode.X))
            {
                transform.Rotate(Vector3.right * Time.deltaTime * 90f);
            }
            if (Input.GetKey(KeyCode.Y))
            {
                transform.Rotate(Vector3.up * Time.deltaTime * 90f);
            }
 
            // Basically tells Unity to "pause" here, render this frame and
            // continue from here in the next frame
            yield return null;
        }
    }
}