ASC学习笔记0001:处理目标选择系统中当Actor拒绝目标确认时的调用

中文注释:UrealEngine-5.2.1源码-AbilitySystemComponent.h

cpp 复制代码
/** 当目标选择Actor拒绝目标确认时调用 */
DECLARE_MULTICAST_DELEGATE_OneParam(FTargetingRejectedConfirmation, int32);

一、这是一个C++中的多播委托声明,用于处理目标选择系统中当Actor拒绝目标确认时的回调机制。让我详细解释一下这个声明:

组成部分:

  • DECLARE_MULTICAST_DELEGATE_OneParam - 宏声明,创建一个可以绑定多个回调函数的多播委托,带有一个参数

  • FTargetingRejectedConfirmation - 委托类型名称

  • int32 - 委托的参数类型,这里是一个32位整数

使用示例

1. 声明委托变量:

cpp 复制代码
// 在类中声明
FTargetingRejectedConfirmation OnTargetingRejected;

2. 绑定回调函数

cpp 复制代码
// 绑定Lambda表达式
OnTargetingRejected.AddLambda([](int32 TargetID) {
    UE_LOG(LogTemp, Warning, TEXT("目标 %d 拒绝确认"), TargetID);
});

// 绑定成员函数
OnTargetingRejected.AddUObject(this, &AMyClass::HandleTargetRejection);

3. 触发委托

cpp 复制代码
// 当目标拒绝确认时
void AMyTargetingSystem::RejectTargetConfirmation(int32 TargetID)
{
    // 广播给所有绑定的回调函数
    OnTargetingRejected.Broadcast(TargetID);
}

4. 完整的类示例

cpp 复制代码
UCLASS()
class MYGAME_API ATargetingSystem : public AActor
{
    GENERATED_BODY()

public:
    // 委托声明
    FTargetingRejectedConfirmation OnTargetingRejected;

    // 触发目标拒绝的方法
    void ProcessTargetRejection(int32 RejectedTargetID)
    {
        // 执行一些逻辑...
        
        // 广播委托
        OnTargetingRejected.Broadcast(RejectedTargetID);
    }

private:
    // 处理目标拒绝的成员函数
    UFUNCTION()
    void HandleTargetRejected(int32 TargetID)
    {
        UE_LOG(LogTemp, Warning, TEXT("处理目标 %d 的拒绝"), TargetID);
        // 执行相应的游戏逻辑
    }

public:
    // 在BeginPlay中绑定委托
    virtual void BeginPlay() override
    {
        Super::BeginPlay();
        OnTargetingRejected.AddUObject(this, &ATargetingSystem::HandleTargetRejected);
    }
};

应用场景

这种委托模式常用于:

  • 目标选择系统 - 当玩家选择的目标无效或被拒绝时

  • UI交互 - 处理用户取消操作

  • 任务系统 - 处理任务目标失败的情况

  • 多人游戏 - 同步玩家间的目标选择状态

这种设计提供了很好的解耦,让不同的系统可以监听目标拒绝事件并做出相应反应。

二、在实战项目中,FTargetingRejectedConfirmation 这样的目标选择拒绝确认委托有着广泛的应用场景。以下是一些具体的实际应用案例:

1. 技能系统目标选择

技能目标选择器

cpp 复制代码
// 技能组件
UCLASS()
class USkillComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    FTargetingRejectedConfirmation OnTargetRejected;

    // 开始选择技能目标
    void StartTargetSelection(int32 SkillID)
    {
        CurrentSkillID = SkillID;
        bIsSelectingTarget = true;
        
        // 显示目标选择UI
        ShowTargetingUI();
    }

    // 确认目标选择
    void ConfirmTarget(int32 TargetID)
    {
        if (!IsValidTarget(TargetID))
        {
            // 目标无效,触发拒绝事件
            OnTargetRejected.Broadcast(TargetID);
            HandleTargetRejection(TargetID);
            return;
        }
        
        ExecuteSkill(CurrentSkillID, TargetID);
    }

