Added player task system. simple interaction with objects. Known issue - no player stats canvas

This commit is contained in:
Vladimir Koshevarov
2023-02-21 18:58:06 +02:00
parent 7c26b80584
commit 59d2f7cc30
46 changed files with 2289 additions and 3121 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Assets.Scripts.Actions
DurationInTicks = durationTicks;
}
public abstract void ApplyAction(PlayerManager playerController);
public abstract void ApplyAction(Player playerController);
}
}
+2 -2
View File
@@ -19,9 +19,9 @@ namespace Assets.Scripts.Actions
}
public void ApplyAction(PlayerManager playerController)
public void ApplyAction(Player playerController)
{
playerController.PlayerStats[GameManager.StatsId.Food].increase(_energy);
playerController.PlayerStats[StatsId.Food].increase(_energy);
}
}
}
@@ -4,7 +4,7 @@
public interface IPlayerAction
{
public string Description { get; }
public void ApplyAction(PlayerManager player);
public void ApplyAction(Player player);
}
public interface ISellable
+1 -1
View File
@@ -16,7 +16,7 @@ namespace Assets.Scripts.Actions
_position = position;
Sallary = sallary;
}
public void ApplyAction(PlayerManager playerController)
public void ApplyAction(Player playerController)
{
playerController.WorkPlace = this;
}
+2 -2
View File
@@ -12,9 +12,9 @@ namespace Assets.Scripts.Actions
public string Description => throw new System.NotImplementedException();
public void ApplyAction(PlayerManager playerController)
public void ApplyAction(Player playerController)
{
playerController.PlayerStats[GameManager.StatsId.Energy].increase(_energyPerTick);
playerController.PlayerStats[StatsId.Energy].increase(_energyPerTick);
}
}
}
+3 -6
View File
@@ -2,9 +2,6 @@ using UnityEngine;
public class CameraPlayerFollow : MonoBehaviour
{
[SerializeField]
private Transform _player;
private Vector3 _cameraOffset;
private Transform _obstruction;
@@ -16,13 +13,13 @@ public class CameraPlayerFollow : MonoBehaviour
void Start()
{
_obstruction = null;
_cameraOffset = transform.position - _player.position;
_cameraOffset = transform.position - Player.Instance.transform.position;
// .LookAt(_player);
}
void LateUpdate()
{
Vector3 newPosition = _player.position + _cameraOffset;
Vector3 newPosition = Player.Instance.transform.position + _cameraOffset;
transform.position = Vector3.Slerp(transform.position, newPosition, _smoothFactor);
ViewObstructed();
@@ -31,7 +28,7 @@ public class CameraPlayerFollow : MonoBehaviour
private void ViewObstructed()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, _player.position - transform.position, out hit, 3.5f))
if (Physics.Raycast(transform.position, Player.Instance.transform.position - transform.position, out hit, 3.5f))
{
if (hit.collider.gameObject.tag != "Player")
{
@@ -11,7 +11,6 @@ public class ConversationController : MonoBehaviour
[SerializeField] public Button _choiceButton;
[SerializeField] private Button _btnApply;
[SerializeField] private Button _btnClose;
[SerializeField] PlayerManager _playerManager;
public ConversationChangeEvent conversationChangeEvent;
private List<ChoiceController> choiceControllers = new();
@@ -37,7 +36,7 @@ public class ConversationController : MonoBehaviour
ApplyActionOnPlayer(_selectedAction);
});
_playerManager.allowMovement = false;
Player.Instance.allowMovement = false;
RemoveChoices();
_title.text = title;
gameObject.SetActive(true);
@@ -60,14 +59,14 @@ public class ConversationController : MonoBehaviour
_selectedAction = action;
if (action is ISellable)
{
_btnApply.interactable = _playerManager.PlayerStats[GameManager.StatsId.Money].Value >= (action as ISellable).Price;
_btnApply.interactable = Player.Instance.PlayerStats[StatsId.Money].Value >= (action as ISellable).Price;
}
}
private void ApplyActionOnPlayer(IPlayerAction action)
{
if (action is ISellable)
_playerManager.BuyAction(action);
Player.Instance.BuyAction(action);
}
private void RemoveChoices()
{
@@ -84,6 +83,6 @@ public class ConversationController : MonoBehaviour
RemoveChoices();
gameObject.SetActive(false);
Time.timeScale = 1;
_playerManager.allowMovement = true;
Player.Instance.allowMovement = true;
}
}
+2 -2
View File
@@ -3,10 +3,10 @@ using UnityEngine;
public class OnSelectedObjectChangedEventArgs : EventArgs
{
public Transform SelectedObject;
public BaseInteractableObject SelectedObject;
}
public class OnMovementTargetSelectedEventArgs:EventArgs
public class OnPlayerMovesEventArgs : EventArgs
{
public Vector3 PointToMove;
}
+1 -3
View File
@@ -1,13 +1,11 @@
using System.Collections.Generic;
using UnityEngine;
public enum StatsId { Money, RentAccount, Food, Energy, BankAccount, Job, }
public class GameManager : MonoBehaviour
{
public enum StatsId { Money, RentAccount, Food, Energy, BankAccount, Job, }
public static GameManager Instance { get; private set; }
public PlayerManager Player;
public Dictionary<StatsId, Stat> PlayerStats;
// Start is called before the first frame update
void Awake()
+3 -7
View File
@@ -1,13 +1,9 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using static GameManager;
public class GameUIManager : MonoBehaviour
{
[SerializeField]
private PlayerManager _playerController;
[SerializeField]
private TextMeshProUGUI _timeText;
@@ -34,7 +30,7 @@ public class GameUIManager : MonoBehaviour
// Update is called once per frame
void Update()
{
_moneyText.text = $"${_playerController.PlayerStats[StatsId.Money].Value}";
_moneyText.text = $"${Player.Instance.PlayerStats[StatsId.Money].Value}";
}
@@ -46,7 +42,7 @@ public class GameUIManager : MonoBehaviour
_timeText.text = TimeManager.CurrentTime.ToString(@"hh\:mm");
}
_energy.value = (float)_playerController.PlayerStats[StatsId.Energy].Value;
_food.value = (float)_playerController.PlayerStats[StatsId.Food].Value;
_energy.value = (float)Player.Instance.PlayerStats[StatsId.Energy].Value;
_food.value = (float)Player.Instance.PlayerStats[StatsId.Food].Value;
}
}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 31c259be454ab6b4cb65a567ef4c2d0f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using UnityEngine;
public class BaseInteractableObject : MonoBehaviour
{
[SerializeField]
public Transform _playerArrivePoint;
public virtual void Interact()
{
Debug.Log("Interact with some object");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2af31bf77e63ee64da69d7c708550949
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+10
View File
@@ -0,0 +1,10 @@
using UnityEngine;
public class Bed : BaseInteractableObject
{
public override void Interact()
{
Debug.Log("Interact with bed");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec924e9d7d23a4e46b256dedc9caa75c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,10 @@
using UnityEngine;
public class Fridge : BaseInteractableObject
{
public override void Interact()
{
Debug.Log("Interact with Fridge");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6768a45c9ae20c246bf1052cfa08ddec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+22 -12
View File
@@ -11,10 +11,8 @@ public class MouseInputManager : MonoBehaviour
[SerializeField]
private Camera _camera;
private RaycastHit _raycastHit;
public event EventHandler<OnSelectedObjectChangedEventArgs> OnSelectedObjectChanged;
public event EventHandler<OnMovementTargetSelectedEventArgs> OnMovementTargetSelected;
public static MouseInputManager Instance { get; private set; }
@@ -22,7 +20,7 @@ public class MouseInputManager : MonoBehaviour
{
if (Instance != null)
{
Debug.Log("There's more than one player instance");
Debug.Log("There's more than one mouse Input instance");
}
Instance = this;
}
@@ -30,20 +28,32 @@ public class MouseInputManager : MonoBehaviour
void Update()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (!EventSystem.current.IsPointerOverGameObject() && Physics.Raycast(ray, out _raycastHit, 100f, _selectableLayerMask))
if (!EventSystem.current.IsPointerOverGameObject() && Physics.Raycast(ray, out var mouseRaycastHit, 100f, _selectableLayerMask))
{
OnSelectedObjectChanged?.Invoke(this, new OnSelectedObjectChangedEventArgs() { SelectedObject = _raycastHit.transform });
mouseRaycastHit.transform.TryGetComponent(out BaseInteractableObject baseObject);
if (baseObject != null)
{
OnSelectedObjectChanged?.Invoke(this, new OnSelectedObjectChangedEventArgs() { SelectedObject = baseObject });
if (Input.GetMouseButtonDown(0))
{
Player.Instance.AddTask(new PlayerTasks(Tasks.Move, baseObject._playerArrivePoint.position));
Player.Instance.AddTask(new PlayerTasks(Tasks.Interact, baseObject));
}
}
else
{
OnSelectedObjectChanged?.Invoke(this, new OnSelectedObjectChangedEventArgs() { SelectedObject = null });
}
}
else
{
OnSelectedObjectChanged?.Invoke(this, new OnSelectedObjectChangedEventArgs() { SelectedObject = null });
}
if (Input.GetMouseButton(0))
{
if (Physics.Raycast(_camera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, 100f, _walkableLayerMask))
if (Input.GetMouseButtonDown(0))
{
var pointToMove = hit.point;
OnMovementTargetSelected?.Invoke(this, new OnMovementTargetSelectedEventArgs() { PointToMove = pointToMove });
if (Physics.Raycast(_camera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, 100f, _walkableLayerMask))
{
Player.Instance.AddTask(new PlayerTasks(Tasks.Move, hit.point));
}
}
}
}
@@ -1,111 +1,158 @@
using Assets.Scripts.Actions.Interfaces;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using static GameManager;
using static UnityEditor.PlayerSettings;
public class PlayerManager : MonoBehaviour
{
private enum States { Idle, Walking, Sleeping };
[SerializeField]
public LayerMask _walkableLayer;
[SerializeField]
public NavMeshAgent _navAgent;
[SerializeField]
public Animator _animator;
[SerializeField]
private Camera _camera;
public bool allowMovement = true;
private States _state;
private Vector3 _groundDeltaPosition;
public Dictionary<StatsId, Stat> PlayerStats;
public IWorkPlace WorkPlace { get; set; }
private Vector3 _pointToMove;
private bool _movePointReceived=false;
private void Start()
{
TimeManager.OnMinuteChanged += UpdatePlayerState;
allowMovement = true;
_navAgent.updatePosition = false;
PlayerStats = GameManager.Instance.PlayerStats;
MouseInputManager.Instance.OnMovementTargetSelected += Mouse_OnMovementTargetSelected;
}
private void Mouse_OnMovementTargetSelected(object sender, OnMovementTargetSelectedEventArgs e)
{
_pointToMove= e.PointToMove;
_movePointReceived = true;
}
private void OnDestroy()
{
TimeManager.OnMinuteChanged -= UpdatePlayerState;
MouseInputManager.Instance.OnMovementTargetSelected -= Mouse_OnMovementTargetSelected;
}
private void Update()
{
if (allowMovement && _movePointReceived)
{
_movePointReceived = false;
_navAgent.SetDestination(_pointToMove);
}
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);
}
}
private void OnAnimatorMove()
{
transform.position = _navAgent.nextPosition;
}
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);
}
}
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);
}
}
+27
View File
@@ -0,0 +1,27 @@
using UnityEngine;
public class PlayerTasks
{
public Tasks Task { get; private set; }
public Vector3 Position { get; private set; }
public BaseInteractableObject Interactable { get; private set; }
public TaskStatus Status { get; private set; }
public PlayerTasks(Tasks task, Vector3 position)
{
Task = task;
Position = position;
Status = TaskStatus.Waiting;
}
public PlayerTasks(Tasks task, BaseInteractableObject interactable)
{
Task = task;
Interactable = interactable;
Status = TaskStatus.Waiting;
}
public void UpdateStatus(TaskStatus status)
{
Status = status;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a64ec35bd6b0f784cba543d437d7cdd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+4 -2
View File
@@ -2,8 +2,10 @@ using UnityEngine;
public class SelectedVisual : MonoBehaviour
{
[SerializeField] private Transform _selectedObject;
[SerializeField] private GameObject[] visualGameObjectArray;
[SerializeField]
private BaseInteractableObject _selectedObject;
[SerializeField]
private GameObject[] visualGameObjectArray;
private void Start()
+3 -3
View File
@@ -9,10 +9,10 @@ public class WaypointVisual : MonoBehaviour
private void Start()
{
MouseInputManager.Instance.OnMovementTargetSelected += Mouse_OnMovementTargetSelected;
Player.Instance.OnPlayerMoves += Instance_OnPlayerMoves;
}
private void Mouse_OnMovementTargetSelected(object sender, OnMovementTargetSelectedEventArgs e)
private void Instance_OnPlayerMoves(object sender, OnPlayerMovesEventArgs e)
{
_wayPoint.position = e.PointToMove;
_particleSystem.Play();
@@ -20,6 +20,6 @@ public class WaypointVisual : MonoBehaviour
private void OnDestroy()
{
MouseInputManager.Instance.OnMovementTargetSelected -= Mouse_OnMovementTargetSelected;
Player.Instance.OnPlayerMoves -= Instance_OnPlayerMoves;
}
}