Files
trail-into-darkness/Assets/Code/GameState/PlayModes/PartyMovementHandler.cs
2026-04-27 00:01:15 +02:00

151 lines
5.7 KiB
C#

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace Nox.Game {
public class PartyMovementHandler {
private readonly PartyReference partyReference;
private readonly ICameraController cameraController;
private readonly InputSystem_Actions inputActions;
private readonly MapLocationsReference mapLocationsReference;
private readonly EncounterHandler encounterHandler;
private readonly AdventureSettings adventureSettings;
private readonly float maxDistance = 100f;
private readonly AdventureData adventureData;
private bool partyCanMove;
private Vector3 targetPosition;
private bool shouldHover;
private MapLocation currentSelectedPoi;
private string previousZoneId;
private bool hasClicked;
private bool skipNextClick;
public LayerMask clickToMoveMask = LayerMask.GetMask("Clickable");
public LayerMask hoverOverMask = LayerMask.GetMask("Hoverable");
public PartyMovementHandler(
PartyReference partyReference,
ICameraController cameraController,
MapLocationsReference mapLocationsReference,
Input.InputSettings inputSettings,
EncounterHandler encounterHandler,
AdventureData adventureData,
AdventureSettings adventureSettings) {
this.partyReference = partyReference;
this.cameraController = cameraController;
this.mapLocationsReference = mapLocationsReference;
this.encounterHandler = encounterHandler;
this.adventureData = adventureData;
this.adventureSettings = adventureSettings;
inputActions = inputSettings.inputActions;
}
public void Initialize() {
inputActions.Player.ClickOnMap.performed += OnClickOnMap;
}
public void ConsumeNextClick() {
skipNextClick = true;
}
private void OnClickOnMap(InputAction.CallbackContext obj) {
if(!obj.action.WasReleasedThisFrame()) {
return;
}
hasClicked = true;
}
private void HandleHoverableLocation(RaycastHit hitInfo) {
var go = hitInfo.collider.gameObject;
if(!go.transform.parent.TryGetComponent(out MapLocation mapLocation)) {
return;
}
currentSelectedPoi = mapLocation;
mapLocation.highlight.gameObject.SetActive(true);
}
private void HandleClickableLocation() {
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
if(!Physics.Raycast(ray, out var clickHit, maxDistance, clickToMoveMask, QueryTriggerInteraction.Ignore)) {
return;
}
if(!clickHit.collider.gameObject.transform.parent.TryGetComponent(out MapReference mapReference)) {
return;
}
if(ValidateMoveLocation(clickHit)) {
targetPosition = clickHit.point;
partyCanMove = true;
}
}
private bool ValidateMoveLocation(object hitInfoPoint) {
return true;
}
public void Tick() {
HandleHover();
if(hasClicked) {
hasClicked = false;
// should it skip next click to avoid click-through from the pause menu?
if(skipNextClick) {
skipNextClick = false;
return;
}
if(EventSystem.current.IsPointerOverGameObject()) {
return;
}
HandleClickableLocation();
}
if(!partyCanMove) {
adventureData.isPartyMoving = false;
return;
}
if(Vector3.Distance(partyReference.transform.position, targetPosition) < 0.05f) {
partyReference.transform.position = targetPosition;
VerifyPointsOfInterest();
partyCanMove = false;
}
adventureData.isPartyMoving = true;
partyReference.transform.position = Vector3.MoveTowards(
new Vector3(partyReference.transform.position.x, 0,
partyReference.transform.position.z), targetPosition,
Time.deltaTime * adventureSettings.partyBaseSpeed);
encounterHandler?.CheckForEncounters(partyReference.transform.position);
}
private void HandleHover() {
if(EventSystem.current.IsPointerOverGameObject()) {
return;
}
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
if(Physics.Raycast(ray, out var hoverHit, maxDistance, hoverOverMask, QueryTriggerInteraction.Ignore)) {
HandleHoverableLocation(hoverHit);
}
else {
currentSelectedPoi?.highlight.gameObject.SetActive(false);
currentSelectedPoi = null;
}
}
private void VerifyPointsOfInterest() {
foreach(var location in mapLocationsReference.mapLocations) {
if(Vector3.Distance(location.mapLocation.transform.position, partyReference.transform.position) < 0.4f) {
Debug.Log($"Arrived at {location.locationId}");
break;
}
}
}
public void Dispose() {
inputActions.Player.ClickOnMap.performed -= OnClickOnMap;
}
}
}