Split posture: eyes+head on selection, body on conversation start

PostureComponent gains bEnableBodyTracking flag. When false, only
head and eyes track the target — body stays frozen.

InteractionComponent now:
- On posture attach: sets TargetActor but disables body tracking
  (agent notices player with eyes+head only)
- On StartListening: enables body tracking (agent fully engages)
- On StopListening: disables body tracking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
j.foucher 2026-02-27 18:26:27 +01:00
parent 23e216b211
commit 92a8b70a7f
3 changed files with 31 additions and 7 deletions

View File

@ -198,6 +198,12 @@ void UPS_AI_ConvAgent_InteractionComponent::SetSelectedAgent(UPS_AI_ConvAgent_El
if (bAutoManageListening)
{
OldAgent->StopListening();
// Disable body tracking — eyes+head will return to neutral via posture detach.
if (UPS_AI_ConvAgent_PostureComponent* Posture = FindPostureOnAgent(OldAgent))
{
Posture->bEnableBodyTracking = false;
}
}
// ── Posture: detach ──────────────────────────────────────────────
@ -244,6 +250,12 @@ void UPS_AI_ConvAgent_InteractionComponent::SetSelectedAgent(UPS_AI_ConvAgent_El
if (bAutoManageListening)
{
NewAgent->StartListening();
// Now that we're talking, enable full body tracking.
if (UPS_AI_ConvAgent_PostureComponent* Posture = FindPostureOnAgent(NewAgent))
{
Posture->bEnableBodyTracking = true;
}
}
// ── Posture: attach ──────────────────────────────────────────────
@ -345,10 +357,12 @@ void UPS_AI_ConvAgent_InteractionComponent::AttachPostureTarget(
if (UPS_AI_ConvAgent_PostureComponent* Posture = FindPostureOnAgent(AgentPtr))
{
Posture->TargetActor = GetOwner();
// Eyes+head only at first — body tracking is enabled when listening starts.
Posture->bEnableBodyTracking = false;
if (bDebug)
{
UE_LOG(LogPS_AI_ConvAgent_Select, Log, TEXT("Posture attached: %s -> %s"),
UE_LOG(LogPS_AI_ConvAgent_Select, Log, TEXT("Posture attached (eyes+head only): %s -> %s"),
AgentPtr->GetOwner() ? *AgentPtr->GetOwner()->GetName() : TEXT("(null)"),
GetOwner() ? *GetOwner()->GetName() : TEXT("(null)"));
}

View File

@ -240,12 +240,16 @@ void UPS_AI_ConvAgent_PostureComponent::TickComponent(
}
// Body smoothly interpolates toward its persistent target
const float BodyDelta = FMath::FindDeltaAngleDegrees(
Owner->GetActorRotation().Yaw, TargetBodyWorldYaw);
if (FMath::Abs(BodyDelta) > 0.1f)
// (only when body tracking is enabled — otherwise only head+eyes move).
if (bEnableBodyTracking)
{
const float BodyStep = FMath::FInterpTo(0.0f, BodyDelta, SafeDeltaTime, BodyInterpSpeed);
Owner->AddActorWorldRotation(FRotator(0.0f, BodyStep, 0.0f));
const float BodyDelta = FMath::FindDeltaAngleDegrees(
Owner->GetActorRotation().Yaw, TargetBodyWorldYaw);
if (FMath::Abs(BodyDelta) > 0.1f)
{
const float BodyStep = FMath::FInterpTo(0.0f, BodyDelta, SafeDeltaTime, BodyInterpSpeed);
Owner->AddActorWorldRotation(FRotator(0.0f, BodyStep, 0.0f));
}
}
// ── 3. Compute DeltaYaw after body interp ──────────────────────────
@ -274,7 +278,7 @@ void UPS_AI_ConvAgent_PostureComponent::TickComponent(
BodyTargetFacing, TargetWorldYaw);
bool bBodyOverflowed = false;
if (FMath::Abs(DeltaFromBodyTarget) > MaxHeadYaw + MaxEyeHorizontal)
if (bEnableBodyTracking && FMath::Abs(DeltaFromBodyTarget) > MaxHeadYaw + MaxEyeHorizontal)
{
// Body realigns to face target
TargetBodyWorldYaw = TargetWorldYaw - MeshForwardYawOffset;

View File

@ -73,6 +73,12 @@ public:
meta = (ToolTip = "Target actor to look at.\nSet to null to return to neutral."))
TObjectPtr<AActor> TargetActor;
/** When false, body rotation is frozen — only head and eyes track the target.
* Useful to have the agent notice the player (eyes+head) before fully engaging (body). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Posture",
meta = (ToolTip = "Enable body rotation toward the target.\nWhen false, only head and eyes track."))
bool bEnableBodyTracking = true;
/** Offset from the target actor's origin to aim at.
* Useful for actors without a skeleton (e.g. (0,0,160) for eye-level). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Posture",