// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value. using Animancer.Units; using UnityEngine; namespace Animancer.Samples.Sprites { /// A 3D version of the . /// /// /// Sample: /// /// Directional Character 3D /// /// /// https://kybernetik.com.au/animancer/api/Animancer.Samples.Sprites/DirectionalCharacter3D /// [AddComponentMenu(Strings.SamplesMenuPrefix + "Sprites - Directional Character 3D")] [AnimancerHelpUrl(typeof(DirectionalCharacter3D))] public class DirectionalCharacter3D : MonoBehaviour { /************************************************************************************************************************/ #if UNITY_PHYSICS_3D /************************************************************************************************************************/ [Header("Physics")] [SerializeField] private CapsuleCollider _Collider; [SerializeField] private Rigidbody _Rigidbody; [SerializeField, MetersPerSecond] private float _WalkSpeed = 1; [SerializeField, MetersPerSecond] private float _RunSpeed = 2; [Header("Animations")] [SerializeField] private DirectionalAnimations3D _Animancer; [SerializeField] private DirectionalAnimationSet _Idle; [SerializeField] private DirectionalAnimationSet _Walk; [SerializeField] private DirectionalAnimationSet _Run; [SerializeField] private DirectionalAnimationSet _Push; private Vector3 _Movement; private bool _IsPushing; public enum AnimationGroup { Other, Movement, } /************************************************************************************************************************/ protected virtual void Update() { Vector2 input = SampleInput.WASD; if (input != Vector2.zero) { input = _Animancer.Animations.Snap(input); // Convert the input to 3D in the XZ plane. _Movement = new Vector3(input.x, 0, input.y); // Apply the camera's rotation and set the forward direction. Transform camera = _Animancer.Camera; _Movement = camera.TransformDirection(_Movement); _Movement.y = 0; _Movement.Normalize(); _Animancer.Forward = _Movement; Play(GetMovementAnimations(), AnimationGroup.Movement); } else { _Movement = Vector3.zero; Play(_Idle, AnimationGroup.Other); } } /************************************************************************************************************************/ private void Play(DirectionalAnimationSet animations, AnimationGroup group) => _Animancer.SetAnimations(animations, (int)group); /************************************************************************************************************************/ private DirectionalAnimationSet GetMovementAnimations() { if (_IsPushing) return _Push; else if (SampleInput.LeftShiftHold) return _Run; else return _Walk; } /************************************************************************************************************************/ protected virtual void OnCollisionEnter(Collision collision) => OnCollision(collision); protected virtual void OnCollisionStay(Collision collision) => OnCollision(collision); private void OnCollision(Collision collision) { if (_IsPushing) return; int contactCount = collision.contactCount; for (int i = 0; i < contactCount; i++) { ContactPoint contact = collision.GetContact(i); // If we're moving directly towards an object (or within 30 degrees of it), we are pushing it. if (Vector3.Angle(contact.normal, _Movement) > 180 - 30) { _IsPushing = true; return; } } } /************************************************************************************************************************/ protected virtual void FixedUpdate() { _IsPushing = false; // Determine the desired speed based on the current animation. float speed = _Animancer.Animations == _Run ? _RunSpeed : _WalkSpeed; #if UNITY_6000_0_OR_NEWER _Rigidbody.linearVelocity = _Movement * speed; #else _Rigidbody.velocity = _Movement * speed; #endif } /************************************************************************************************************************/ #if UNITY_EDITOR /************************************************************************************************************************/ protected virtual void OnValidate() { if (_Animancer != null) _Animancer.Animations = _Idle; } /************************************************************************************************************************/ #endif /************************************************************************************************************************/ #else /************************************************************************************************************************/ protected virtual void Awake() { SampleReadMe.LogMissingPhysics3DModuleError(this); } /************************************************************************************************************************/ #endif /************************************************************************************************************************/ } }