Вращение камеры вокруг сферы в Unity / C # с помощью клавиш со стрелками - PullRequest
0 голосов
/ 23 сентября 2019

В настоящее время я изучаю Unity и на какое-то время застрял в проекте, которым я занимаюсь.

У меня есть модель Марса, которая вращается и вращается вокруг нее с двумя лунами.Я хочу иметь возможность перемещать камеру вокруг нее с помощью клавиш со стрелками, но я не могу понять это.

Текущий код (все в одном скрипте под названием GameManager):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    void Start()
    {
        Camera.main.transform.position = new Vector3(0,0,-200);

        Camera.main.transform.LookAt(mars.transform.position);

        Rigidbody rb = mars.GetComponent<Rigidbody>();
        rb.angularVelocity = new Vector3(0,20,0);
    }

    // Update is called once per frame
    void Update()
    {

        if(Input.GetKey("up")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.right, 50* Time.deltaTime);
        }
        else if(Input.GetKey("down")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.right, -50* Time.deltaTime);
        }else if(Input.GetKey("right")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.up, -50* Time.deltaTime);
        }else if(Input.GetKey("left")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.up, 50* Time.deltaTime);
        }

        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 60*Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 50*Time.deltaTime);

    }
}

Изначально это работает нормально, но направления начинают путаться, когда вы используете левую / правую после повышения / понижения или наоборот.

Любая помощь приветствуется.

Ответы [ 4 ]

1 голос
/ 23 сентября 2019

Может быть, было бы лучше, если бы вы определили другую функцию для получения нового вектора для вращения, например:

Vector3 CalculateRotationVector(){
    Vector3 RotationVector = Vector3.zero;

    if(Input.GetKey("up")){
        RotationVector += Vector3.right;
    }
    else if(Input.GetKey("down")){
        RotationVector -= Vector3.right;
    }else if(Input.GetKey("right")){
        RotationVector -= Vector3.right;
    }else if(Input.GetKey("left")){
        RotationVector += Vector3.right;
    }

    return RotationVector;

}

И в вашей функции обновления вы можете вызвать ее так:

void Update(){
    Camera.main.transform.RotateAround(refpoint.transform.position, CalculateRotationVector(), 50* Time.deltaTime);
}

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

0 голосов
/ 24 сентября 2019

Я считаю, что RotateAround здесь является ошибкой.С другими предлагаемыми решениями вы быстро потерялись бы в повороте, когда камера заканчивала вверх ногами или даже вбок.

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    public float cameraAngularVelocity = 60f;
    public float cameraDistance = 200;
    public float cameraAngleY = 0;
    public float cameraAngleX = 0;

    private Camera mainCam;

    void Start()
    {
        mainCam = Camera.main;
    }

    void Update()
    {
        float angleDelta = cameraAngularVelocity * Time.deltaTime;

        //Standard Input management
        if (Input.GetKey("up"))
        {
            cameraAngleX += angleDelta;
        }
        if (Input.GetKey("down"))
        {
            cameraAngleX -= angleDelta;
        }
        if (Input.GetKey("right"))
        {
            cameraAngleY -= angleDelta;
        }
        if (Input.GetKey("left"))
        {
            cameraAngleY += angleDelta;
        }
        //Alternative using axis
        cameraAngleX += Input.GetAxis("Vertical") * angleDelta;
        cameraAngleY += Input.GetAxis("Horizontal") * angleDelta;

        //Protections
        cameraAngleX = Mathf.Clamp(cameraAngleX, -90f, 90f);
        cameraAngleY = Mathf.Repeat(cameraAngleY, 360f);

        Quaternion cameraRotation =
            Quaternion.AngleAxis(cameraAngleY, Vector3.up)
            * Quaternion.AngleAxis(cameraAngleX, Vector3.right);

        Vector3 cameraPosition =
            refpoint.transform.position
            + cameraRotation * Vector3.back * cameraDistance;

        mainCam.transform.position = cameraPosition;
        mainCam.transform.rotation = cameraRotation;

        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 60 * Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 50 * Time.deltaTime);
    }
}

Это решение блокирует ваш крен и предотвращает прохождение вертикали через поворот X.

0 голосов
/ 24 сентября 2019

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

Эта логика требует, чтобы вы не позволяли камере идти прямо над или под планетой.Зафиксируйте вертикальное вращение на основе угла между глобальным увеличением / уменьшением и направлением от эталона к камере, а также некоторого «минимального угла», на который камера может быть направлена ​​вверх / вниз.

Кроме того, Camera.mainвызывает FindGameObjectsWithTag внутри, поэтому рекомендуется для кэширования результатов.

В целом это может выглядеть так:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    private Camera mainCam;
    private float cameraRotateSpeed = 50f;
    private float cameraMinVerticalAngle = 10f;

    void Start()
    {
        mainCam = Camera.main;

        mainCam.transform.position = new Vector3(0,0,-200);

        mainCam.transform.LookAt(mars.transform.position);

        Rigidbody rb = mars.GetComponent<Rigidbody>();
        rb.angularVelocity = new Vector3(0,20,0);
    }

    // Update is called once per frame
    void Update()
    {

        float horizontalRotateDirection = 0f;
        float verticalRotateDirection = 0f;


        if(Input.GetKey("up")){
            doRotate = true;
            verticalRotateDirection += 1f;
        }

        if(Input.GetKey("down")){
            doRotate = true;
            verticalRotateDirection -= 1f;
        }

        if(Input.GetKey("right")){
            doRotate = true;
            horizontalRotateDirection += 1f;
        }

        if(Input.GetKey("left")){
            doRotate = true;
            verticalRotateDirection -= 1f;
        }

        float horizontalRotateAmount = horizontalRotateDirection 
                * cameraRotateSpeed * Time.deltaTime;

        float verticalRotateAmount = verticalRotateDirection 
                * cameraRotateSpeed * Time.deltaTime;

        // Prevent camera from flipping
        Vector3 fromRefToCam = (mainCam.transform.position - refpoint.transform.position).normalized;

        float maxRotateDown = Vector3.Angle(Vector3.down, fromRefToCam);
        float maxRotateUp = Vector3.Angle(Vector3.up, fromRefToCam)

        verticalRotateAmount = Mathf.Clamp(verticalRotateAmount, 
                cameraMinVerticalAngle - maxRotateDown, 
                maxRotateUp - cameraMinVerticalAngle);

        Vector3 verticalRotateAxis = Vector3.Cross(Vector3.down, fromRefToCam); 

        //Rotate horizontally around global down
        mainCam.transform.RotateAround(refpoint.transform.position, 
                    Vector3.up, 
                    horizontalRotateAmount);

        // Rotate vertically around camera's right (in global space)
        mainCam.transform.RotateAround(refpoint.transform.position,
                    verticalRotateAxis, 
                    verticalRotateAmount);


        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 
                60*Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 
                50*Time.deltaTime);

    }
}
0 голосов
/ 23 сентября 2019

Посмотрите на это.

https://docs.unity3d.com/ScriptReference/Transform.RotateAround.html

При этом вы можете вращать вокруг данной точки.Если вы объедините это с клавишным вводом и постоянной скоростью, умноженной на Time.deltaTime, это может сработать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...