diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..ddb6ff85 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "visualstudiotoolsforunity.vstuc" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..da60e25a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Unity", + "type": "vstuc", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..07c76f9d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "files.exclude": { + "**/.DS_Store": true, + "**/.git": true, + "**/.vs": true, + "**/.gitmodules": true, + "**/.vsconfig": true, + "**/*.booproj": true, + "**/*.pidb": true, + "**/*.suo": true, + "**/*.user": true, + "**/*.userprefs": true, + "**/*.unityproj": true, + "**/*.dll": true, + "**/*.exe": true, + "**/*.pdf": true, + "**/*.mid": true, + "**/*.midi": true, + "**/*.wav": true, + "**/*.gif": true, + "**/*.ico": true, + "**/*.jpg": true, + "**/*.jpeg": true, + "**/*.png": true, + "**/*.psd": true, + "**/*.tga": true, + "**/*.tif": true, + "**/*.tiff": true, + "**/*.3ds": true, + "**/*.3DS": true, + "**/*.fbx": true, + "**/*.FBX": true, + "**/*.lxo": true, + "**/*.LXO": true, + "**/*.ma": true, + "**/*.MA": true, + "**/*.obj": true, + "**/*.OBJ": true, + "**/*.asset": true, + "**/*.cubemap": true, + "**/*.flare": true, + "**/*.mat": true, + "**/*.meta": true, + "**/*.prefab": true, + "**/*.unity": true, + "build/": true, + "Build/": true, + "Library/": true, + "library/": true, + "obj/": true, + "Obj/": true, + "Logs/": true, + "logs/": true, + "ProjectSettings/": true, + "UserSettings/": true, + "temp/": true, + "Temp/": true + }, + "dotnet.defaultSolution": "SimUL.sln" +} \ No newline at end of file diff --git a/Assets/Scripts/InteractableObjects/BaseInteractableObject.cs b/Assets/Scripts/InteractableObjects/BaseInteractableObject.cs index 0e50101b..425a6236 100644 --- a/Assets/Scripts/InteractableObjects/BaseInteractableObject.cs +++ b/Assets/Scripts/InteractableObjects/BaseInteractableObject.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using UnityEngine; public abstract class BaseInteractableObject : MonoBehaviour @@ -30,52 +31,28 @@ public abstract class BaseInteractableObject : MonoBehaviour }; } - public InteractionStatus Interact(Player player) + public async Task ShowPopupMenu(Player player) { _player = player; - PrepareMenuActions(); - - switch (_currentStatus) - { - case InteractionStatus.None: - var filteredActions = _menuActions.Where(x => x.Value.IsEnabled).ToDictionary(i => i.Key, i => i.Value) ; - GameManager.Instance.UI.ShowItemPopupMenu(filteredActions, PopupMenuCallback); - _currentStatus = InteractionStatus.WaitForChoose; - break; - case InteractionStatus.Complete: - _currentStatus = InteractionStatus.None; - return InteractionStatus.Complete; - default: - if (_currentStatus != InteractionStatus.WaitForChoose && _currentStatus != InteractionStatus.Complete) - { - if (_player.IsPathComplete(_interactionPoint.position)) - { - InteractAction(_selectedAction); - _currentStatus = InteractionStatus.None; - return InteractionStatus.Complete; - } - else - { - _currentStatus = InteractionStatus.FarFromPlayer; - } - } - break; - } - return _currentStatus; - } - - private void PopupMenuCallback(RadialMenuActions action) - { - if (action == RadialMenuActions.Cancel) + var filteredActions = _menuActions.Where(x => x.Value.IsEnabled).ToDictionary(i => i.Key, i => i.Value); + var result=await GameManager.Instance.UI.ShowItemPopupMenu(filteredActions); + if (result == RadialMenuActions.Cancel) { _currentStatus = InteractionStatus.Complete; } else { - _selectedAction= action; + _selectedAction = result; _currentStatus = InteractionStatus.InProgress; } + return _currentStatus; + } + + public TaskStatus Interact() + { + InteractAction(_selectedAction); + return TaskStatus.Complete; } protected abstract void InteractAction(RadialMenuActions interactAction); diff --git a/Assets/Scripts/Managers/InGameMouseHandler.cs b/Assets/Scripts/Managers/InGameMouseHandler.cs index 1361dfa9..92d628d3 100644 --- a/Assets/Scripts/Managers/InGameMouseHandler.cs +++ b/Assets/Scripts/Managers/InGameMouseHandler.cs @@ -42,14 +42,14 @@ public class InGameMouseHandler : UnityEngine.Object if (_selectedObject != null) { _waypointVisual.SetWaypoint(_selectedObject._interactionPoint.position); - Player.Instance.AddTask(new PlayerTasks(Tasks.Interact, _selectedObject)); + Player.Instance.Interact(_selectedObject); } else { if (Physics.Raycast(_ray, out RaycastHit hit, 100f, _walkableLayerMask)) { _waypointVisual.SetWaypoint(hit.point); - Player.Instance.AddTask(new PlayerTasks(Tasks.Move, _waypointVisual)); + Player.Instance.GoToPoint( _waypointVisual); } } } diff --git a/Assets/Scripts/Player/BaseCharacter.cs b/Assets/Scripts/Player/BaseCharacter.cs new file mode 100644 index 00000000..73bddbbc --- /dev/null +++ b/Assets/Scripts/Player/BaseCharacter.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AI; + +public class BlockingAnimation : Attribute { } +public abstract class BaseCharacter : MonoBehaviour +{ + [SerializeField] + public NavMeshAgent _navAgent; + [SerializeField] + public Animator _animator; + + private const string WALK_VELOCITY = "WalkVelocity"; + private readonly Queue _tasks = new Queue(); + private PlayerTasks _currentTask; + + private Action _OnAnimationFinish; + private AnimationStates _currentAnimation; + + private void Update() + { + if (PlayerHelper.IsBlockingAnimation(_currentAnimation)) + { + if (IsAnimationStatePlaying(0)) + { + return; + } + else + { + _OnAnimationFinish?.Invoke(); + _OnAnimationFinish = null; + } + } + + 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.Rotate: + _currentTask.UpdateStatus(Rotate(_currentTask.TagretObject._interactionPoint.forward)); + break; + case Tasks.Move: + if (_currentAnimation == AnimationStates.Sitting) + { + SetPlayerAnimation(AnimationStates.Standing); + return; + } + _navAgent.SetDestination(_currentTask.TagretObject._interactionPoint.position); + _currentTask.UpdateStatus(MoveToPoint()); + break; + case Tasks.Interact: + _currentTask.UpdateStatus(_currentTask.TagretObject.Interact()); + break; + } + } + } + private TaskStatus MoveToPoint() + { + _navAgent.isStopped = false; + SetPlayerAnimation(AnimationStates.Walking); + + _animator.SetFloat(WALK_VELOCITY, _navAgent.velocity.magnitude); + return IsPathComplete(_navAgent.destination) ? TaskStatus.Complete : TaskStatus.InProgress; + } + + public bool IsPathComplete(Vector3 destination) + { + var dest = new Vector3(destination.x, 0, destination.z); + var pos = new Vector3(_navAgent.transform.position.x, 0, _navAgent.transform.position.z); + + if (Vector3.Distance(dest, pos) <= _navAgent.radius) + { + transform.position = destination; + if (!_navAgent.hasPath || _navAgent.velocity.sqrMagnitude < 0.2f) + { + SetPlayerAnimation(AnimationStates.Idle); + _navAgent.isStopped = true; + return true; + } + } + + return false; + } + + public TaskStatus Rotate(Vector3 target) + { + var targetRot = Quaternion.LookRotation(target); + Quaternion rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(target), 10 * Time.deltaTime); + rotation.x = 0; + transform.rotation = rotation; + if (IsApproximate(targetRot, transform.rotation, 0.000004f)) + { + return TaskStatus.Complete; + } + return TaskStatus.InProgress; + } + + protected void AddTask(PlayerTasks task) + { + _tasks.Enqueue(task); + } + + public bool IsAnimationStatePlaying(int animLayer) + { + string stateName = PlayerHelper.GetEnumMemberValue(_currentAnimation); + var stateInfo = _animator.GetCurrentAnimatorStateInfo(animLayer); + return stateInfo.IsName(stateName) && stateInfo.normalizedTime < 1.0f; + } + + public void SetPlayerAnimation(AnimationStates newState, Action onAnimationFinish) + { + _OnAnimationFinish = onAnimationFinish; + SetPlayerAnimation(newState); + } + + public void SetPlayerAnimation(AnimationStates newState) + { + if (newState == _currentAnimation) + { + return; + } + _animator.Play(PlayerHelper.GetEnumMemberValue(newState)); + _currentAnimation = newState; + } + + private bool IsApproximate(Quaternion q1, Quaternion q2, float precision) + { + return Mathf.Abs(Quaternion.Dot(q1, q2)) >= 1 - precision; + } +} diff --git a/Assets/Scripts/Player/BaseCharacter.cs.meta b/Assets/Scripts/Player/BaseCharacter.cs.meta new file mode 100644 index 00000000..0b57d934 --- /dev/null +++ b/Assets/Scripts/Player/BaseCharacter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ae6d3e3aea34ae447a6aa1914a953e8e \ No newline at end of file diff --git a/Assets/Scripts/Player/Player.cs b/Assets/Scripts/Player/Player.cs index 263579e0..c5ad1245 100644 --- a/Assets/Scripts/Player/Player.cs +++ b/Assets/Scripts/Player/Player.cs @@ -1,38 +1,23 @@ using Assets.Scripts.Interfaces; -using System; using System.Collections.Generic; using UnityEngine; -using UnityEngine.AI; -public class BlockingAnimation : Attribute { } - -public class Player : MonoBehaviour +public class Player : BaseCharacter { public static Player Instance { get; private set; } - - [SerializeField] - public NavMeshAgent _navAgent; - [SerializeField] - public Animator _animator; - + [SerializeField] private Transform _holdPoint; private PlayerStates _currentActing; - private AnimationStates _currentAnimation; public Dictionary Stats; public JobPositions JobPosition { get; set; } public EducationSkill Education { get; set; } - private readonly Queue _tasks = new Queue(); - private PlayerTasks _currentTask; - - private const string WALK_VELOCITY = "WalkVelocity"; - private ContainerItem _containerItem; - private Action _OnAnimationFinish; + private string _locationName; private void Awake() @@ -66,143 +51,33 @@ public class Player : MonoBehaviour GameManager.Instance.Time.OnMinuteChanged -= UpdateStatsByClock; } - private void Update() - { - if (PlayerHelper.IsBlockingAnimation(_currentAnimation)) - { - if (IsAnimationStatePlaying(0)) - { - return; - } - else - { - _OnAnimationFinish?.Invoke(); - _OnAnimationFinish = null; - } - } - - 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.Rotate: - _currentTask.UpdateStatus(Rotate(_currentTask.TagretObject._interactionPoint.forward)); - break; - case Tasks.Move: - if (_currentAnimation == AnimationStates.Sitting) - { - SetPlayerAnimation(AnimationStates.Standing); - return; - } - _navAgent.SetDestination(_currentTask.TagretObject._interactionPoint.position); - _currentTask.UpdateStatus(MoveToPoint()); - break; - case Tasks.Interact: - var result = _currentTask.TagretObject.Interact(this); - switch (result) - { - case InteractionStatus.FarFromPlayer: - AddTask(new PlayerTasks(Tasks.Move, _currentTask.TagretObject)); - AddTask(new PlayerTasks(Tasks.Rotate, _currentTask.TagretObject)); - AddTask(_currentTask); - _currentTask = null; - break; - case InteractionStatus.Complete: - _currentTask.UpdateStatus(TaskStatus.Complete); - break; - default: - break; - } - break; - } - } - } - public void SetPosition(Vector3 desiredPosition) { _navAgent.Warp(desiredPosition); _navAgent.updatePosition = false; } - private TaskStatus MoveToPoint() + public void GoToPoint(BaseInteractableObject point) { - _navAgent.isStopped = false; - SetPlayerAnimation(AnimationStates.Walking); - - _animator.SetFloat(WALK_VELOCITY, _navAgent.velocity.magnitude); - return IsPathComplete(_navAgent.destination) ? TaskStatus.Complete : TaskStatus.InProgress; + AddTask(new PlayerTasks(Tasks.Move, point)); } - - public bool IsPathComplete(Vector3 destination) + public async void Interact(BaseInteractableObject interactionItem) { - var dest = new Vector3(destination.x, 0, destination.z); - var pos = new Vector3(_navAgent.transform.position.x, 0, _navAgent.transform.position.z); - - if (Vector3.Distance(dest, pos) <= _navAgent.radius) + var result = await interactionItem.ShowPopupMenu(this); + if (result != InteractionStatus.Complete) { - transform.position = destination; - if (!_navAgent.hasPath || _navAgent.velocity.sqrMagnitude < 0.2f) + if (!IsPathComplete(interactionItem._interactionPoint.position)) { - SetPlayerAnimation(AnimationStates.Idle); - _navAgent.isStopped = true; - return true; + AddTask(new PlayerTasks(Tasks.Move, interactionItem)); + AddTask(new PlayerTasks(Tasks.Rotate, interactionItem)); + AddTask(new PlayerTasks(Tasks.Interact, interactionItem)); + } + else + { + AddTask(new PlayerTasks(Tasks.Interact, interactionItem)); } } - - return false; - } - - public TaskStatus Rotate(Vector3 target) - { - var targetRot = Quaternion.LookRotation(target); - Quaternion rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(target), 10 * Time.deltaTime); - rotation.x = 0; - transform.rotation = rotation; - if (IsApproximate(targetRot, transform.rotation, 0.000004f)) - { - return TaskStatus.Complete; - } - return TaskStatus.InProgress; - } - - private bool IsApproximate(Quaternion q1, Quaternion q2, float precision) - { - return Mathf.Abs(Quaternion.Dot(q1, q2)) >= 1 - precision; - } - - public void SetPlayerAnimation(AnimationStates newState, Action onAnimationFinish) - { - _OnAnimationFinish = onAnimationFinish; - SetPlayerAnimation(newState); - } - - public void SetPlayerAnimation(AnimationStates newState) - { - if (newState == _currentAnimation) - { - return; - } - _animator.Play(PlayerHelper.GetEnumMemberValue(newState)); - _currentAnimation = newState; - } - - public bool IsAnimationStatePlaying(int animLayer) - { - string stateName = PlayerHelper.GetEnumMemberValue(_currentAnimation); - var stateInfo = _animator.GetCurrentAnimatorStateInfo(animLayer); - return stateInfo.IsName(stateName) && stateInfo.normalizedTime < 1.0f; - } - - public void AddTask(PlayerTasks task) - { - _tasks.Enqueue(task); - } + } public void SetPlayerActing(PlayerStates state) { diff --git a/Assets/Scripts/UIElements/RadialMenuItem.cs b/Assets/Scripts/UIElements/RadialMenuItem.cs index dcf35a57..7ed20fc4 100644 --- a/Assets/Scripts/UIElements/RadialMenuItem.cs +++ b/Assets/Scripts/UIElements/RadialMenuItem.cs @@ -1,6 +1,6 @@ -using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.UI; @@ -9,47 +9,47 @@ public class RadialMenuItem : MonoBehaviour { [SerializeField] private Button _radialMenuItemPrefab; - private Action _menuButtonClick=null; private Dictionary _actions; + TaskCompletionSource tcs = new TaskCompletionSource(); - public void ShowButtons(RadialMenuItem popupMenu, Dictionary actions, Action menuButtonClick) + + public Task ShowButtons(RadialMenuItem popupMenu, Dictionary actions) { + _actions = actions; - _menuButtonClick = menuButtonClick; for (int buttonsCount = 0; buttonsCount < actions.Count; buttonsCount++) { var button = Instantiate(_radialMenuItemPrefab); button.transform.SetParent(transform, false); float theta = (2 * Mathf.PI / actions.Count) * buttonsCount; - float posX=Mathf.Sin(theta); - float posY=Mathf.Cos(theta); + float posX = Mathf.Sin(theta); + float posY = Mathf.Cos(theta); - button.transform.localPosition = new Vector3(posX, posY, 0)*100f; + button.transform.localPosition = new Vector3(posX, posY, 0) * 100f; var textMeshPro = button.GetComponentInChildren(); if (textMeshPro != null) { textMeshPro.text = actions.ElementAt(buttonsCount).Value.Description; } - AddEvent(button, buttonsCount); + } + return tcs.Task; } - + void AddEvent(Button b, int buttonNumber) { b.onClick.AddListener(() => { + tcs.SetResult(_actions.ElementAt(buttonNumber).Key); Close(); - _menuButtonClick?.Invoke(_actions.ElementAt(buttonNumber).Key); - }); } public void CancelAndClose() { Close(); - _menuButtonClick?.Invoke(RadialMenuActions.Cancel); } private void Close() diff --git a/Assets/Scripts/UIElements/UISystem.cs b/Assets/Scripts/UIElements/UISystem.cs index 2a874ba3..a919ec7b 100644 --- a/Assets/Scripts/UIElements/UISystem.cs +++ b/Assets/Scripts/UIElements/UISystem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using UnityEngine; public class UISystem : MonoBehaviour @@ -32,12 +33,12 @@ public class UISystem : MonoBehaviour jobSelector.ShowJobSelectionDialog(title, onCancel, onConfirm); } - public void ShowItemPopupMenu(Dictionary actions,Action itemsMenuCallback) + public async Task ShowItemPopupMenu(Dictionary actions) { _popupMenu = Instantiate(_radialMenuItemPrefab); _popupMenu.transform.transform.SetParent(transform, false); _popupMenu.transform.position = Input.mousePosition; - _popupMenu.ShowButtons(_popupMenu, actions,itemsMenuCallback); + return await _popupMenu.ShowButtons(_popupMenu, actions); } public void ClosePopupMenu()