Add radial pose menu with hotkeys, remove C cycle hotkey

- PlayerPose: Icon (Sprite) + Title (string) UI properties
- PoseMenu: modal pause overlay building a radial menu from Icon Button
  prefab instances; active pose disabled (hover ring marks it); click
  applies pose via SetPoseIndex and closes
- OverviewMenu: pose button wiring with pause hand-off, Esc/Tab chain
  extended; hotkeys C (toggle pose menu) and V (paint mode) mirroring
  the buttons incl. identical gating
- PlayerPoseController: C cycle hotkey and NextPose() removed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Fable 5 committed 2026-07-12 16:17:40 +02:00
1 parent c3d9c06118
commit 3a2e8a7057
5 files changed
+216 -23

No files matched your search

@@ -3,14 +3,12 @@ using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
using UnityEngine.Serialization;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
/// <summary>
/// Owns ALL character animation (the Animator is left empty): plays the active <see cref="PlayerPose"/>'s
/// idle or optional walk/run/fall clip through a two-input mixer <see cref="PlayableGraph"/> that
/// crossfades every clip switch. One key cycles poses, sprinting resets to the default pose; each pose
/// crossfades every clip switch. Poses are selected via <see cref="SetPoseIndex"/> (the pose menu UI);
/// sprinting resets to the default pose; each pose
/// also carries its own eased CharacterController capsule and per-pose camera y-offsets.
/// </summary>
[RequireComponent(typeof(PlayerCharacterController))]
@@ -28,15 +26,6 @@ public class PlayerPoseController : MonoBehaviour
[Min(0)]
[SerializeField] private int defaultPoseIndex = 0;
[Header("Input")]
#if ENABLE_INPUT_SYSTEM
[Tooltip("Key that cycles to the next pose (wraps at the end of the list).")]
[SerializeField] private Key cycleKey = Key.C;
#else
[Tooltip("Key that cycles to the next pose (wraps at the end of the list).")]
[SerializeField] private KeyCode cycleKey = KeyCode.C;
#endif
[Header("Transitions")]
[Tooltip("Seconds to crossfade from the previous pose to a newly selected one. 0 = instant snap.")]
[Min(0f)]
@@ -111,6 +100,9 @@ public class PlayerPoseController : MonoBehaviour
public int CurrentIndex => _currentIndex;
/// <summary>Selectable poses, for the pose selection menu (icons/titles per entry).</summary>
public IReadOnlyList<PlayerPose> Poses => poses;
/// <summary>Locomotion category resolved this frame; the owner publishes it for network sync.</summary>
public Locomotion CurrentLocomotion => _currentLocomotion;
@@ -169,9 +161,6 @@ public class PlayerPoseController : MonoBehaviour
// Local control only - a remote's pose index is pushed in via SetNetworkState.
if (!_networkControlled)
{
if (InputUtil.GameplayKeyPressed(cycleKey))
NextPose();
// Sprinting in any state (ground, air, wall, ceiling) snaps the selection back to the default
// pose. Held continuously, so the reset shows up immediately, not only once back on the floor.
if (_player.IsSprinting)
@@ -234,10 +223,7 @@ public class PlayerPoseController : MonoBehaviour
_capsuleStarted = false; // re-snap to the active pose's capsule if this is re-enabled
}
/// <summary>Advances to the next pose, wrapping at the end of the list.</summary>
public void NextPose() => SetPoseIndex(_currentIndex + 1);
/// <summary>Selects a pose by index, wrapping into range so cycling never goes out of bounds.</summary>
/// <summary>Selects a pose by index, wrapping into range so a stale index never goes out of bounds.</summary>
public void SetPoseIndex(int index) => _currentIndex = WrapIndex(index);
private int WrapIndex(int index)