提问人:Logan Alexander Thies 提问时间:11/9/2023 最后编辑:Logan Alexander Thies 更新时间:11/10/2023 访问量:51
Unity 3D - 脉冲反应行为上的意外轴捕捉和未知力
Unity 3D - Unintended axis snapping and unknown force on Impulse reaction behavior
问:
UNITY 版本 2022.3.11f1 3D URP项目
我正在开发一个简单的播放器控制器脚本,但很难确定速度以意外方式运行的原因。
两个问题:
1 - 当我在向前移动时旋转玩家刚体时 - 速度/方向会捕捉到世界的 x 轴。
黄线是速度 红线是作用力(根据键 (W) 输入和鼠标输入的方向推动)
视频演示 : https://clipchamp.com/watch/kpePTVpR73s
问题 - 为什么速度会捕捉到这样的世界轴,我该如何开始解决?
2 - 当我按下空格键在 y 方向上施加脉冲力时,在 z 世界轴方向上施加了一个力,该力正在推动刚体,我花了很多时间注释掉其他作用力并查看 UI 以查找可能起作用的力。
再
黄线是速度 红线是作用力(根据键 (W) 输入和鼠标输入的方向推动)
视频演示 : https://clipchamp.com/watch/phAYs1v4ULU
问题 - 为什么当脉冲设置为世界 y 时,速度会立即与 z 方向成一定角度,为什么在弧路径的末端会发生偏转,就好像刚体在撞到一堵看不见的墙上一样?
资产结构
照相机 父级 - CameraHolder - MoveCamera 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCamera : MonoBehaviour
{
public Transform cameraPosition;
// Update is called once per frame
void Update()
{
transform.position = cameraPosition.position;
}
}
儿童 - PlayerCam(主摄像头) - PlayerCam脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCam : MonoBehaviour
{
public float sensX;
public float sensY;
public Transform orientation;
float xRotation;
float yRotation;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
// Get Mouse Input
float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;
yRotation += mouseX;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
orientation.rotation = Quaternion.Euler(0, yRotation, 0);
}
}
选手 父级 - 玩家 - 刚体 - 玩家移动脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
public float groundDrag;
public float jumpForce;
public float jumpCooldown;
public float airMultiplier;
bool readyToJump = true;
[Header("Keybinds")]
public KeyCode jumpKey = KeyCode.Space;
[Header("Ground Check")]
public float playerHeight;
public LayerMask whatIsGround;
public Transform orientation;
bool grounded;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
}
// Update is called once per frame
void Update()
{
Debug.DrawRay(rb.position, rb.velocity, Color.yellow);
Debug.DrawRay(rb.position, rb.GetAccumulatedForce(), Color.red);
// Ground Check
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
// Handle drag
if (grounded)
rb.drag = groundDrag;
else
rb.drag = 0;
}
private void FixedUpdate()
{
MovePlayer();
}
private void MyInput()
{
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
if (Input.GetKey(jumpKey) && readyToJump && grounded)
{
readyToJump = false;
Jump();
Invoke(nameof(ResetJump), jumpCooldown);
}
}
private void MovePlayer()
{
// Calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
Debug.Log("Orientation --- " + orientation.position);
Debug.Log("Orientation --- " + orientation.forward);
Debug.DrawLine(rb.position, moveDirection, Color.green);
// On Ground
if (grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
else if (!grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
}
private void SpeedControl()
{
Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.y);
// Limit velocity if needed
if(flatVelocity.magnitude > moveSpeed)
{
Vector3 limitedVelocity = flatVelocity.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVelocity.x, rb.velocity.y, limitedVelocity.z);
}
}
private void Jump()
{
// Reset Y Velocity
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
private void ResetJump()
{
readyToJump = true;
}
}
儿童 - PlayerObj - 胶囊对撞机
子 - 方向 - 只需变换方向
儿童 - CameraPos - 只需变换位置
我尝试了各种代码注释、日志记录和 UI 配置,以尝试推理力如何作用在刚体上。
答:
我看到你的方法你有.SpeedControl()
Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.y);
这显然会将 RigidBody 的速度分量映射到其分量。
这可以解释捕捉,因为大多数时候它看起来都是零。因此,当您达到速度限制时,您需要将组件设置为 0,这将沿轴对齐它。Y
Z
Y
Z
X
这也可以解释跳跃问题,因为在这种情况下,速度不会为 0,这意味着映射的速度将映射到轴上,在跳跃时将角色向前推。Y
Y
Z
我想你想说的是:Vector3 flatVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
评论