private:
    void HandleTargetRejection(int32 TargetID)
    {
        // 播放拒绝音效
        PlayRejectionSound();
        
        // 显示拒绝特效
        ShowRejectionEffect(TargetID);
        
        // 重置选择状态
        bIsSelectingTarget = false;
    }
};

2. UI 系统集成

目标选择UI控制器

cpp 复制代码
// UI控制器绑定委托
void UTargetSelectionWidget::BindToSkillComponent(USkillComponent* SkillComponent)
{
    if (SkillComponent)
    {
        SkillComponent->OnTargetRejected.AddUObject(
            this, 
            &UTargetSelectionWidget::OnTargetRejected
        );
    }
}

void UTargetSelectionWidget::OnTargetRejected(int32 TargetID)
{
    // 显示红色拒绝提示
    ShowRejectionMessage(FText::FromString("Invalid target!"));
    
    // 抖动目标图标
    ShakeTargetIcon(TargetID);
    
    // 更新UI状态,允许重新选择
    SetSelectionState(ETargetSelectionState::CanReselect);
}

3. AI 命令系统

AI命令执行器

cpp 复制代码
// AI命令组件
UCLASS()
class UAICommandComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    FTargetingRejectedConfirmation OnCommandTargetRejected;

    void ExecuteAttackCommand(int32 TargetEnemyID)
    {
        AAIController* AIController = GetAIController();
        if (!AIController || !IsEnemyValid(TargetEnemyID))
        {
            // 目标无效,通知AI系统
            OnCommandTargetRejected.Broadcast(TargetEnemyID);
            AIController->HandleCommandFailure();
            return;
        }
        
        // 执行攻击命令
        AIController->IssueAttackCommand(TargetEnemyID);
    }
};

// AI行为树服务中绑定
UBTTService_ExecuteCommand::UBTTService_ExecuteCommand()
{
    CommandComponent = nullptr;
}

void UBTTService_ExecuteCommand::OnBecomeRelevant(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
    Super::OnBecomeRelevant(OwnerComp, NodeMemory);
    
    AAIController* AIController = OwnerComp.GetAIOwner();
    if (AIController)
    {
        CommandComponent = AIController->FindComponentByClass<UAICommandComponent>();
        if (CommandComponent)
        {
            CommandComponent->OnCommandTargetRejected.AddUObject(
                this,
                &UBTTService_ExecuteCommand::OnCommandRejected
            );
        }
    }
}

void UBTTService_ExecuteCommand::OnCommandRejected(int32 TargetID)
{
    // AI命令失败,切换到其他行为
    UE_LOG(LogAI, Warning, TEXT("Attack command rejected for target %d"), TargetID);
    
    // 可以触发寻找新目标、撤退等行为
    FindAlternativeTarget();
}

4. 网络同步游戏

多人游戏中的目标验证

cpp 复制代码
// 网络游戏中的技能系统
void UMultiplayerSkillSystem::Server_ConfirmTarget_Implementation(
    APlayerController* PlayerController, 
    int32 SkillID, 
    int32 TargetID)
{
    if (!ValidateTarget(PlayerController, TargetID))
    {
        // 服务器端验证失败
        OnTargetRejected.Broadcast(TargetID);
        
        // 通知客户端目标无效
        Client_TargetRejected(PlayerController, TargetID);
        return;
    }
    
    // 执行有效的技能
    ExecuteSkillOnServer(SkillID, TargetID);
}

void UMultiplayerSkillSystem::Client_TargetRejected_Implementation(
    APlayerController* PlayerController, 
    int32 TargetID)
{
    // 客户端收到拒绝通知
    OnTargetRejected.Broadcast(TargetID);
    
    // 本地处理拒绝效果
    PlayLocalRejectionEffects(TargetID);
}

5. 任务/任务系统

任务目标选择

