maze_switching (#82)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #82
This commit is contained in:
@@ -9,9 +9,10 @@ namespace Input
|
||||
/// <summary>
|
||||
/// Base class for player movement controllers.
|
||||
/// Handles tap-to-move and hold-to-move input with pathfinding or direct movement.
|
||||
/// Implements IInteractingCharacter to enable interaction with items.
|
||||
/// Derived classes can override to add specialized behavior (e.g., shader updates).
|
||||
/// </summary>
|
||||
public abstract class BasePlayerMovementController : ManagedBehaviour, ITouchInputConsumer
|
||||
public abstract class BasePlayerMovementController : ManagedBehaviour, ITouchInputConsumer, IInteractingCharacter
|
||||
{
|
||||
[Header("Movement")]
|
||||
[SerializeField] protected float moveSpeed = 5f;
|
||||
@@ -42,6 +43,12 @@ namespace Input
|
||||
public event System.Action OnMovementStarted;
|
||||
public event System.Action OnMovementStopped;
|
||||
|
||||
// IInteractingCharacter implementation - scripted movement for interactions
|
||||
private Coroutine _moveToCoroutine;
|
||||
private bool _interruptMoveTo;
|
||||
public event System.Action OnArrivedAtTarget;
|
||||
public event System.Action OnMoveToCancelled;
|
||||
|
||||
// Components
|
||||
protected AIPath _aiPath;
|
||||
protected Animator _animator;
|
||||
@@ -67,13 +74,6 @@ namespace Input
|
||||
{
|
||||
base.OnManagedStart();
|
||||
|
||||
// Register with InputManager
|
||||
if (InputManager.Instance != null)
|
||||
{
|
||||
InputManager.Instance.SetDefaultConsumer(this);
|
||||
Logging.Debug($"[{GetType().Name}] Registered as default input consumer");
|
||||
}
|
||||
|
||||
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().inputLogVerbosity;
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Input
|
||||
|
||||
public virtual void OnTap(Vector2 worldPosition)
|
||||
{
|
||||
InterruptMoveTo(); // Cancel any scripted movement
|
||||
Logging.Debug($"[{GetType().Name}] OnTap at {worldPosition}");
|
||||
if (_aiPath != null)
|
||||
{
|
||||
@@ -116,6 +117,7 @@ namespace Input
|
||||
|
||||
public virtual void OnHoldStart(Vector2 worldPosition)
|
||||
{
|
||||
InterruptMoveTo(); // Cancel any scripted movement
|
||||
Logging.Debug($"[{GetType().Name}] OnHoldStart at {worldPosition}");
|
||||
_lastHoldPosition = worldPosition;
|
||||
_isHolding = true;
|
||||
@@ -325,6 +327,103 @@ namespace Input
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInteractingCharacter Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Controller-driven interaction movement. Base implementation moves this controller to the interactable.
|
||||
/// Override in derived classes for custom behavior (e.g., PlayerTouchController handles follower dispatch).
|
||||
/// </summary>
|
||||
public virtual async System.Threading.Tasks.Task<bool> MoveToInteractableAsync(Interactions.InteractableBase interactable)
|
||||
{
|
||||
// Default behavior: move self to interactable position
|
||||
Vector3 targetPosition = interactable.transform.position;
|
||||
|
||||
// Check for custom CharacterMoveToTarget
|
||||
var moveTargets = interactable.GetComponentsInChildren<Interactions.CharacterMoveToTarget>();
|
||||
foreach (var target in moveTargets)
|
||||
{
|
||||
if (target.characterType == Interactions.CharacterToInteract.Trafalgar ||
|
||||
target.characterType == Interactions.CharacterToInteract.Both)
|
||||
{
|
||||
targetPosition = target.GetTargetPosition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Use MovementUtilities to handle movement
|
||||
return await Utils.MovementUtilities.MoveToPositionAsync(this, targetPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the character to a specific target position and notifies via events when arrived or cancelled.
|
||||
/// This is used by systems like interactions to orchestrate scripted movement.
|
||||
/// </summary>
|
||||
public virtual void MoveToAndNotify(Vector3 target)
|
||||
{
|
||||
// Cancel any previous move-to coroutine
|
||||
if (_moveToCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_moveToCoroutine);
|
||||
}
|
||||
|
||||
_interruptMoveTo = false;
|
||||
// Ensure pathfinding is enabled for MoveToAndNotify
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.enabled = true;
|
||||
_aiPath.canMove = true;
|
||||
_aiPath.isStopped = false;
|
||||
}
|
||||
_moveToCoroutine = StartCoroutine(MoveToTargetCoroutine(target));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels any in-progress MoveToAndNotify operation and fires the cancellation event.
|
||||
/// </summary>
|
||||
public virtual void InterruptMoveTo()
|
||||
{
|
||||
_interruptMoveTo = true;
|
||||
_isHolding = false;
|
||||
_directMoveVelocity = Vector3.zero;
|
||||
if (Settings != null && Settings.DefaultHoldMovementMode == HoldMovementMode.Direct && _aiPath != null)
|
||||
_aiPath.enabled = false;
|
||||
OnMoveToCancelled?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine for moving the character to a target position and firing arrival/cancel events.
|
||||
/// </summary>
|
||||
protected virtual System.Collections.IEnumerator MoveToTargetCoroutine(Vector3 target)
|
||||
{
|
||||
if (_aiPath != null)
|
||||
{
|
||||
_aiPath.destination = target;
|
||||
_aiPath.maxSpeed = Settings.MoveSpeed;
|
||||
_aiPath.maxAcceleration = Settings.MaxAcceleration;
|
||||
}
|
||||
|
||||
while (!_interruptMoveTo)
|
||||
{
|
||||
Vector2 current2D = new Vector2(transform.position.x, transform.position.y);
|
||||
Vector2 target2D = new Vector2(target.x, target.y);
|
||||
float dist = Vector2.Distance(current2D, target2D);
|
||||
if (dist <= Settings.StopDistance + 0.2f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
_moveToCoroutine = null;
|
||||
if (!_interruptMoveTo)
|
||||
{
|
||||
OnArrivedAtTarget?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user