Files
chameleon/Assets/Scripts/PlayerPose.cs
T
adminandClaude Opus 4.8 cfb767f6cb Add first-person camera mode with pose-aware eye offset and yaw facing
Introduce a FirstPersonController / FirstPersonMode pair (mirroring the
free-cam mode) wired into the GameModeManager Tab cycle. In first person the
mesh is hidden, the eye sits on CameraTarget plus a per-pose
firstPersonCameraTargetYOffset, and the character body yaw is driven to match
the camera via a new single-writer FaceYaw hook on PlayerCharacterController.

Also includes user content edits (poses, prefabs, scene) carried along.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 13:03:52 +02:00

100 lines
5.4 KiB
C#

using UnityEngine;
/// <summary>
/// A selectable player pose: an idle <see cref="AnimationClip"/> held while the player stands still,
/// plus optional walk and run clips that the pose system plays itself (the Animator stays empty) while
/// moving on the ground, its own CharacterController capsule dimensions (so a low pose like a ball can
/// crawl under furniture the default standing capsule is too tall for), and a camera-target y-offset that
/// frames the pose without moving the body. The first ScriptableObject in this project.
///
/// Named PlayerPose (not Pose) to avoid shadowing the built-in UnityEngine.Pose struct, mirroring
/// why the controller is PlayerCharacterController and not just "PlayerController".
/// </summary>
[CreateAssetMenu(fileName = "NewPose", menuName = "Chameleon/Pose")]
public class PlayerPose : ScriptableObject
{
[Tooltip("Clip held while the player is idle in this pose (looped if the clip itself loops, " +
"otherwise frozen on its last frame). Authored for the paintman generic rig; clips for " +
"other hierarchies will not retarget.")]
[SerializeField] private AnimationClip clip;
[Tooltip("Playback speed multiplier for the idle clip. 1 = authored speed.")]
[Range(0.1f, 3f)]
[SerializeField] private float clipSpeed = 1f;
[Tooltip("Optional. Played instead of the idle clip while walking on the ground (moving, not " +
"sprinting). Leave empty to keep holding the idle pose while walking. Should loop.")]
[SerializeField] private AnimationClip walkClip;
[Tooltip("Playback speed multiplier for the walk clip. 1 = authored speed.")]
[Range(0.1f, 3f)]
[SerializeField] private float walkClipSpeed = 1f;
[Tooltip("Optional. Played instead of the idle clip while sprinting on the ground. Leave empty to " +
"keep holding the idle pose while sprinting. Should loop.")]
[SerializeField] private AnimationClip runClip;
[Tooltip("Playback speed multiplier for the run clip. 1 = authored speed.")]
[Range(0.1f, 3f)]
[SerializeField] private float runClipSpeed = 1f;
[Header("Collision")]
[Tooltip("CharacterController capsule center Y while this pose is active (meters, local space). Lower " +
"this together with Height so a short pose still rests its feet on the floor.")]
[SerializeField] private float controllerCenterY = 0.66f;
[Tooltip("CharacterController capsule radius while this pose is active (meters). Unity clamps it to " +
"half the height.")]
[Min(0.01f)]
[SerializeField] private float controllerRadius = 0.1f;
[Tooltip("CharacterController capsule height while this pose is active (meters). Lower it (with Center " +
"Y) so a ball/star pose can crawl under a table or couch the default capsule is too tall for.")]
[Min(0.01f)]
[SerializeField] private float controllerHeight = 1.3f;
[Tooltip("Local-up offset applied to the camera target (the ThirdPersonCamera's follow/look target) " +
"while this pose is active, in ANY state. Frames the pose by raising/lowering what the camera " +
"tracks, without moving the body. Meters.")]
[SerializeField] private float cameraTargetYOffset;
[Tooltip("Additional local-up offset applied to the first-person eye (the FirstPersonController's camera " +
"position) while this pose is active, on top of the shared camera target. Only affects first " +
"person — never the body or the ThirdPersonCamera. Lets a low pose (ball/star) keep its eye at a " +
"sensible height even though the camera target sits where third-person frames it. Meters.")]
[SerializeField] private float firstPersonCameraTargetYOffset;
/// <summary>Idle clip held while the player stands still in this pose (may be null).</summary>
public AnimationClip Clip => clip;
/// <summary>Playback speed multiplier for the idle clip (1 = authored speed).</summary>
public float ClipSpeed => clipSpeed;
/// <summary>Optional clip played while walking on the ground; null = hold the idle pose.</summary>
public AnimationClip WalkClip => walkClip;
/// <summary>Playback speed multiplier for the walk clip (1 = authored speed).</summary>
public float WalkClipSpeed => walkClipSpeed;
/// <summary>Optional clip played while sprinting on the ground; null = hold the idle pose.</summary>
public AnimationClip RunClip => runClip;
/// <summary>Playback speed multiplier for the run clip (1 = authored speed).</summary>
public float RunClipSpeed => runClipSpeed;
/// <summary>CharacterController capsule center Y applied while this pose is active.</summary>
public float ControllerCenterY => controllerCenterY;
/// <summary>CharacterController capsule radius applied while this pose is active.</summary>
public float ControllerRadius => controllerRadius;
/// <summary>CharacterController capsule height applied while this pose is active.</summary>
public float ControllerHeight => controllerHeight;
/// <summary>Local-up offset applied to the camera target while this pose is active (any state).</summary>
public float CameraTargetYOffset => cameraTargetYOffset;
/// <summary>Additional local-up offset for the first-person eye, on top of the camera target (first person only).</summary>
public float FirstPersonCameraTargetYOffset => firstPersonCameraTargetYOffset;
}