Files
2026-03-04 10:03:45 +08:00

122 lines
3.6 KiB
C#

using UnityEngine;
namespace RootMotion.Demos
{
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
public abstract class CharacterBase : MonoBehaviour
{
[Header("Base Parameters")]
[Tooltip("If specified, will use the direction from the character to this Transform as the gravity vector instead of Physics.gravity. Physics.gravity.magnitude will be used as the magnitude of the gravity vector.")]
public Transform gravityTarget;
[Tooltip("Multiplies gravity applied to the character even if 'Individual Gravity' is unchecked.")]
public float gravityMultiplier = 2f;
public float airborneThreshold = 0.6f;
public float slopeStartAngle = 50f;
public float slopeEndAngle = 85f;
public float spherecastRadius = 0.1f;
public LayerMask groundLayers;
private PhysicMaterial zeroFrictionMaterial;
private PhysicMaterial highFrictionMaterial;
protected Rigidbody r;
protected const float half = 0.5f;
protected float originalHeight;
protected Vector3 originalCenter;
protected CapsuleCollider capsule;
public abstract void Move(Vector3 deltaPosition, Quaternion deltaRotation);
protected Vector3 GetGravity()
{
if (gravityTarget != null)
{
return (gravityTarget.position - base.transform.position).normalized * Physics.gravity.magnitude;
}
return Physics.gravity;
}
protected virtual void Start()
{
capsule = GetComponent<Collider>() as CapsuleCollider;
r = GetComponent<Rigidbody>();
originalHeight = capsule.height;
originalCenter = capsule.center;
zeroFrictionMaterial = new PhysicMaterial();
zeroFrictionMaterial.dynamicFriction = 0f;
zeroFrictionMaterial.staticFriction = 0f;
zeroFrictionMaterial.frictionCombine = PhysicMaterialCombine.Minimum;
zeroFrictionMaterial.bounciness = 0f;
zeroFrictionMaterial.bounceCombine = PhysicMaterialCombine.Minimum;
highFrictionMaterial = new PhysicMaterial();
r.constraints = RigidbodyConstraints.FreezeRotation;
}
protected virtual RaycastHit GetSpherecastHit()
{
Vector3 up = base.transform.up;
Ray ray = new Ray(r.position + up * airborneThreshold, -up);
RaycastHit hitInfo = new RaycastHit
{
point = base.transform.position - base.transform.transform.up * airborneThreshold,
normal = base.transform.up
};
Physics.SphereCast(ray, spherecastRadius, out hitInfo, airborneThreshold * 2f, groundLayers);
return hitInfo;
}
public float GetAngleFromForward(Vector3 worldDirection)
{
Vector3 vector = base.transform.InverseTransformDirection(worldDirection);
return Mathf.Atan2(vector.x, vector.z) * 57.29578f;
}
protected void RigidbodyRotateAround(Vector3 point, Vector3 axis, float angle)
{
Quaternion quaternion = Quaternion.AngleAxis(angle, axis);
Vector3 vector = base.transform.position - point;
r.MovePosition(point + quaternion * vector);
r.MoveRotation(quaternion * base.transform.rotation);
}
protected void ScaleCapsule(float mlp)
{
if (capsule.height != originalHeight * mlp)
{
capsule.height = Mathf.MoveTowards(capsule.height, originalHeight * mlp, Time.deltaTime * 4f);
capsule.center = Vector3.MoveTowards(capsule.center, originalCenter * mlp, Time.deltaTime * 2f);
}
}
protected void HighFriction()
{
capsule.material = highFrictionMaterial;
}
protected void ZeroFriction()
{
capsule.material = zeroFrictionMaterial;
}
protected float GetSlopeDamper(Vector3 velocity, Vector3 groundNormal)
{
float num = 90f - Vector3.Angle(velocity, groundNormal);
num -= slopeStartAngle;
float num2 = slopeEndAngle - slopeStartAngle;
return 1f - Mathf.Clamp(num / num2, 0f, 1f);
}
}
}