using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovingSphere : MonoBehaviour
{
//Vector3 playerInput;
Vector3 desiredVelocity,velocity;
//刚体
Rigidbody rb;
//环境判断变量
bool desiredJump;
int groundContactCount;
bool OnGround => groundContactCount > 0;
[Header("physic data")]
[SerializeField]
float maxSpeed;
[SerializeField,Range(0f,100f)]
float maxAcceleration,maxAirAcceleration;
//air参数
[Header("midAir")]
[SerializeField]
float jumpHeight;
[SerializeField,Range(0,3)]
int maxAirJumps;
int jumpPhase = 0;
//斜坡测试有关
[SerializeField,Range(0,90)]
float maxGroundAngle;
float minGroundDotProduct;
Vector3 contactNormal;
void Awake()
{
rb = GetComponent<Rigidbody>();
OnValidate();
}
// Update is called once per frame
void Update()
{ Vector3 playerInput;
playerInput.x = Input.GetAxis("Horizontal");
playerInput.z = Input.GetAxis("Vertical");
desiredVelocity = new Vector3(playerInput.x,0f,playerInput.z) * maxSpeed;
//Debug.Log($"{desiredVelocity}");
desiredJump |= Input.GetButtonDown("Jump");
}
void FixedUpdate()
{
UpdateState();
AdjustVelocity();
if(desiredJump)
{
desiredJump = false;
Jump();
}
rb.velocity = velocity;
//onGround = false;
ClearState();
}
void Jump()
{
if(OnGround|| jumpPhase < maxAirJumps)
{
jumpPhase += 1;
//V = sqr(-2gh)
float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
//速度在接触法线方向的分量
float alignedSpeed = Vector3.Dot(velocity,contactNormal);
if(alignedSpeed > 0 )
{
//确保不为负值
jumpSpeed = Mathf.Max(jumpSpeed - alignedSpeed,0f) ;
}
//接触面的法线方向增加跳跃速度
velocity += contactNormal*jumpSpeed;
}
}
void OnCollisionEnter(Collision other) {
EvaluateCollision(other);
}
void OnCollisionStay(Collision other) {
EvaluateCollision(other);
}
void EvaluateCollision(Collision other)
{
for (int i = 0; i < other.contactCount; i++)
{
//获取碰撞点的法线
Vector3 normal = other.GetContact(i).normal;
// //法线的y轴分向量大于一个值,才表示在地面上
// onGround |= normal.y >= minGroundDotProduct;
if(normal.y >= minGroundDotProduct)
{
//onGround = true;
groundContactCount += 1;
//如果有多个接触点,累加法线向量
contactNormal += normal;
}
}
}
//更新状态模块
void UpdateState()
{
velocity = rb.velocity;
//
if(OnGround)
{
jumpPhase = 0;
// 归一化接触法线
if(groundContactCount > 1)
contactNormal.Normalize();
}
else
{
contactNormal = Vector3.up;
}
}
//Clear State mode
void ClearState()
{
//onGround = false;
groundContactCount = 0;
contactNormal = Vector3.zero;
}
//计算角度的cos值,得出在y分量上的大小
void OnValidate() {
minGroundDotProduct = Mathf.Cos(maxGroundAngle * Mathf.Deg2Rad);
}
//将x轴变成物体的x轴方向
Vector3 ProjectOnContactPlane(Vector3 vector)
{
//减去在法线方向的向量,
return vector - contactNormal * Vector3.Dot(vector,contactNormal);
}
//速度调整函数
void AdjustVelocity()
{
//自定义x,z轴
Vector3 xAxis = ProjectOnContactPlane(Vector3.right).normalized;
Vector3 zAxis = ProjectOnContactPlane(Vector3.forward).normalized;
//当前的速度在自定义x轴上的大小
float currentX = Vector3.Dot(velocity,xAxis);
float currentZ = Vector3.Dot(velocity,zAxis);
//选择加速度
float acceleration = OnGround ? maxAcceleration : maxAirAcceleration;
//单帧速度的改变量
float maxSpeedChange = acceleration * Time.deltaTime;
//将速度改成所需的速度
float newX = Mathf.MoveTowards(velocity.x,desiredVelocity.x,maxSpeedChange);
float newZ = Mathf.MoveTowards(velocity.z,desiredVelocity.z,maxSpeedChange);
//xAxis控制方向,(newX 所需的速度- currentX在x轴的分量)控制大小
velocity += xAxis *(newX - currentX) + zAxis * (newZ - currentZ);
}
}
第二章.物理
最新推荐文章于 2022-10-26 21:45:20 发布