Docs: reduce over-documentation across gameplay scripts
Trim restated narration, dead commented-out code, and oversized class headers; keep all why-comments (authority, timing, edge cases), tooltips, and serialization caveats. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
882d30797e
commit
066e308cde
21 files changed
+478
-902
No files matched your search
@@ -8,26 +8,16 @@ using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sits next to the <see cref="PlayerCharacterController"/> and holds a list of <see cref="PlayerPose"/>s
|
||||
/// plus the active index. The pose system owns all character animation — the Animator is left empty —
|
||||
/// so it drives locomotion itself: standing still (or airborne / on a wall / on the ceiling) holds the
|
||||
/// active pose's idle clip, walking on the ground plays that pose's optional walk clip, and sprinting
|
||||
/// on the ground plays its optional run clip. Either locomotion clip is optional; when a pose leaves
|
||||
/// one null, the idle pose is simply held in that state.
|
||||
/// Holds a list of <see cref="PlayerPose"/>s plus the active index. The pose system owns ALL character
|
||||
/// animation (the Animator is left empty): standing / airborne / wall / ceiling holds the active pose's
|
||||
/// idle clip, walking/sprinting on the ground plays its optional walk/run clip (unset = idle held).
|
||||
///
|
||||
/// One key cycles to the next pose (wrapping), and sprinting in any state (ground, air, wall, ceiling)
|
||||
/// snaps the selection back to the default pose. The selection is held continuously, so cycling or the
|
||||
/// sprint reset shows up immediately instead of only once the player comes to a stop.
|
||||
///
|
||||
/// Clips are played through a tiny <see cref="PlayableGraph"/> (a two-input
|
||||
/// <see cref="AnimationMixerPlayable"/> on an <see cref="AnimationPlayableOutput"/>) that drives the
|
||||
/// Animator directly. Switching clip — between poses, or between idle/walk/run within a pose —
|
||||
/// crossfades the outgoing and incoming clips over <see cref="poseBlendDuration"/> instead of snapping.
|
||||
/// Each pose also carries its own CharacterController capsule (center Y / radius / height): the active
|
||||
/// pose's dimensions are eased toward and written through the controller so a low pose (ball, star) can
|
||||
/// crawl under furniture the default standing capsule is too tall for. A per-pose camera y-offset is
|
||||
/// likewise eased and routed to the controller's camera target, framing each pose for the
|
||||
/// ThirdPersonCamera without moving the body.
|
||||
/// One key cycles poses (wrapping); sprinting in any state snaps back to the default pose, held
|
||||
/// continuously so the reset shows up immediately. Clips play through a tiny <see cref="PlayableGraph"/>
|
||||
/// (two-input mixer on an <see cref="AnimationPlayableOutput"/>) that crossfades every clip switch over
|
||||
/// <see cref="poseBlendDuration"/>. Each pose also carries its own CharacterController capsule (eased,
|
||||
/// so a low pose can crawl under furniture) and per-pose camera y-offsets (third-person framing and
|
||||
/// first-person eye).
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(PlayerCharacterController))]
|
||||
[DisallowMultipleComponent]
|
||||
@@ -83,11 +73,9 @@ public class PlayerPoseController : MonoBehaviour
|
||||
/// <summary>Locomotion category that selects which clip the active pose plays.</summary>
|
||||
public enum Locomotion { Idle, Walk, Run, Fall }
|
||||
|
||||
// Network drive: a remote avatar's PlayerCharacterController and CharacterController are disabled
|
||||
// (NetworkTransform owns its transform), so its movement-state flags are dead. Instead of reading
|
||||
// local input/physics, such an avatar takes its pose index and locomotion category from the owner
|
||||
// via SetNetworkState (pushed by PlayerAnimationSync). _currentLocomotion is the category resolved
|
||||
// this frame, published by the owner for replication.
|
||||
// Network drive: a remote avatar's controllers are disabled (NetworkTransform owns the transform),
|
||||
// so its movement flags are dead - pose index + locomotion come from the owner via SetNetworkState.
|
||||
// _currentLocomotion is the category resolved this frame, published by the owner for replication.
|
||||
private bool _networkControlled;
|
||||
private Locomotion _networkLoco;
|
||||
private Locomotion _currentLocomotion;
|
||||
@@ -118,13 +106,10 @@ public class PlayerPoseController : MonoBehaviour
|
||||
private float _capCenterY, _capRadius, _capHeight;
|
||||
private float _capBlend;
|
||||
|
||||
// Rest pose snapshot of the whole Animator subtree, taken in Awake before the Animator first
|
||||
// evaluates. An AnimationClipPlayable only writes the bones its curves cover, so a clip that
|
||||
// doesn't key a bone (an empty clip like the T-pose, or a partial one) would otherwise leave that
|
||||
// bone frozen on the previous animation. Restoring this before each pose start makes every pose
|
||||
// define the full body. The controller's model-offset transform (meshOffsetTarget) is explicitly
|
||||
// dropped from this set in CaptureRestPose — with the humanoid rig the Animator sits on that node,
|
||||
// so it is the root of this subtree, and resetting it would wipe the wall-lean / ground raise.
|
||||
// Rest-pose snapshot of the Animator subtree, taken before the Animator first evaluates. A clip only
|
||||
// writes the bones its curves cover, so un-keyed bones would stay frozen on the previous animation;
|
||||
// restoring rest first makes every pose define the full body. The controller's meshOffsetTarget is
|
||||
// dropped from the set (see CaptureRestPose) so the wall-lean / ground raise is never wiped.
|
||||
private Transform[] _restBones;
|
||||
private Vector3[] _restPos;
|
||||
private Quaternion[] _restRot;
|
||||
@@ -175,11 +160,10 @@ public class PlayerPoseController : MonoBehaviour
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Resolution freeze: hold the currently-evaluated pose. Keep the graph playing (so it re-asserts the
|
||||
// frozen frame every render, even under Animator culling) but zero the mixer's speed so clip time
|
||||
// stops advancing, and skip everything below so no locomotion/rest-reset moves a bone. The per-clip
|
||||
// speeds PlayPose writes onto the mixer INPUTS are unaffected; only the mixer's own multiplier is
|
||||
// zeroed here and restored on the first un-frozen frame just below.
|
||||
// Resolution freeze: keep the graph playing (it re-asserts the frozen frame every render, even
|
||||
// under Animator culling) but zero the MIXER's speed so clip time stops advancing; skip everything
|
||||
// below so no locomotion/rest-reset moves a bone. The per-input clip speeds are untouched; the
|
||||
// mixer multiplier is restored on the first un-frozen frame just below.
|
||||
if (Frozen)
|
||||
{
|
||||
if (_graph.IsValid())
|
||||
@@ -192,8 +176,7 @@ public class PlayerPoseController : MonoBehaviour
|
||||
if (_mixer.IsValid() && PlayableExtensions.GetSpeed(_mixer) == 0d)
|
||||
PlayableExtensions.SetSpeed(_mixer, 1d);
|
||||
|
||||
// Local control: the cycle key and the sprint reset choose the pose. A network-driven (remote)
|
||||
// avatar skips this — its pose index is pushed in from the owner via SetNetworkState.
|
||||
// Local control only - a remote's pose index is pushed in via SetNetworkState.
|
||||
if (!_networkControlled)
|
||||
{
|
||||
if (CycleKeyPressed())
|
||||
@@ -207,12 +190,9 @@ public class PlayerPoseController : MonoBehaviour
|
||||
|
||||
PlayerPose pose = ActivePose();
|
||||
|
||||
// Resolve the locomotion category (idle / walk / run / fall) and pick its clip. Locally the
|
||||
// category comes from the controller's movement state; on a remote avatar it is the replicated
|
||||
// value. It is stored so the owner's PlayerAnimationSync can publish it. ClipFor falls back to
|
||||
// the idle clip for an unset optional clip, so a remote avatar (same pose asset) resolves to
|
||||
// exactly the clip the owner shows; PlayPose crossfades on any change and hands the rig back
|
||||
// only when there is no clip at all (empty list / null idle clip).
|
||||
// Resolve the locomotion category and its clip: locally from the controller's movement state, on
|
||||
// a remote the replicated value. ClipFor falls back to idle for unset optional clips, so a remote
|
||||
// (same pose asset) resolves to exactly the clip the owner shows.
|
||||
_currentLocomotion = _networkControlled ? _networkLoco : ResolveLocalLocomotion();
|
||||
AnimationClip clip = ClipFor(pose, _currentLocomotion, out float speed);
|
||||
PlayPose(clip, speed);
|
||||
@@ -222,10 +202,8 @@ public class PlayerPoseController : MonoBehaviour
|
||||
if (_networkControlled)
|
||||
return;
|
||||
|
||||
// CharacterController capsule: each pose carries its own center Y / radius / height so a low pose
|
||||
// (ball, star) can crawl where the default standing capsule is too tall. Eased toward the active
|
||||
// pose's dimensions when the pose changes so the collider resizes smoothly instead of popping; a
|
||||
// pose that leaves them unset (height/radius <= 0) keeps the default capsule.
|
||||
// Per-pose collision capsule so a low pose can crawl where the standing capsule is too tall;
|
||||
// unset dimensions (<= 0) keep the default capsule.
|
||||
bool hasCapsule = pose && pose.ControllerHeight > 0f && pose.ControllerRadius > 0f;
|
||||
float capCenterY = hasCapsule ? pose.ControllerCenterY : _player.BaseCapsuleCenterY;
|
||||
float capRadius = hasCapsule ? pose.ControllerRadius : _player.BaseCapsuleRadius;
|
||||
@@ -240,9 +218,8 @@ public class PlayerPoseController : MonoBehaviour
|
||||
: cameraPoseTarget;
|
||||
_player.SetCameraTargetLocalYOffset(_cameraPoseOffset);
|
||||
|
||||
// First-person eye: a separate per-pose offset, eased the same way but NOT routed to the shared
|
||||
// camera target (that would also move the ThirdPersonCamera). The FirstPersonController reads this
|
||||
// and applies it to its own eye position only.
|
||||
// Separate per-pose first-person eye offset - NOT routed to the shared camera target (that would
|
||||
// also move the ThirdPersonCamera); the FirstPersonController reads it directly.
|
||||
float firstPersonTarget = pose ? pose.FirstPersonCameraTargetYOffset : 0f;
|
||||
_firstPersonCameraOffset = cameraOffsetSpeed > 0f
|
||||
? Mathf.MoveTowards(_firstPersonCameraOffset, firstPersonTarget, cameraOffsetSpeed * Time.deltaTime)
|
||||
@@ -364,7 +341,7 @@ public class PlayerPoseController : MonoBehaviour
|
||||
|
||||
private bool CycleKeyPressed()
|
||||
{
|
||||
if (TypingGuard.IsTyping) return false; // don't cycle pose while typing in a text field
|
||||
if (TypingGuard.IsTyping) return false;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
var keyboard = Keyboard.current;
|
||||
return keyboard != null && keyboard[cycleKey].wasPressedThisFrame;
|
||||
@@ -396,16 +373,13 @@ public class PlayerPoseController : MonoBehaviour
|
||||
|
||||
AdvanceBlend(Time.deltaTime);
|
||||
|
||||
// Set every frame (not just on clip change) so tuning a pose's speed slider live in the inspector
|
||||
// takes effect immediately and re-selecting the same clip keeps its speed. The outgoing pose on
|
||||
// input 0 keeps the speed it carried, so a crossfade fades it out at its own pace.
|
||||
// Set every frame so live speed-slider tuning takes effect immediately; the outgoing pose on
|
||||
// input 0 keeps the speed it carried, fading out at its own pace.
|
||||
if (_toPlayable.IsValid())
|
||||
PlayableExtensions.SetSpeed(_toPlayable, speed);
|
||||
|
||||
// Snap un-keyed bones to rest every frame, so each mixer input blends relative to rest: a
|
||||
// partial or empty clip (e.g. the T-pose) defines the whole body, and a crossfade interpolates
|
||||
// both poses against the same baseline. The graph overrides the keyed bones, weighted, when it
|
||||
// evaluates later this frame.
|
||||
// Snap un-keyed bones to rest every frame so each mixer input blends relative to the same
|
||||
// baseline; the graph then overrides the keyed bones when it evaluates later this frame.
|
||||
ResetToRestPose();
|
||||
|
||||
if (!_graph.IsPlaying())
|
||||
@@ -516,12 +490,9 @@ public class PlayerPoseController : MonoBehaviour
|
||||
_restScale[i] = t.localScale;
|
||||
}
|
||||
|
||||
// Drop the model-offset transform from the reset set so the per-frame ResetToRestPose never
|
||||
// touches it: the wall-lean / ground raise (PlayerCharacterController.SetMeshLean) is its sole
|
||||
// writer. With the humanoid rig the Animator shares this node, putting it in the captured subtree;
|
||||
// resetting it each frame is exactly what was wiping the offsets. Nulling the slot makes
|
||||
// ResetToRestPose's null-guard skip it. _player is resolved (and meshOffsetTarget too, since the
|
||||
// controller's Awake runs first at its lower execution order) before this runs.
|
||||
// Drop the model-offset transform from the reset set: the wall-lean / ground raise (SetMeshLean)
|
||||
// is its sole writer, and with the humanoid rig the Animator shares this node - resetting it each
|
||||
// frame was exactly what wiped the offsets. Nulling the slot makes ResetToRestPose skip it.
|
||||
Transform offsetTarget = _player ? _player.MeshOffsetTarget : null;
|
||||
if (offsetTarget)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user