Files
SimUL/Assets/Scripts/Player.cs
T

159 lines
4.7 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 class Player : MonoBehaviour
{
public event EventHandler<OnPlayerMovesEventArgs> OnPlayerMoves;
private enum States { Idle, Walking, Sleeping };
public static Player Instance { get; private set; }
[SerializeField]
public NavMeshAgent _navAgent;
[SerializeField]
public Animator _animator;
public bool allowMovement = true;
private States _state;
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 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 (_state != States.Sleeping)
{
_state = shouldMove ? States.Walking : States.Idle;
_animator.SetBool("Move", shouldMove);
_animator.SetFloat("velY", 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)
{
return true;
}
}
return false;
}
private TaskStatus InteractWithObject(BaseInteractableObject interactableObject)
{
interactableObject.Interact();
return TaskStatus.Complete;
}
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 (_state)
{
case States.Idle:
case States.Walking:
PlayerStats[StatsId.Energy].deduct(0.1m); // 24 hours it's 100, 100/1440=~0.096 per minute
break;
case States.Sleeping:
PlayerStats[StatsId.Energy].increase(1m);
break;
}
if (PlayerStats[StatsId.Energy].Value <= 10 && _state != States.Sleeping)
{
_state = States.Sleeping;
allowMovement = false;
_animator.SetBool("Fall", true);
}
if (PlayerStats[StatsId.Energy].Value >= 100 && _state == States.Sleeping)
{
_state = States.Idle;
allowMovement = true;
_animator.SetBool("Fall", false);
}
}
public void BuyAction(IPlayerAction action)
{
PlayerStats[StatsId.Money].deduct(((ISellable)action).Price);
action.ApplyAction(this);
}
}