Add per-pose camera target Y offset and route ceiling offset to camera

Add cameraTargetYOffset to PlayerPose so each pose can offset the
Cinemachine ThirdPersonCamera follow/look target independently of the
body mesh. PlayerCharacterController gains a cameraTarget reference
(auto-resolved via the "CameraTarget" child, base position captured in
Awake) and a single-writer SetCameraTargetLocalYOffset. PlayerPoseController
eases the per-pose camera offset and composes it with the shared ceiling
offset, so the camera target follows the ceiling lift in lockstep with the
mesh. Wire cameraTarget explicitly in SampleScene.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-26 22:01:43 +02:00
1 parent ba7f8804c5
commit 0edc59555a
4 files changed
+51 -1

No files matched your search

+16 -1
View File
@@ -24,6 +24,8 @@ using UnityEngine.InputSystem;
/// crossfades the outgoing and incoming clips over <see cref="poseBlendDuration"/> instead of snapping.
/// The per-pose ceiling y-offset is eased toward its target and routed through the controller (the
/// single writer of the model-offset transform) so it composes with the wall-lean instead of fighting it.
/// A separate per-pose camera y-offset (plus that same ceiling offset) is likewise eased and routed to the
/// controller's camera target, framing each pose for the ThirdPersonCamera without moving the body.
/// </summary>
[RequireComponent(typeof(PlayerCharacterController))]
[DisallowMultipleComponent]
@@ -83,7 +85,8 @@ public partial class PlayerPoseController : MonoBehaviour
private float _blend; // 0..1 weight of the "to" input; 1 = fully on the target pose
private bool _blending;
private float _ceilingOffset; // eased local-up offset currently fed to the controller
private float _ceilingOffset; // eased local-up offset currently fed to the controller (mesh + camera)
private float _cameraPoseOffset; // eased per-pose camera-target offset; the ceiling offset is added on top when routed to the controller
// 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
@@ -149,6 +152,16 @@ public partial class PlayerPoseController : MonoBehaviour
? Mathf.MoveTowards(_ceilingOffset, ceilingTarget, ceilingOffsetSpeed * Time.deltaTime)
: ceilingTarget;
_player.SetPoseLocalYOffset(_ceilingOffset);
// Camera target: a per-pose framing offset (applied in any state) plus the same ceiling offset,
// routed to the ThirdPersonCamera's follow target only (never the body). The pose part eases like
// the ceiling offset so cycling poses glides the camera; the ceiling part reuses the value above so
// camera and model stay in lockstep on the ceiling.
float cameraPoseTarget = pose ? pose.CameraTargetYOffset : 0f;
_cameraPoseOffset = ceilingOffsetSpeed > 0f
? Mathf.MoveTowards(_cameraPoseOffset, cameraPoseTarget, ceilingOffsetSpeed * Time.deltaTime)
: cameraPoseTarget;
_player.SetCameraTargetLocalYOffset(_cameraPoseOffset + _ceilingOffset);
}
void OnDisable()
@@ -157,9 +170,11 @@ public partial class PlayerPoseController : MonoBehaviour
// next idle frame. Also clear any ceiling offset we were holding.
ReleasePose();
_ceilingOffset = 0f;
_cameraPoseOffset = 0f;
if (_player)
{
_player.SetPoseLocalYOffset(0f);
_player.SetCameraTargetLocalYOffset(0f);
}
}