using System.Threading; using UdonSharp; using UnityEngine; using VRC.Core; using VRC.SDK3.ClientSim; using VRC.SDKBase; using VRC.Udon; public enum ChickenState { Idle, Walk, Run, Eat, Held } public class Chimken : UdonSharpBehaviour { [UdonSynced, FieldChangeCallback(nameof(AnimationState))] private ChickenState _AnimationState = 0; [UdonSynced] private bool _IsBeingHeld = false; [SerializeField] private string _FollowUser = ""; private VRCPlayerApi _PlayerToFollow = null; [FieldChangeCallback(nameof(FollowMode))] private bool _FollowMode = false; private Animator _Animator = null; private bool _Moving = false; private float _MovementTimer = 0.0f; private float _MovementDirectionDegrees = 0.0f; private const float WALK_SPEED = 0.35f; private const float RUN_SPEED = 1.4f; void Start() { _Animator = GetComponent(); } void FixedUpdate() { if (Networking.IsOwner(Networking.LocalPlayer, gameObject) && !_IsBeingHeld) { if (FollowMode && _PlayerToFollow != null) { Vector3 PlayerPosition = _PlayerToFollow.GetPosition(); Vector3 PlayerPositionLateral = new Vector3(PlayerPosition.x, 0.0f, PlayerPosition.z); Vector3 ChickenPosition = transform.position; Vector3 ChickenPositionLateral = new Vector3(ChickenPosition.x, 0.0f, ChickenPosition.z); float DistanceToPlayer = Vector3.Distance(ChickenPositionLateral, PlayerPositionLateral); if (DistanceToPlayer <= 0.7f) { SetAnimationState(ChickenState.Eat); } else if (DistanceToPlayer <= 2.75f) { transform.LookAt(PlayerPosition); SetAnimationState(ChickenState.Walk); } else { transform.LookAt(PlayerPosition); SetAnimationState(ChickenState.Run); } } else { _MovementTimer -= Time.deltaTime; if (_MovementTimer <= 0.0f) { ChickenState NewState = (ChickenState)Random.Range(0, 4); SetAnimationState(NewState); _MovementDirectionDegrees = Random.Range(0.0f, 359.999999999f); switch (NewState) { case ChickenState.Idle: _MovementTimer = 4.0f; break; case ChickenState.Walk: _MovementTimer = 4.5f; break; case ChickenState.Run: _MovementTimer = 1.2f; break; case ChickenState.Eat: _MovementTimer = 6.0f; break; } } transform.rotation = Quaternion.Euler( transform.eulerAngles.x, Mathf.LerpAngle(transform.rotation.eulerAngles.y, _MovementDirectionDegrees, 0.2f), transform.eulerAngles.x); } if (_Moving) { switch (_AnimationState) { case ChickenState.Walk: transform.position += (transform.forward * Time.fixedDeltaTime * WALK_SPEED); break; case ChickenState.Run: transform.position += (transform.forward * Time.fixedDeltaTime * RUN_SPEED); break; } } // Reset roll and pitch to zero on every physics update so the chicken stays upright Vector3 Rotation = transform.eulerAngles; Rotation.x = 0.0f; Rotation.z = 0.0f; transform.rotation = Quaternion.Euler(Rotation); } } public override void OnPlayerJoined(VRCPlayerApi Player) { if (Player.displayName == _FollowUser) { _PlayerToFollow = Player; SetWanderMode(); } base.OnPlayerJoined(Player); } public override void OnPlayerLeft(VRCPlayerApi Player) { if (Player.displayName == _FollowUser) { _PlayerToFollow = null; SetWanderMode(); } base.OnPlayerLeft(Player); } public override void OnPickup() { Networking.SetOwner(Networking.LocalPlayer, gameObject); SetAnimationState(ChickenState.Held); _IsBeingHeld = true; base.OnPickup(); } public override void OnDrop() { SetWanderMode(); _IsBeingHeld = false; base.OnDrop(); } public void OnCollisionEnter(Collision Collision) { Debug.LogError("[Chimken] Touch!!!"); } private void SetWanderMode() { if (_PlayerToFollow == null) { FollowMode = false; } else { FollowMode = true; } } private void SetAnimationState(ChickenState State) { AnimationState = State; RequestSerialization(); } private void OnStateChanged() { _Animator.SetInteger("State", (int)AnimationState); _Moving = false; switch (AnimationState) { case ChickenState.Idle: break; case ChickenState.Walk: _Moving = true; break; case ChickenState.Run: _Moving = true; break; case ChickenState.Eat: break; case ChickenState.Held: break; } } private ChickenState AnimationState { set { _AnimationState = value; OnStateChanged(); } get => _AnimationState; } private bool FollowMode { set { _FollowMode = value; } get => _FollowMode; } }