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

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

相关推荐
2601_961146203 分钟前
实验室用等离子表面处理设备处理新能源汽车塑料件的一点记录
笔记·汽车·设备
知产xiao_xin13 分钟前
专利主体及权利归属
经验分享·笔记·知识产权
学电子她就能回来吗22 分钟前
LeetCode Hot 100|普通数组专题学习笔记(零基础版)
笔记·算法·leetcode
2601_9653842624 分钟前
从微生态与流体力学视角看:“口水臭”的系统级成因与清洁边界
经验分享·笔记
卿卿的产品经理日记1 小时前
【AI产品经理实战】Day 38|try-except 踩坑实录:报错是数据
人工智能·笔记·python·学习·产品经理
keyipatience1 小时前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
衍玊2 小时前
多路转接原理与应用
c++
lazy H2 小时前
【计算机网络】第 2 篇:一条数据如何穿过网络?彻底理解数据封装与解封装
网络·经验分享·后端·学习·计算机网络
我命由我123453 小时前
软件工程概念 - 可插拔性
java·后端·学习·java-ee·系统架构·软件工程·学习方法
kkkkkkkkkk_Z4 小时前
新手自学嵌入式 | 学习日记:I2C总线协议、时序分析、读写流程与代码实现
学习