所以我用transform.position编写了我的运动,我不想使用刚体,因为我使用我自己的物理计算。作为回报,我只会引入额外的步骤(我什至不需要,因为我基本上将所有内容都清空了,而且它会引入新的错误(例如在我的斜坡运动中)......所以,我需要一些限制我可能的东西移动方向,受限于我的对撞机的命中位置,我正在考虑光线投射,这会起作用...但我必须拍摄太多的光线投射,并且无论如何都不是万无一失的,即使它是 8 个方向的光线投射...有人对我的问题有任何想法或解决方案吗?
代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
[Header("Player")]
public float PlayerHeight = 2f;
[Header("Objects")]
public Transform Direction;
// Input
float CurrentMoveX;
float CurrentMoveZ;
float TargetMoveX;
float TargetMoveZ;
[Header("Settings")]
public float CurrentMoveSpeedMode = 5f;
[Header("Movement Physics")]
public float AccelSpeed = 4.5f;
public float DeaccelSpeed = 4.5f;
public float SnapRange = 0.01f;
[Header("Gravity Physics")]
public float GravityStrength = 1f;
[Header("Ground")]
public float GroundDetectionRadius = 0.3f;
bool IsGrounded;
// Units
float GForce = 9.80665f;
float SpeedConversionValue = 3.6f;
// Direction
Vector3 MoveDirection;
// Vertical
float CurrentVerticalVelocity;
void Update()
{
HorizontalMovement();
MoveOutput();
}
void HorizontalMovement()
{
InputDirection();
EditedDirection();
Ground();
}
void InputDirection()
{
// Move X - Horizontal
if(Input.GetAxisRaw("Horizontal") < 0f)
{
TargetMoveX = -CurrentMoveSpeedMode / SpeedConversionValue;
if(CurrentMoveX > TargetMoveX)
{
if(CurrentMoveX > 0f)
{
CurrentMoveX -= GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveX <= 0f)
{
CurrentMoveX -= GForce * AccelSpeed * Time.deltaTime;
}
}
else if(CurrentMoveX <= TargetMoveX)
{
CurrentMoveX = TargetMoveX;
}
}
else if(Input.GetAxisRaw("Horizontal") > 0f)
{
TargetMoveX = CurrentMoveSpeedMode / SpeedConversionValue;
if(CurrentMoveX < TargetMoveX)
{
if(CurrentMoveX < 0f)
{
CurrentMoveX += GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveX >= 0f)
{
CurrentMoveX += GForce * AccelSpeed * Time.deltaTime;
}
}
else if(CurrentMoveX >= TargetMoveX)
{
CurrentMoveX = TargetMoveX;
}
}
else if(Input.GetAxisRaw("Horizontal") == 0f)
{
TargetMoveX = 0f;
if(CurrentMoveX > 0.1f)
{
CurrentMoveX -= GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveX < -0.1f)
{
CurrentMoveX += GForce * AccelSpeed * Time.deltaTime;
}
else
{
CurrentMoveX = TargetMoveX;
}
}
// Move Z - Vertical
if(Input.GetAxisRaw("Vertical") < 0f)
{
TargetMoveZ = -CurrentMoveSpeedMode / SpeedConversionValue;
if(CurrentMoveZ > TargetMoveZ)
{
if(CurrentMoveZ > 0f)
{
CurrentMoveZ -= GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveZ <= 0f)
{
CurrentMoveZ -= GForce * AccelSpeed * Time.deltaTime;
}
}
else if(CurrentMoveZ <= TargetMoveZ)
{
CurrentMoveZ = TargetMoveZ;
}
}
else if(Input.GetAxisRaw("Vertical") > 0f)
{
TargetMoveZ = CurrentMoveSpeedMode / SpeedConversionValue;
if(CurrentMoveZ < TargetMoveZ)
{
if(CurrentMoveZ < 0f)
{
CurrentMoveZ += GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveZ >= 0f)
{
CurrentMoveZ += GForce * AccelSpeed * Time.deltaTime;
}
}
else if(CurrentMoveZ >= TargetMoveZ)
{
CurrentMoveZ = TargetMoveZ;
}
}
else if(Input.GetAxisRaw("Vertical") == 0f)
{
TargetMoveZ = 0f;
if(CurrentMoveZ > SnapRange)
{
CurrentMoveZ -= GForce * (AccelSpeed + DeaccelSpeed) * Time.deltaTime;
}
else if(CurrentMoveZ < -SnapRange)
{
CurrentMoveZ += GForce * AccelSpeed * Time.deltaTime;
}
else
{
CurrentMoveZ = TargetMoveZ;
}
}
}
void EditedDirection()
{
// Directionalize And Normalize Movement Input
Vector3 DirectionInput = Direction.forward * CurrentMoveZ + Direction.right * CurrentMoveX;
Vector3 DirectionNormal = DirectionInput.normalized;
DirectionNormal = new Vector3(Mathf.Abs(DirectionNormal.x), 0, Mathf.Abs(DirectionNormal.z));
Vector3 OutputDirection = new Vector3(DirectionInput.x * DirectionNormal.x, 0, DirectionInput.z * DirectionNormal.z);
// Slope Detection
RaycastHit TerrainHit;
if(Physics.SphereCast(transform.position, PlayerHeight / 4f, Vector3.down, out TerrainHit))
{
if(TerrainHit.normal != Vector3.up)
{
OnSlopeFunction();
}
else
{
NotOnSlopeFunction();
}
}
else
{
NotOnSlopeFunction();
}
// Follow Terrain/Slopes
void OnSlopeFunction()
{
MoveDirection = Vector3.ProjectOnPlane(OutputDirection, TerrainHit.normal);
}
void NotOnSlopeFunction()
{
MoveDirection = OutputDirection;
}
}
void Ground()
{
// Prevent Clipping Through Floor (Especially when moving down slopes)
GroundAlign();
void GroundAlign()
{
RaycastHit GroundAlignHit;
if(Physics.Raycast(transform.position, Vector3.down, out GroundAlignHit, PlayerHeight / 2f))
{
Vector3 GroundAlignPos = GroundAlignHit.point;
transform.position = new Vector3(transform.position.x, GroundAlignPos.y + PlayerHeight / 2f, transform.position.z);
}
}
}
void MoveOutput()
{
// Output Movement
transform.position = MoveDirection * Time.deltaTime;
}
}
Rigidbody,预计运动正常运行,似乎不是结果,transform.position也似乎更平滑,因为它不需要计算物理,它基于自定义物理值,存储在浮点数中。
无需过多关注,我就会切入您的
MoveOutput
功能。假设您的对撞机只是一个基元,您可以在应用新位置之前使用 Physics.OverlapCapsule
(立方体和球体也可用)检查“重叠”。
void MoveOutput()
{
Vector3 newPos = transform.position + MoveDirection * Time.deltaTime;
//TODO adjust parameters to your needs
//NOTE the capsule is always upright no matter how your object is rotated
float height = 2;
if(Physics.OverlapCapsule(newPos - (height / 2) * Vector3.up, newPos + (height / 2) * Vector3.up, 0.5f).Length == 0)
{
transform.position = newPos;
}
}
该密码将阻止您进入墙壁。如果您以一定角度进入,您将不会滑行。
请注意,帧速率下降可能会导致一些卡顿,从而导致您出界或卡住。我强烈建议您将
Update
更换为 FixedUpdate
,以获得更高的一致性。