Files
SimUL/Assets/Scripts/Player.cs
T
2023-02-27 23:30:00 +02:00

214 lines
6.5 KiB
C#

using Assets.Scripts.Actions.Interfaces;
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, Standing };
public class Player : MonoBehaviour
{
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 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)
{
if (_currentTask.Status == TaskStatus.Waiting)
Debug.Log($"Current task {_currentTask.Task}");
switch (_currentTask.Task)
{
case Tasks.Move:
_navAgent.SetDestination(_currentTask.TagretObject._playerArrivePoint.position);
_currentTask.UpdateStatus(MoveToPoint());
break;
case Tasks.Interact:
if (pathComplete(_currentTask.TagretObject._playerArrivePoint.position))
_currentTask.UpdateStatus(InteractWithObject(_currentTask.TagretObject));
else
{
AddTask(new PlayerTasks(Tasks.Move, _currentTask.TagretObject));
AddTask(_currentTask);
_currentTask = null;
}
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.Sitting)
{
SetPlayerState(ActionStates.Standing);
}
_currentState = shouldMove ? ActionStates.Walking : ActionStates.Idle;
SetPlayerState(ActionStates.Walking);
_animator.SetFloat(WALK_VELOCITY, velocity.y);
return pathComplete(_navAgent.destination) ? TaskStatus.Complete : TaskStatus.InProgress;
}
public void Rotate(Vector3 target)
{
Quaternion rotation = Quaternion.LookRotation(target);
transform.rotation = rotation;
}
private bool pathComplete(Vector3 destination)
{
if (Vector3.Distance(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:
_animator.SetBool(WALK, true);
break;
case ActionStates.Sleeping:
break;
case ActionStates.Sitting:
_animator.SetBool(SIT_DOWN, true);
break;
case ActionStates.Standing:
_animator.SetBool(SIT_DOWN, false);
break;
}
_currentState = newState;
}
bool isAnimationStatePlaying(int animLayer, string stateName)
{
if (_animator.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName) &&
_animator.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
return true;
else
return false;
}
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);
}
}