cpp 复制代码
// 任务系统
UCLASS()
class UQuestSystem : public UGameInstanceSubsystem
{
    GENERATED_BODY()

public:
    FTargetingRejectedConfirmation OnQuestTargetRejected;

    void SelectQuestTarget(int32 QuestID, int32 TargetNPCID)
    {
        APlayerController* PlayerController = GetPlayerController();
        if (!CanInteractWithQuestTarget(PlayerController, QuestID, TargetNPCID))
        {
            // 任务目标选择被拒绝
            OnQuestTargetRejected.Broadcast(TargetNPCID);
            
            // 显示拒绝原因
            ShowQuestRejectionMessage(QuestID, TargetNPCID);
            return;
        }
        
        StartQuestDialogue(QuestID, TargetNPCID);
    }
};

// 任务UI绑定
void UQuestJournalWidget::BindToQuestSystem(UQuestSystem* QuestSystem)
{
    QuestSystem->OnQuestTargetRejected.AddUObject(
        this,
        &UQuestJournalWidget::OnQuestTargetRejected
    );
}

void UQuestJournalWidget::OnQuestTargetRejected(int32 TargetNPCID)
{
    // 更新任务UI状态
    UpdateQuestObjectives();
    
    // 显示提示信息
    ShowHintMessage("You cannot interact with this NPC yet. Complete prerequisites first.");
}

6. 调试和数据分析

目标拒绝统计

cpp 复制代码
// 数据分析组件
UCLASS()
class UAnalyticsComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    void BindToTargetingSystems()
    {
        // 绑定到各种目标选择系统
        SkillComponent->OnTargetRejected.AddUObject(
            this, 
            &UAnalyticsComponent::OnTargetRejected
        );
        
        QuestSystem->OnQuestTargetRejected.AddUObject(
            this, 
            &UAnalyticsComponent::OnTargetRejected
        );
    }

private:
    void OnTargetRejected(int32 TargetID)
    {
        // 记录分析数据
        FTargetRejectionData RejectionData;
        RejectionData.TargetID = TargetID;
        RejectionData.Timestamp = FDateTime::Now();
        RejectionData.PlayerID = GetPlayerID();
        
        AnalyticsProvider->RecordTargetRejection(RejectionData);
        
        UE_LOG(LogAnalytics, Verbose, TEXT("Target %d rejected by player"), TargetID);
    }
};

实际项目中的最佳实践

  1. 清晰的错误分类:根据不同的拒绝原因使用不同的处理逻辑

  2. 用户体验优化:提供明确的视觉/音频反馈

  3. 性能考虑:避免在委托处理中进行昂贵的操作

  4. 内存管理:确保在对象销毁时正确解除绑定

  5. 网络同步:在多人游戏中确保客户端和服务器的状态同步

这种委托模式在实际项目中极大地提高了代码的模块化和可维护性,使得各个系统能够独立开发而又能高效协作。

相关推荐
..过云雨3 小时前
13.【Linux系统编程】从ELF格式深入理解动静态库
linux·c语言·c++·后端
长沙红胖子Qt3 小时前
QGIS开发笔记(五):qgis加载标记点功能,基础标记数量与性能对比测试
c++
星星20253 小时前
电子电气架构全解析
笔记
AI研一研3 小时前
如何快速学习知识、查找要点、把知识读“薄”、读“精”?
人工智能·学习
Bear on Toilet3 小时前
C++_Bug:现代写法拷贝构造中 swap 写法之小坑
数据结构·c++·bug
智者知已应修善业3 小时前
【给定英文字符串统计最多小写最前输出】2023-2-27
c语言·开发语言·c++·经验分享·笔记·算法
我的golang之路果然有问题4 小时前
mac配置 unity+vscode的坑
开发语言·笔记·vscode·macos·unity·游戏引擎
铅笔小新z4 小时前
【C++】从理论到实践:类和对象完全指南(上)
开发语言·c++
go_bai4 小时前
Linux-线程
linux·开发语言·c++·经验分享·笔记