Вращение одного объекта при подключении сценария к нескольким объектам

#c# #unity3d #rotation #transform #game-development

Вопрос:

У меня есть игра в Unity, в которой я добавил три объекта (Куб, Цилиндр, Капсулу). К этим игровым объектам я добавил скрипт для поворота их вдоль оси при нажатии левой кнопки мыши и x, y или z, поворачивая объект вдоль соответствующей оси. Но когда я пытаюсь повернуть один объект, другие объекты тоже вращаются. Как повернуть каждый объект, не затрагивая другие объекты.

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

Ответ №1:

Я предполагаю, что вы пытаетесь достичь

  • щелкните по объекту курсором мыши и удерживайте
  • затем поверните этот объект с помощью соответствующих клавиш.

На самом деле для этого вам нужен только один сценарий, не для каждого объекта, а только один в вашей сцене (например, центральный контроллер).

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

Ответ №2:

Попробуйте три отдельных однонаправленных действия с условием ввода Input.GetKey(KeyCode.X) Input.GetKey(KeyCode.Y) , Input.GetKey(KeyCode.Z) соответственно:

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

Это transform относится к преобразованию игрового объекта Monobehvaiour , к которому он прикреплен, поэтому, если у вас есть сценарий, прикрепленный ко многим игровым объектам, логика применима ко всем из них.

Вам нужно сделать 3 разных Monobehaviours и обработать входную логику соответственно или создать глобальный Monobehaviour обработчик вращения, в котором вы сохраняете ссылку для каждого из ваших игровых объектов, чтобы вы могли обрабатывать каждое преобразование соответственно.

Комментарии:

1. Итак, мне нужно создать три разных сценария и прикрепить их к объектам? Разве это не привело бы к тому же результату? Извините, я новичок в написании сценариев на c# и unity.

2. да, но с каждым из if (Input.GetMouseButton(0) amp;amp; Input.GetKey(KeyCode.X)) { ... соответственно. Это приведет к тому, что каждое преобразование игрового объекта будет перемещено соответственно каждым из входных данных

3. Я попробовал твой метод. Я создал три сценария с конкретными входными данными в каждом сценарии и добавил их к каждому объекту, но результат тот же. Все объекты перемещаются независимо от того, что выбрано

4. убедитесь, что у вас нет подключенного предыдущего компонента или любого другого, выполняющего движение с помощью ввода

5. Я попробовал это. Это работает, если скрипт добавлен к одному объекту. В противном случае объекты тоже вращаются.