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

Viewed 337

I have a game in Unity in which I have added three objects (Cube, Cylinder, Capsule). To these game objects, I have added a script to rotate them along an axis when they press the left click and x, y or z, rotating the object along the respective axis. But when I attempt rotate a single object, the other objects rotate too. How do I rotate each object without affecting the other objects.

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);
}
2 Answers

Try three separate monobehaviour with input condition Input.GetKey(KeyCode.X), Input.GetKey(KeyCode.Y), Input.GetKey(KeyCode.Z) respectively:

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

The transform applies to the transform of the gameObject the Monobehvaiour is attached to, so if the you have the script attached to many gameobjects, the logic applies to all of them.

You need to make 3 different Monobehaviours and handle the input logic respectively, or make a global Monobehaviour rotation handler, where you keep a reference for each of your gameObjects so that you can handle each of the transforms respectively.

I assume what you are trying to achieve is

  • click on an object with the mouse Cursor and hold
  • then rotate this object using the according keys.

You actually need only one single script for this, not on every object but just one in your scene (like a central controller)

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);
                }
            }
        }
    }
}

NOTE: Requires your target objects to have colliders (and the selected layer(s))


As an alternative if you rather want to go for a solution with one script per object you could rather use e.g.

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;
        }
    }
}
Related