Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/World/WorldRagdollController.cs
2025-06-24 23:49:13 +08:00

149 lines
4.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Animancer;
using BITKit;
using BITKit.Physics;
using UnityEngine;
using Cysharp.Threading.Tasks;
namespace Net.Project.B.World
{
public class WorldRagdollController : MonoBehaviour
{
[SerializeField] private AnimationClip[] startClips;
private AnimancerComponent _animancerComponent;
private Transform _hips;
private bool _isInitialized;
private bool _isPlaying;
private bool _isBreak;
private UnityCollisionController[] _collisionControllers=Array.Empty<UnityCollisionController>();
private Collider[] _colliders=Array.Empty<Collider>();
private Collider[] _selfColliders = Array.Empty<Collider>();
private Rigidbody[] _rigidbodies = Array.Empty<Rigidbody>();
private Collider _selfCollider;
private Rigidbody _selfRigidbody;
private void OnEnable()
{
if (_isInitialized)
{
Play();
}
}
private void Start()
{
_selfRigidbody = GetComponent<Rigidbody>();
_selfCollider = GetComponent<Collider>();
_animancerComponent=GetComponent<AnimancerComponent>();
_selfColliders = GetComponentsInChildren<Collider>().RemoveIn(_selfCollider).ToArray();
_rigidbodies = GetComponentsInChildren<Rigidbody>().RemoveIn(_selfRigidbody).ToArray();
_hips = _animancerComponent.Animator.GetBoneTransform(HumanBodyBones.Hips);
foreach (var collisionController in _collisionControllers=_animancerComponent.GetComponentsInChildren<UnityCollisionController>())
{
collisionController.OnUnityTriggerEnter += OnUnityTriggerEnter;
}
_colliders = _collisionControllers.Select(x => x.GetComponent<Collider>()).ToArray();
if (_isInitialized) return;
_isInitialized = true;
Play();
}
private void OnUnityTriggerEnter(Collider obj)
{
if (_isPlaying is false) return;
if (_selfColliders.Contains(obj)) return;
if (obj is not MeshCollider{convex:false} && obj.ClosestPoint(transform.position).y > transform.position.y)
{
Stop();
}
}
private void Stop()
{
_isBreak = true;
_selfRigidbody.isKinematic = true;
_animancerComponent.enabled = _selfCollider.enabled = _animancerComponent.Animator.enabled = false;
}
private async void Play()
{
if(!_animancerComponent)return;
_isBreak = false;
foreach (var x in _colliders)
{
x.isTrigger = true;
}
_animancerComponent.enabled = _selfCollider.enabled = _animancerComponent.Animator.enabled = true;
_selfRigidbody.isKinematic = false;
_isPlaying = true;
foreach (var x in _rigidbodies)
{
x.isKinematic = true;
}
var play = _animancerComponent.Play(startClips.Random());
play.Time = 0;
try
{
await play.WithCancellation(destroyCancellationToken);
}
catch (OperationCanceledException)
{
return;
}
_isPlaying = false;
_animancerComponent.enabled = _selfCollider.enabled =_animancerComponent.Animator.enabled= false;
_selfRigidbody.isKinematic = true;
if (_isBreak)
{
foreach (var x in _colliders)
{
x.isTrigger = false;
}
foreach (var x in _rigidbodies)
{
x.isKinematic = false;
x.velocity = default;
}
}
else
{
foreach (var x in _colliders)
{
x.isTrigger = false;
}
foreach (var x in _rigidbodies)
{
x.isKinematic = true;
}
}
}
private void OnCollisionEnter(Collision other)
{
if (other.gameObject.layer == LayerMask.NameToLayer("Entities"))
{
Stop();
}
}
private void OnAnimatorMove()
{
var isGrounded = Physics.Raycast(transform.position+Vector3.up*0.1f,Vector3.down,0.11f);
_animancerComponent.Animator.applyRootMotion = isGrounded;
if (isGrounded)
{
_selfRigidbody.velocity = _animancerComponent.Animator.velocity;
}
}
}
}