using System; using BehaviorDesigner.Runtime; using BlueWater.Enemies; using BlueWater.Interfaces; using BlueWater.Items; using BlueWater.Players; using BlueWater.Tycoons; using BlueWater.Uis; using Pathfinding; using PixelCrushers.DialogueSystem; using Sirenix.OdinInspector; using UnityEngine; namespace BlueWater.Npcs.Customers { public enum CustomerSpineAnimation { Idle = 0, Run, RunSlow, Eat, Eat2 } public class Customer : MonoBehaviour, IPlayerInteraction { // Variables #region Variables // Components [field: SerializeField] public Transform Transform { get; private set; } [field: SerializeField] public Rigidbody Rigidbody { get; private set; } [field: SerializeField] public CapsuleCollider CharacterCollider { get; private set; } [field: SerializeField] public BehaviorTree BehaviorTree { get; private set; } [field: SerializeField] public Transform VisualLook { get; private set; } [field: SerializeField] public MeshRenderer MeshRenderer { get; private set; } [field: SerializeField] public BarkTrigger BarkTrigger { get; private set; } [field: SerializeField] public Canvas InteractionCanvas { get; private set; } [field: SerializeField] public Transform InteractionUi { get; private set; } [field: SerializeField] public FoodBalloonUi FoodBalloonUi { get; private set; } // Classes [field: SerializeField, Required] public CustomerData CustomerData { get; private set; } [field: SerializeField, Required] public SpineController SpineController { get; private set; } [field: SerializeField, Required] public AiMovement AIMovement { get; private set; } [field: SerializeField] public bool EnableInteraction { get; private set; } = true; [field: SerializeField] public float InteractionRadius { get; private set; } = 2f; private IAstarAI _astarAi; public TableSeat TableSeat { get; private set; } private int _happyPoint; public int HappyPoint { get => _happyPoint; private set { var newHappyPoint = Mathf.Max(0, value); _happyPoint = newHappyPoint; } } private bool _isMoving; public bool IsMoving { get => _isMoving; set { if (_isMoving == value) return; _isMoving = value; SpineController.PlayAnimation(_isMoving ? CustomerSpineAnimation.Run.ToString() : CustomerSpineAnimation.Idle.ToString(), true); } } private Vector3 _currentDirection = Vector3.right; public Vector3 CurrentDirection { get => _currentDirection; set { if (value == Vector3.zero) return; _currentDirection = value; } } private bool _isQuitting; public Action OnInteraction; #endregion // Unity events #region Unity events private void Awake() { InitializeComponents(); } private void OnApplicationQuit() { _isQuitting = true; } private void Update() { HandleMovement(); FlipVisualLook(); } private void OnDestroy() { if (_isQuitting) return; CustomerManager.Instance.UnregisterCustomer(this); } #endregion // Initialize methods #region Initialize methods [Button("컴포넌트 초기화")] protected virtual void InitializeComponents() { Transform = transform; Rigidbody = GetComponent(); CharacterCollider = GetComponent(); BehaviorTree = GetComponent(); VisualLook = transform.Find("VisualLook"); MeshRenderer = VisualLook.GetComponent(); BarkTrigger = transform.Find("DialogueSystem").GetComponent(); InteractionCanvas = transform.Find("InteractionCanvas").GetComponent(); InteractionCanvas.worldCamera = TycoonCameraManager.Instance.UiCamera; InteractionUi = InteractionCanvas.transform.Find("InteractionUi"); InteractionUi.localScale = Vector3.one * (1 / transform.localScale.x); FoodBalloonUi = InteractionCanvas.transform.Find("FoodBalloonUi").GetComponent(); SpineController = GetComponent(); AIMovement = GetComponent(); _astarAi = GetComponent(); } public void Initialize() { CustomerData = CustomerManager.Instance.GetRandomCustomerData(); AIMovement.SetMoveSpeed(CustomerData.MoveSpeed); HappyPoint = CustomerData.BaseHappyPoint; BehaviorTree.EnableBehavior(); } #endregion // Methods #region Methods private void HandleMovement() { if (!_astarAi.canMove || _astarAi.isStopped) { IsMoving = false; return; } CurrentDirection = _astarAi.velocity.normalized; IsMoving = _astarAi.velocity != Vector3.zero || _astarAi.velocity != Vector3.positiveInfinity; } private void FlipVisualLook() { var localScale = VisualLook.localScale; localScale.x = CurrentDirection.x switch { > 0.01f => -Mathf.Abs(localScale.x), < -0.01f => Mathf.Abs(localScale.x), _ => localScale.x }; VisualLook.localScale = localScale; } public void SetTableSeat(TableSeat tableSeat) { TableSeat = tableSeat; FoodBalloonUi.Initialize(TableSeat); } public void SetCurrentDirection(Vector3 normalDirection) => CurrentDirection = normalDirection; public void SetTableSeatPositionAndDirection() { transform.position = TableSeat.SeatTransform.position; SetCurrentDirection(TableSeat.TableDirection); } public void SetFood(ItemData foodData) { TableSeat.SetFood(foodData.Sprite); } public void Interaction() { OnInteraction?.Invoke(); } public bool CanInteraction() => true; public void ShowInteractionUi() { if (!InteractionUi) return; InteractionUi.gameObject.SetActive(true); } public void HideInteractionUi() { if (!InteractionUi) return; InteractionUi.gameObject.SetActive(false); } public void RegisterPlayerInteraction() { if (EnableInteraction) { GameManager.Instance.CurrentTycoonPlayer.TycoonInput.RegisterPlayerInteraction(this); } } public void UnregisterPlayerInteraction() { if (EnableInteraction) { GameManager.Instance.CurrentTycoonPlayer.TycoonInput.UnregisterPlayerInteraction(this); } } public void AddHappyPoint(int value) => HappyPoint += value; public void Bark(string conversation = null) { if (!string.IsNullOrEmpty(conversation)) { BarkTrigger.conversation = conversation; } BarkTrigger.OnUse(); } #endregion } }