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

@@ -138,6 +138,9 @@ public partial class PlayerCharacterController : MonoBehaviour
[Tooltip("Visual model root moved by the wall-climb lean offset (into/out of the wall) while the capsule stays put. Must parent both the skinned mesh and its bones. Auto-resolved from the SkinnedMeshRenderer if empty.")]
[SerializeField] private Transform meshOffsetTarget;
[Tooltip("Camera follow/look target (what the ThirdPersonCamera tracks). Moved vertically by the active pose's camera y-offset plus the ceiling offset, without moving the body. Auto-resolved from a child named \"CameraTarget\" if empty.")]
[SerializeField] private Transform cameraTarget;
/// <summary>
/// When false, movement/jump input is ignored but gravity and ground contact
/// keep running. Toggled by the GameModeManager.
@@ -214,6 +217,8 @@ public partial class PlayerCharacterController : MonoBehaviour
private bool _offsetDragging; // true while the offset/rotation is being set (pauses camera orbit)
private bool _climbLeftGround; // true once the capsule has left the ground while climbing (enables ground-detach)
private Vector3 _meshBaseLocalPos; // meshOffsetTarget's authored local position; the lean offset is applied relative to this
private Vector3 _cameraTargetBaseLocalPos; // cameraTarget's authored local position; the pose/ceiling camera offset is applied relative to this
private float _cameraYOffset; // last camera-target local-up offset written (cached so an unchanged value skips the transform write)
private float _meshOffsetResidual; // leftover mesh lean still easing back to 0 after leaving the wall (no longer climbing)
private Vector3 _meshOffsetExitNormal; // wall normal latched at exit; the residual eases along it (live _wallNormal may shift on stray contact)
private readonly RaycastHit[] _wallProbe = new RaycastHit[8];
@@ -248,6 +253,13 @@ public partial class PlayerCharacterController : MonoBehaviour
}
}
if (meshOffsetTarget) _meshBaseLocalPos = meshOffsetTarget.localPosition;
if (!cameraTarget)
{
Transform t = transform.Find("CameraTarget");
if (t) cameraTarget = t;
}
if (cameraTarget) _cameraTargetBaseLocalPos = cameraTarget.localPosition;
}
void Update()
@@ -778,6 +790,19 @@ public partial class PlayerCharacterController : MonoBehaviour
SetMeshLean(_meshOffsetExitNormal, _meshOffsetResidual);
}
/// <summary>
/// Places the camera target (the ThirdPersonCamera's follow/look target) at the given local-up
/// offset relative to its authored local position, without moving the body. Driven by
/// <see cref="PlayerPoseController"/> with the active pose's camera y-offset plus the ceiling offset;
/// 0 restores the authored target height. Cached so an unchanged value skips the write.
/// </summary>
public void SetCameraTargetLocalYOffset(float y)
{
if (!cameraTarget || _cameraYOffset == y) return;
_cameraYOffset = y;
cameraTarget.localPosition = _cameraTargetBaseLocalPos + Vector3.up * y;
}
/// <summary>
/// Raycasts from the character center toward the surface (along -_wallNormal) to find the
/// current normal and the gap (surface clearance) to it. The capsule's support distance