Add auto posture management to InteractionComponent
InteractionComponent now automatically sets/clears the agent's PostureComponent TargetActor on selection/deselection, with configurable attach/detach delays and a master toggle for manual control. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b1bac66256
commit
c6aed472f9
@ -4,10 +4,12 @@
|
||||
#include "PS_AI_ConvAgent_InteractionSubsystem.h"
|
||||
#include "PS_AI_ConvAgent_ElevenLabsComponent.h"
|
||||
#include "PS_AI_ConvAgent_MicrophoneCaptureComponent.h"
|
||||
#include "PS_AI_ConvAgent_PostureComponent.h"
|
||||
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "Camera/PlayerCameraManager.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogPS_AI_ConvAgent_Select, Log, All);
|
||||
|
||||
@ -48,6 +50,13 @@ void UPS_AI_ConvAgent_InteractionComponent::BeginPlay()
|
||||
|
||||
void UPS_AI_ConvAgent_InteractionComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
// Cancel any pending posture timers.
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
World->GetTimerManager().ClearTimer(PostureAttachTimerHandle);
|
||||
World->GetTimerManager().ClearTimer(PostureDetachTimerHandle);
|
||||
}
|
||||
|
||||
if (MicComponent)
|
||||
{
|
||||
MicComponent->StopCapture();
|
||||
@ -57,6 +66,12 @@ void UPS_AI_ConvAgent_InteractionComponent::EndPlay(const EEndPlayReason::Type E
|
||||
// Fire deselection event for cleanup.
|
||||
if (UPS_AI_ConvAgent_ElevenLabsComponent* Agent = SelectedAgent.Get())
|
||||
{
|
||||
// Clear posture immediately on shutdown — no delay.
|
||||
if (bAutoManagePosture)
|
||||
{
|
||||
DetachPostureTarget(Agent);
|
||||
}
|
||||
|
||||
SelectedAgent.Reset();
|
||||
OnAgentDeselected.Broadcast(Agent);
|
||||
}
|
||||
@ -162,6 +177,7 @@ UPS_AI_ConvAgent_ElevenLabsComponent* UPS_AI_ConvAgent_InteractionComponent::Eva
|
||||
void UPS_AI_ConvAgent_InteractionComponent::SetSelectedAgent(UPS_AI_ConvAgent_ElevenLabsComponent* NewAgent)
|
||||
{
|
||||
UPS_AI_ConvAgent_ElevenLabsComponent* OldAgent = SelectedAgent.Get();
|
||||
UWorld* World = GetWorld();
|
||||
|
||||
// Deselect old agent.
|
||||
if (OldAgent)
|
||||
@ -174,6 +190,26 @@ void UPS_AI_ConvAgent_InteractionComponent::SetSelectedAgent(UPS_AI_ConvAgent_El
|
||||
OldAgent->GetOwner() ? *OldAgent->GetOwner()->GetName() : TEXT("(null)"));
|
||||
}
|
||||
|
||||
// ── Posture: detach ──────────────────────────────────────────────
|
||||
if (bAutoManagePosture && World)
|
||||
{
|
||||
// Cancel any pending attach — agent left before attach fired.
|
||||
World->GetTimerManager().ClearTimer(PostureAttachTimerHandle);
|
||||
|
||||
if (PostureDetachDelay > 0.0f)
|
||||
{
|
||||
TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> WeakOld = OldAgent;
|
||||
World->GetTimerManager().SetTimer(PostureDetachTimerHandle,
|
||||
FTimerDelegate::CreateUObject(this,
|
||||
&UPS_AI_ConvAgent_InteractionComponent::DetachPostureTarget, WeakOld),
|
||||
PostureDetachDelay, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DetachPostureTarget(OldAgent);
|
||||
}
|
||||
}
|
||||
|
||||
OnAgentDeselected.Broadcast(OldAgent);
|
||||
}
|
||||
|
||||
@ -194,6 +230,26 @@ void UPS_AI_ConvAgent_InteractionComponent::SetSelectedAgent(UPS_AI_ConvAgent_El
|
||||
MicComponent->StartCapture();
|
||||
}
|
||||
|
||||
// ── Posture: attach ──────────────────────────────────────────────
|
||||
if (bAutoManagePosture && World)
|
||||
{
|
||||
// Cancel any pending detach — agent came back before detach fired.
|
||||
World->GetTimerManager().ClearTimer(PostureDetachTimerHandle);
|
||||
|
||||
if (PostureAttachDelay > 0.0f)
|
||||
{
|
||||
TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> WeakNew = NewAgent;
|
||||
World->GetTimerManager().SetTimer(PostureAttachTimerHandle,
|
||||
FTimerDelegate::CreateUObject(this,
|
||||
&UPS_AI_ConvAgent_InteractionComponent::AttachPostureTarget, WeakNew),
|
||||
PostureAttachDelay, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachPostureTarget(NewAgent);
|
||||
}
|
||||
}
|
||||
|
||||
OnAgentSelected.Broadcast(NewAgent);
|
||||
}
|
||||
else
|
||||
@ -252,6 +308,55 @@ void UPS_AI_ConvAgent_InteractionComponent::ClearSelection()
|
||||
SetSelectedAgent(nullptr);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Posture helpers
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
UPS_AI_ConvAgent_PostureComponent* UPS_AI_ConvAgent_InteractionComponent::FindPostureOnAgent(
|
||||
UPS_AI_ConvAgent_ElevenLabsComponent* Agent)
|
||||
{
|
||||
if (!Agent) return nullptr;
|
||||
AActor* AgentActor = Agent->GetOwner();
|
||||
if (!AgentActor) return nullptr;
|
||||
return AgentActor->FindComponentByClass<UPS_AI_ConvAgent_PostureComponent>();
|
||||
}
|
||||
|
||||
void UPS_AI_ConvAgent_InteractionComponent::AttachPostureTarget(
|
||||
TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> Agent)
|
||||
{
|
||||
UPS_AI_ConvAgent_ElevenLabsComponent* AgentPtr = Agent.Get();
|
||||
if (!AgentPtr) return;
|
||||
|
||||
if (UPS_AI_ConvAgent_PostureComponent* Posture = FindPostureOnAgent(AgentPtr))
|
||||
{
|
||||
Posture->TargetActor = GetOwner();
|
||||
|
||||
if (bDebug)
|
||||
{
|
||||
UE_LOG(LogPS_AI_ConvAgent_Select, Log, TEXT("Posture attached: %s -> %s"),
|
||||
AgentPtr->GetOwner() ? *AgentPtr->GetOwner()->GetName() : TEXT("(null)"),
|
||||
GetOwner() ? *GetOwner()->GetName() : TEXT("(null)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UPS_AI_ConvAgent_InteractionComponent::DetachPostureTarget(
|
||||
TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> Agent)
|
||||
{
|
||||
UPS_AI_ConvAgent_ElevenLabsComponent* AgentPtr = Agent.Get();
|
||||
if (!AgentPtr) return;
|
||||
|
||||
if (UPS_AI_ConvAgent_PostureComponent* Posture = FindPostureOnAgent(AgentPtr))
|
||||
{
|
||||
Posture->TargetActor = nullptr;
|
||||
|
||||
if (bDebug)
|
||||
{
|
||||
UE_LOG(LogPS_AI_ConvAgent_Select, Log, TEXT("Posture detached: %s"),
|
||||
AgentPtr->GetOwner() ? *AgentPtr->GetOwner()->GetName() : TEXT("(null)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Mic routing
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
class UPS_AI_ConvAgent_ElevenLabsComponent;
|
||||
class UPS_AI_ConvAgent_MicrophoneCaptureComponent;
|
||||
class UPS_AI_ConvAgent_PostureComponent;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Delegates
|
||||
@ -82,6 +83,29 @@ public:
|
||||
meta = (ToolTip = "Require the player to look at an agent to select it.\nWhen false, the closest agent within range is always selected."))
|
||||
bool bRequireLookAt = true;
|
||||
|
||||
// ── Posture management ───────────────────────────────────────────────────
|
||||
|
||||
/** Automatically set/clear the agent's PostureComponent TargetActor
|
||||
* when the agent is selected/deselected. When false, posture must
|
||||
* be managed from Blueprint (e.g. on conversation start). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Posture",
|
||||
meta = (ToolTip = "Automatically point the agent's posture at the pawn on selection.\nDisable for manual control (e.g. set target only when conversation starts)."))
|
||||
bool bAutoManagePosture = true;
|
||||
|
||||
/** Delay (seconds) before setting the agent's posture target after selection.
|
||||
* 0 = immediate. Useful to let the agent "notice" the player with a beat. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Posture",
|
||||
meta = (EditCondition = "bAutoManagePosture", ClampMin = "0",
|
||||
ToolTip = "Seconds to wait before the agent looks at the pawn.\n0 = immediate."))
|
||||
float PostureAttachDelay = 0.0f;
|
||||
|
||||
/** Delay (seconds) before clearing the agent's posture target after deselection.
|
||||
* 0 = immediate. Useful to have the agent keep looking briefly as the player leaves. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Posture",
|
||||
meta = (EditCondition = "bAutoManagePosture", ClampMin = "0",
|
||||
ToolTip = "Seconds to wait before the agent stops looking at the pawn.\n0 = immediate."))
|
||||
float PostureDetachDelay = 0.0f;
|
||||
|
||||
// ── Debug ────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Enable debug logging for this component. */
|
||||
@ -144,6 +168,17 @@ private:
|
||||
/** Get the pawn's view location and direction (uses camera or control rotation). */
|
||||
void GetPawnViewPoint(FVector& OutLocation, FVector& OutDirection) const;
|
||||
|
||||
// ── Posture helpers ──────────────────────────────────────────────────────
|
||||
|
||||
/** Find the PostureComponent on an agent's owner actor (null if absent). */
|
||||
static UPS_AI_ConvAgent_PostureComponent* FindPostureOnAgent(UPS_AI_ConvAgent_ElevenLabsComponent* Agent);
|
||||
|
||||
/** Set the agent's PostureComponent target to the pawn (attach). */
|
||||
void AttachPostureTarget(TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> Agent);
|
||||
|
||||
/** Clear the agent's PostureComponent target (detach). */
|
||||
void DetachPostureTarget(TWeakObjectPtr<UPS_AI_ConvAgent_ElevenLabsComponent> Agent);
|
||||
|
||||
// ── Mic routing ──────────────────────────────────────────────────────────
|
||||
|
||||
/** Forward captured mic audio to the currently selected agent. */
|
||||
@ -160,4 +195,9 @@ private:
|
||||
|
||||
/** True while ForceSelectAgent is active (suppresses automatic re-evaluation for one frame). */
|
||||
bool bForceSelectionActive = false;
|
||||
|
||||
// ── Posture timers ───────────────────────────────────────────────────────
|
||||
|
||||
FTimerHandle PostureAttachTimerHandle;
|
||||
FTimerHandle PostureDetachTimerHandle;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user