191 lines
5.8 KiB
C#
191 lines
5.8 KiB
C#
using Assets.Scripts.Actions.Interfaces;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
public enum Tasks { Move, Interact };
|
|
public enum TaskStatus { Waiting, InProgress, Complete };
|
|
public enum ActionStates { Idle, Walking, Sleeping, Sitting };
|
|
public class Player : MonoBehaviour
|
|
{
|
|
public event EventHandler<OnPlayerMovesEventArgs> OnPlayerMoves;
|
|
|
|
|
|
public static Player Instance { get; private set; }
|
|
|
|
[SerializeField]
|
|
public NavMeshAgent _navAgent;
|
|
[SerializeField]
|
|
public Animator _animator;
|
|
|
|
public bool allowMovement = true;
|
|
private ActionStates _currentState;
|
|
private Vector3 _groundDeltaPosition;
|
|
|
|
public Dictionary<StatsId, Stat> PlayerStats;
|
|
public IWorkPlace WorkPlace { get; set; }
|
|
|
|
private readonly Queue<PlayerTasks> _tasks = new Queue<PlayerTasks>();
|
|
private PlayerTasks _currentTask;
|
|
|
|
private const string FALL_DOWN = "Fall";
|
|
private const string SIT_DOWN = "SitDown";
|
|
private const string STAND_UP = "StandUp";
|
|
private const string WALK = "Walk";
|
|
private const string WALK_VELOCITY = "WalkVelocity";
|
|
|
|
private void Awake()
|
|
{
|
|
if (Instance != null)
|
|
{
|
|
Debug.Log("There's more than one player instance");
|
|
return;
|
|
}
|
|
Instance = this;
|
|
}
|
|
private void Start()
|
|
{
|
|
TimeManager.OnMinuteChanged += UpdatePlayerState;
|
|
allowMovement = true;
|
|
_navAgent.updatePosition = false;
|
|
PlayerStats = GameManager.Instance.PlayerStats;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
TimeManager.OnMinuteChanged -= UpdatePlayerState;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_currentTask == null || _currentTask.Status == TaskStatus.Complete)
|
|
{
|
|
_tasks.TryDequeue(out _currentTask);
|
|
}
|
|
if (_currentTask != null)
|
|
{
|
|
switch (_currentTask.Task)
|
|
{
|
|
case Tasks.Move:
|
|
OnPlayerMoves?.Invoke(this, new OnPlayerMovesEventArgs() { PointToMove = _currentTask.Position });
|
|
_navAgent.SetDestination(_currentTask.Position);
|
|
_currentTask.UpdateStatus(MoveToPoint());
|
|
break;
|
|
case Tasks.Interact:
|
|
_currentTask.UpdateStatus(InteractWithObject(_currentTask.Interactable));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private TaskStatus MoveToPoint()
|
|
{
|
|
var worldDeltaPosition = _navAgent.nextPosition - transform.position;
|
|
_groundDeltaPosition.x = Vector3.Dot(transform.right, worldDeltaPosition);
|
|
_groundDeltaPosition.y = Vector3.Dot(transform.forward, worldDeltaPosition);
|
|
|
|
Vector2 velocity = (Time.deltaTime > 1e-5f) ? _groundDeltaPosition / Time.deltaTime : Vector2.zero;
|
|
var shouldMove = velocity.magnitude > 0.025f && _navAgent.remainingDistance > _navAgent.radius;
|
|
if (_currentState != ActionStates.Sleeping)
|
|
{
|
|
_currentState = shouldMove ? ActionStates.Walking : ActionStates.Idle;
|
|
|
|
SetPlayerState(ActionStates.Walking);
|
|
_animator.SetFloat(WALK_VELOCITY, velocity.y);
|
|
}
|
|
|
|
return pathComplete() ? TaskStatus.Complete : TaskStatus.InProgress;
|
|
}
|
|
|
|
private bool pathComplete()
|
|
{
|
|
if (Vector3.Distance(_navAgent.destination, _navAgent.transform.position) <= _navAgent.radius)
|
|
{
|
|
if (!_navAgent.hasPath || _navAgent.velocity.sqrMagnitude == 0f)
|
|
{
|
|
SetPlayerState(ActionStates.Idle);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private TaskStatus InteractWithObject(BaseInteractableObject interactableObject)
|
|
{
|
|
interactableObject.Interact(this);
|
|
return TaskStatus.Complete;
|
|
}
|
|
|
|
public void SetPlayerState(ActionStates newState)
|
|
{
|
|
switch (newState)
|
|
{
|
|
case ActionStates.Idle:
|
|
_animator.SetBool(WALK, false);
|
|
break;
|
|
case ActionStates.Walking when _currentState == ActionStates.Sitting:
|
|
_animator.SetBool(SIT_DOWN, false);
|
|
_animator.SetBool(SIT_DOWN, true);
|
|
_animator.SetBool(WALK, true);
|
|
break;
|
|
case ActionStates.Walking:
|
|
_animator.SetBool(WALK, true);
|
|
break;
|
|
case ActionStates.Sleeping:
|
|
break;
|
|
break;
|
|
case ActionStates.Sitting:
|
|
break;
|
|
}
|
|
_currentState = newState;
|
|
}
|
|
|
|
private void OnAnimatorMove()
|
|
{
|
|
transform.position = _navAgent.nextPosition;
|
|
}
|
|
|
|
public void AddTask(PlayerTasks task)
|
|
{
|
|
_tasks.Enqueue(task);
|
|
}
|
|
|
|
public void UpdatePlayerState()
|
|
{
|
|
PlayerStats[StatsId.Food].deduct(0.034m); // 48 hours it's 100, 100/2880=~0.034 per minute
|
|
switch (_currentState)
|
|
{
|
|
case ActionStates.Idle:
|
|
case ActionStates.Walking:
|
|
PlayerStats[StatsId.Energy].deduct(0.1m); // 24 hours it's 100, 100/1440=~0.096 per minute
|
|
break;
|
|
case ActionStates.Sleeping:
|
|
PlayerStats[StatsId.Energy].increase(1m);
|
|
break;
|
|
}
|
|
if (PlayerStats[StatsId.Energy].Value <= 10 && _currentState != ActionStates.Sleeping)
|
|
{
|
|
_currentState = ActionStates.Sleeping;
|
|
allowMovement = false;
|
|
_animator.SetBool(FALL_DOWN, true);
|
|
}
|
|
if (PlayerStats[StatsId.Energy].Value >= 100 && _currentState == ActionStates.Sleeping)
|
|
{
|
|
_currentState = ActionStates.Idle;
|
|
allowMovement = true;
|
|
_animator.SetBool(FALL_DOWN, false);
|
|
}
|
|
}
|
|
|
|
public void BuyAction(IPlayerAction action)
|
|
{
|
|
PlayerStats[StatsId.Money].deduct(((ISellable)action).Price);
|
|
action.ApplyAction(this);
|
|
}
|
|
|
|
}
|