Created
May 20, 2025 07:02
-
-
Save Mike-Schvedov/b833a89b16e8b5a44df5707923169936 to your computer and use it in GitHub Desktop.
Horse Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| [RequireComponent(typeof(Animator))] | |
| public class HorseController : MonoBehaviour | |
| { | |
| public Transform saddlePoint; | |
| public float walkSpeed = 6f; | |
| public float runSpeed = 12f; | |
| public float acceleration = 2f; | |
| public float deceleration = 2f; | |
| private float currentSpeed = 0f; | |
| private bool isMounted = false; | |
| private float gravity = -9.81f; | |
| private Vector3 verticalVelocity = Vector3.zero; | |
| private Animator animator; | |
| private Transform rider; | |
| private CharacterController controller; | |
| [Header("Audio")] | |
| public AudioSource footstepSource; | |
| public AudioClip walkClip; | |
| public AudioClip runClip; | |
| private float stepTimer = 0f; | |
| private float stepInterval = 0.5f; | |
| private const float walkStepInterval = 1f; // make sure its the same length as your step clip | |
| private const float runStepInterval = 0.5f; | |
| private const float idleToWalkThreshold = 3f; | |
| private const float walkToRunThreshold = 4f; | |
| private void Start() | |
| { | |
| controller = GetComponent<CharacterController>(); | |
| animator = GetComponent<Animator>(); | |
| } | |
| private void Update() | |
| { | |
| if (!isMounted || rider == null) | |
| return; | |
| HandleMovement(); | |
| UpdateAnimations(); | |
| } | |
| private void HandleMovement() | |
| { | |
| float vertical = Input.GetAxis("Vertical"); | |
| // Determine target speed | |
| float targetSpeed = 0f; | |
| if (vertical > 0.1f) | |
| targetSpeed = Input.GetKey(KeyCode.LeftShift) ? runSpeed : walkSpeed; | |
| // Accelerate / Decelerate | |
| currentSpeed = Mathf.MoveTowards(currentSpeed, targetSpeed, | |
| (currentSpeed < targetSpeed ? acceleration : deceleration) * Time.deltaTime); | |
| // Turn | |
| float horizontal = Input.GetAxis("Horizontal"); | |
| if (Mathf.Abs(horizontal) > 0.1f) | |
| transform.Rotate(Vector3.up * horizontal * 60f * Time.deltaTime); | |
| // Apply gravity | |
| if (controller.isGrounded) | |
| verticalVelocity.y = -1f; // Small push down to stay grounded | |
| else | |
| verticalVelocity.y += gravity * Time.deltaTime; | |
| // Final movement vector | |
| Vector3 move = transform.forward * currentSpeed + verticalVelocity; | |
| controller.Move(move * Time.deltaTime); | |
| } | |
| private void UpdateAnimations() | |
| { | |
| animator.SetFloat("Speed", currentSpeed); | |
| PlayHorseSounds(); | |
| } | |
| private void PlayHorseSounds() | |
| { | |
| if (controller.isGrounded && currentSpeed > idleToWalkThreshold) | |
| { | |
| stepTimer -= Time.deltaTime; | |
| if (stepTimer <= 0f) | |
| { | |
| // Set footstep interval based on walking or running | |
| stepInterval = currentSpeed > walkSpeed + walkToRunThreshold ? runStepInterval : walkStepInterval; | |
| // Play correct clip | |
| AudioClip clipToPlay = currentSpeed > walkSpeed + walkToRunThreshold ? runClip : walkClip; | |
| if (footstepSource && clipToPlay) | |
| footstepSource.PlayOneShot(clipToPlay); | |
| stepTimer = stepInterval; | |
| } | |
| } | |
| else | |
| { | |
| stepTimer = 0f; // Reset so we play immediately on next move | |
| } | |
| } | |
| public void Mount(Transform player) | |
| { | |
| if (isMounted) | |
| return; | |
| isMounted = true; | |
| rider = player; | |
| // Position the rider on the saddle | |
| rider.SetParent(saddlePoint); | |
| rider.localPosition = Vector3.zero; | |
| rider.localRotation = Quaternion.identity; | |
| // Disable player movement | |
| MovementManager.Instance.EnableMovement(false); | |
| MovementManager.Instance.EnableLook(false); | |
| } | |
| public void Dismount() | |
| { | |
| if (!isMounted || rider == null) | |
| return; | |
| // Detach and place nearby | |
| rider.SetParent(null); | |
| rider.position = transform.position - transform.right * 3f + Vector3.up * 1f; | |
| // Enable player movement | |
| MovementManager.Instance.EnableMovement(true); | |
| MovementManager.Instance.EnableLook(true); | |
| isMounted = false; | |
| rider = null; | |
| currentSpeed = 0f; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment