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. 网络同步:在多人游戏中确保客户端和服务器的状态同步

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

相关推荐
mykj15517 分钟前
英语单词APP解锁学习新方式,智能高效背单词
学习·英语单词app
知识分享小能手42 分钟前
深度学习学习教程,从入门到精通,深度学习中的正则化 — 完整知识点与代码示例(7)
人工智能·深度学习·学习
~kiss~2 小时前
Agent 的 未来吗?String: An Agentic OS Where Every App Is a Markdown File
学习
Tairitsu_H2 小时前
[C++] 深入理解红黑树:封装set与map
开发语言·c++·set·map·红黑树·模拟实现
HugoStudio_SWAN2 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
猎头南楼4 小时前
VLA 模型落地端侧:从架构选型到量化部署的工程实践笔记
笔记·架构·大模型
会周易的程序员4 小时前
5Draft(五帝)测试报告
服务器·c++·分布式·raft·共识算法·共识·算力服务器
Capricorn19884 小时前
日志级幻觉排障:GPT-6 Astra 迈入 AGI 时代,知芽 Notebook Skill 如何以引用校验与零命中诚实弃权解决长文失忆
论文阅读·人工智能·笔记·gpt·agi
UIU1144 小时前
scanf与cout的误区:探究其内部的机制
c++·学习·c#·scanf
闻缺陷则喜何志丹4 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统