unity3d - 如何在 Unity 中控制倾斜表面上的玩家相机/独立于 xyz 轴?
问题描述
我设法让我的玩家利用重力在圆柱体的内表面周围移动,但在尝试旋转相机环顾四周时出现了问题。
首先,有一个脚本通过将玩家推向圆柱体的内壁来模拟重力。该脚本还通过将玩家的“向上”方向更改为始终面向圆柱体的中心来保持玩家直立。我知道这会阻止我的玩家向上看,所以现在我只是在努力让他们向左看和向右看。
其次,当玩家位于圆柱体底部并与 Y 轴平行时,我可以毫无问题地左右看,因为相机使用 x 轴旋转(参见图像左侧的圆圈)。然而,当玩家围绕圆柱体的一侧移动时,即使它们未对齐,相机仍会尝试基于 X 轴旋转,从而导致相机无法准确旋转(参见图像右侧的圆圈),并且当玩家围绕圆柱体旋转 90 度时,根本无法旋转(我认为是由于重力使玩家保持垂直于圆柱体的侧面),并且在旋转 180 度时会反转。
我假设有两种可能的解决方案我无法成功实施:
忽略世界 xyz 轴'并相对于玩家的 xyz 旋转。
当你考虑到玩家围绕圆柱体的旋转和当前“左”方向的角度时,做一些数学计算来计算出正确的角度。
第一个解决方案的问题是我无法成功地旋转独立于世界 xyz 的玩家。我尝试将 Space.Self 添加到 Rotate() 方法但没有成功。第二个问题是数学让我害怕,到目前为止我已经设法避免四元数和欧拉角,所以我什至不知道如何开始弄清楚这一点。
如果有人遇到过类似的问题,我将不胜感激有关如何解决的任何见解或建议。
这是我控制播放运动/相机方向的代码和我的重力代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
InputManager inputActions;
InputManager.PlayerMovementActions playerMovement;
public GravityAttractor GravityAttractor;
public float moveSpeed = 15;
public float jumpHeight = 10f;
public float sensitivityX = 1f;
public float sensitivityY = 1f;
float mouseX, mouseY;
Vector2 mouseInput;
private bool isJumping = false;
private Vector3 moveDir;
private Vector2 moveInput;
private Rigidbody rbody;
private void Awake()
{
inputActions = new InputManager();
playerMovement = inputActions.PlayerMovement;
playerMovement.Movement.performed += context => moveInput = context.ReadValue<Vector2>();
playerMovement.Jump.performed += ctx => Jump();
//playerMovement.MouseX.performed += context => mouseInput = context.ReadValue<Vector2>();
playerMovement.MouseX.performed += context => mouseInput.x = context.ReadValue<float>();
playerMovement.MouseY.performed += context => mouseInput.y = context.ReadValue<float>();
rbody = GetComponent<Rigidbody>();
isJumping = false;
}
private void Update()
{
moveDir = new Vector3(moveInput.x, 0, moveInput.y).normalized;
if (rbody.velocity.y == 0)
isJumping = false;
}
private void FixedUpdate()
{
rbody.MovePosition(rbody.position + transform.TransformDirection(moveDir) * moveSpeed * Time.deltaTime);
MouseLook(mouseInput);
}
void Jump()
{
//use brackeys method of checking for contact with ground
if(isJumping == false && rbody.velocity.y == 0)
{
isJumping = true;
rbody.velocity = transform.up * jumpHeight;
Debug.Log("player jumped");
}
}
void MouseLook(Vector2 mouseInput)
{
mouseX = mouseInput.x * sensitivityX;
mouseY = mouseInput.y * sensitivityY;
var upTransform = GravityAttractor.transform.position - transform.position;
Vector3 relativeLook = upTransform - transform.forward;
Vector3 qLook = transform.forward - transform.position;
transform.Rotate(transform.up * mouseX * Time.deltaTime, Space.Self);
//transform.Rotate(relativeLook.normalized);
//transform.rotation = Quaternion.LookRotation(qLook);
//transform.Rotate(relativeLook.normalized, mouseX);
}
private void OnEnable()
{
inputActions.Enable();
}
private void OnDisable()
{
inputActions.Enable();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GravityAttractor : MonoBehaviour
{
public float gravityMultiplier = -10f;
private float radius;
public float gravity;
public float distance;
private void Awake()
{
radius = transform.localScale.x/2;
}
public void Attract(Transform body)
{
Vector3 centerOfGravity = new Vector3(transform.position.x, transform.position.y, body.position.z);
distance = Vector3.Distance(centerOfGravity, body.position);
//gravity will match multiplier no matter the radius of cylinder
gravity = gravityMultiplier * (distance/radius);
Vector3 gravityUp = (centerOfGravity - body.position).normalized;
Vector3 bodyUp = body.up;
body.GetComponent<Rigidbody>().AddForce(gravityUp * gravity);
Quaternion targetRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * body.rotation;
body.rotation = Quaternion.Slerp(body.rotation, targetRotation, 50 * Time.deltaTime);
}
}
解决方案
问题是您正试图在世界空间中的 transform.up 周围的局部空间中旋转。
尝试只使用 Vector3.up,而不是 transform.up。或者您可以使用 transform.InverseTransformDirection() 将任何向量从世界转换到本地空间
transform.Rotate(Vector3.up * mouseX * Time.deltaTime, Space.Self);
我不知道你的游戏对象的层次结构。为了让它工作,你应该旋转玩家游戏对象,使其面向圆柱体的中心。并且相机应该是玩家游戏对象的孩子
推荐阅读
- reactjs - 如何使用箭头使材质 ui 芯片数组左右滚动?
- node.js - 使用自定义事件参数运行计划的非定期 AWS Lambda 函数
- powershell - 如何将类放入构造函数参数| 电源外壳
- python - Python 和 Excel 插件
- r - R中的应用族
- jwt - 无法验证 Twilio Authy webhook 回调
- mysql - Spring Boot 应用程序使用 mysql 启动缓慢
- vba - 停用 Excel 365 VBA 中的范围
- git - 如何使用 .gitignore 文件正确忽略来自 git 的文件?
- python - 如何将 tf.data.Dataset 拆分为 keras 的 x_train、y_train、x_test、y_test