美文网首页
十五、RPGCharacterBase (GAS related

十五、RPGCharacterBase (GAS related

作者: 珏_Gray | 来源:发表于2019-06-20 10:18 被阅读0次

    RPGCharacter主要负责Gameplay Ability System部分。直接上代码:

    头文件:

    // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
    
    #pragma once
    
    #include "ActionRPG.h"
    #include "GameFramework/Character.h"
    #include "UObject/ScriptInterface.h"
    #include "RPGInventoryInterface.h"
    #include "AbilitySystemInterface.h"
    #include "Abilities/RPGAbilitySystemComponent.h"
    #include "Abilities/RPGAttributeSet.h"
    #include "RPGCharacterBase.generated.h"
    
    class URPGGameplayAbility;
    class UGameplayEffect;
    
    
    
    /** Base class for Character, Designed to be blueprinted */
    UCLASS()
    class ACTIONRPG_API ARPGCharacterBase : public ACharacter, public IAbilitySystemInterface
    {
        GENERATED_BODY()
    
    public:
        // Constructor and overrides
        ARPGCharacterBase();
    
    /**   Controller    -------------------------------------------------------------------------------------------------- */
    //角色被controller possess时调用:绑定背包的delegate,更新ability system component信息
        virtual void PossessedBy(AController* NewController) override;
        virtual void UnPossessed() override;
        virtual void OnRep_Controller() override;
    /**   -------------------------------------------------------------------------------------------------- */
        
    // replicate property
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
    
        // Implement IAbilitySystemInterface
        UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
    #pragma region Attributes Getter ( 属性getter方法 )
        /** Returns current health, will be 0 if dead */
        UFUNCTION(BlueprintCallable)
        float GetHealth() const;
    
        /** Returns maximum health, health will never be greater than this */
        UFUNCTION(BlueprintCallable)
        float GetMaxHealth() const;
    
        /** Returns current mana */
        UFUNCTION(BlueprintPure)
        float GetMana() const;
    
        /** Returns maximum mana, mana will never be greater than this */
        UFUNCTION(BlueprintCallable)
        float GetMaxMana() const;
    
        /** Returns current movement speed */
        UFUNCTION(BlueprintCallable)
        float GetMoveSpeed() const;
    #pragma endregion
    
        /** Returns the character level that is passed to the ability system */
        UFUNCTION(BlueprintCallable)
        int32 GetCharacterLevel() const;
    
        /** Modifies the character level, this may change abilities. Returns true on success */
        UFUNCTION(BlueprintCallable)
        bool SetCharacterLevel(int32 NewLevel);
    
        /**
         * Attempts to activate any ability in the specified item slot. Will return false if no activatable ability found or activation fails
         * Returns true if it thinks it activated, but it may return false positives due to failure later in activation.
         * If bAllowRemoteActivation is true, it will remotely activate local/server abilities, if false it will only try to locally activate the ability
         */
     // 尝试激活item  slot里对应道具的ability
        UFUNCTION(BlueprintCallable, Category = "Abilities")
        bool ActivateAbilitiesWithItemSlot(FRPGItemSlot ItemSlot, bool bAllowRemoteActivation = true);
    
        /** Returns a list of active abilities bound to the item slot. This only returns if the ability is currently running */
    //返回特定slot中正在生效中的ability list
        UFUNCTION(BlueprintCallable, Category = "Abilities")
        void GetActiveAbilitiesWithItemSlot(FRPGItemSlot ItemSlot, TArray<URPGGameplayAbility*>& ActiveAbilities);
    
        /**
         * Attempts to activate all abilities that match the specified tags
         * Returns true if it thinks it activated, but it may return false positives due to failure later in activation.
         * If bAllowRemoteActivation is true, it will remotely activate local/server abilities, if false it will only try to locally activate the ability
         */
    // 通过tag来激活activity
        UFUNCTION(BlueprintCallable, Category = "Abilities")
        bool ActivateAbilitiesWithTags(FGameplayTagContainer AbilityTags, bool bAllowRemoteActivation = true);
    
        /** Returns a list of active abilities matching the specified tags. This only returns if the ability is currently running */
        UFUNCTION(BlueprintCallable, Category = "Abilities")
        void GetActiveAbilitiesWithTags(FGameplayTagContainer AbilityTags, TArray<URPGGameplayAbility*>& ActiveAbilities);
    
        /** Returns total time and remaining time for cooldown tags. Returns false if no active cooldowns found */
        UFUNCTION(BlueprintCallable, Category = "Abilities")
        bool GetCooldownRemainingForTag(FGameplayTagContainer CooldownTags, float& TimeRemaining, float& CooldownDuration);
    
    protected:
        /** The level of this character, should not be modified directly once it has already spawned */
        UPROPERTY(EditAnywhere, Replicated, Category = "Abilities")
        int32 CharacterLevel;
    
        /** Abilities to grant to this character on creation. These will be activated by tag or event and are not bound to specific inputs */
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Abilities")
        TArray<TSubclassOf<URPGGameplayAbility>> GameplayAbilities;
    
        /** Map of item slot to gameplay ability class, these are bound before any abilities added by the inventory */
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Abilities")
        TMap<FRPGItemSlot, TSubclassOf<URPGGameplayAbility>> DefaultSlottedAbilities;
    
        /** Passive gameplay effects applied on creation */
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Abilities")
        TArray<TSubclassOf<UGameplayEffect>> PassiveGameplayEffects;
    
        /** The component used to handle ability system interactions */
        UPROPERTY()
        URPGAbilitySystemComponent* AbilitySystemComponent;
    
        /** List of attributes modified by the ability system */
        UPROPERTY()
        URPGAttributeSet* AttributeSet;
    
        /** Cached pointer to the inventory source for this character, can be null */
        UPROPERTY()
        TScriptInterface<IRPGInventoryInterface> InventorySource;
    
        /** If true we have initialized our abilities */
        UPROPERTY()
        int32 bAbilitiesInitialized;
    
        /** Map of slot to ability granted by that slot. I may refactor this later */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Inventory)
        TMap<FRPGItemSlot, FGameplayAbilitySpecHandle> SlottedAbilities;
    
        /** Delegate handles */
        FDelegateHandle InventoryUpdateHandle;
        FDelegateHandle InventoryLoadedHandle;
    
        /**
         * Called when character takes damage, which may have killed them
         *
         * @param DamageAmount Amount of damage that was done, not clamped based on current health
         * @param HitInfo The hit info that generated this damage
         * @param DamageTags The gameplay tags of the event that did the damage
         * @param InstigatorCharacter The character that initiated this damage
         * @param DamageCauser The actual actor that did the damage, might be a weapon or projectile
         */
        UFUNCTION(BlueprintImplementableEvent)
        void OnDamaged(float DamageAmount, const FHitResult& HitInfo, const struct FGameplayTagContainer& DamageTags, ARPGCharacterBase* InstigatorCharacter, AActor* DamageCauser);
    
        /**
         * Called when health is changed, either from healing or from being damaged
         * For damage this is called in addition to OnDamaged/OnKilled
         *
         * @param DeltaValue Change in health value, positive for heal, negative for cost. If 0 the delta is unknown
         * @param EventTags The gameplay tags of the event that changed mana
         */
        UFUNCTION(BlueprintImplementableEvent)
        void OnHealthChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
    
        /**
         * Called when mana is changed, either from healing or from being used as a cost
         *
         * @param DeltaValue Change in mana value, positive for heal, negative for cost. If 0 the delta is unknown
         * @param EventTags The gameplay tags of the event that changed mana
         */
        UFUNCTION(BlueprintImplementableEvent)
        void OnManaChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
    
        /**
         * Called when movement speed is changed
         *
         * @param DeltaValue Change in move speed
         * @param EventTags The gameplay tags of the event that changed mana
         */
        UFUNCTION(BlueprintImplementableEvent)
        void OnMoveSpeedChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
    
        /** Called when slotted items change, bound to delegate on interface */
        void OnItemSlotChanged(FRPGItemSlot ItemSlot, URPGItem* Item);
        void RefreshSlottedGameplayAbilities();
    
        /** Apply the startup gameplay abilities and effects */
        void AddStartupGameplayAbilities();
    
        /** Attempts to remove any startup gameplay abilities */
        void RemoveStartupGameplayAbilities();
    
        /** Adds slotted item abilities if needed */
        void AddSlottedGameplayAbilities();
    
        /** Fills in with ability specs, based on defaults and inventory */
        void FillSlottedAbilitySpecs(TMap<FRPGItemSlot, FGameplayAbilitySpec>& SlottedAbilitySpecs);
    
        /** Remove slotted gameplay abilities, if force is false it only removes invalid ones */
        void RemoveSlottedGameplayAbilities(bool bRemoveAll);
    
        // Called from RPGAttributeSet, these call BP events above
        virtual void HandleDamage(float DamageAmount, const FHitResult& HitInfo, const struct FGameplayTagContainer& DamageTags, ARPGCharacterBase* InstigatorCharacter, AActor* DamageCauser);
        virtual void HandleHealthChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
        virtual void HandleManaChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
        virtual void HandleMoveSpeedChanged(float DeltaValue, const struct FGameplayTagContainer& EventTags);
    
        // Friended to allow access to handle functions above
          // 上面所有的Handle XXX函数,都会在URPGAttributeSet中被调用
        friend URPGAttributeSet;
    };
    
    

    头文件的public方法表明,我们可以通过item slotgameplay tag来activate ability。
    character具有初始的ability list,并且负责所有属性变化的回调。


    源文件:

    只摘取部分讲解:

    构造函数

    注意在此处创建AbilitySystemComponentAttributeSet作为Character的SubObject。

    ARPGCharacterBase::ARPGCharacterBase()
    {
        // Create ability system component, and set it to be explicitly replicated
        AbilitySystemComponent = CreateDefaultSubobject<URPGAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
        AbilitySystemComponent->SetIsReplicated(true);
        
        // Create the attribute set, this replicates by default
        AttributeSet = CreateDefaultSubobject<URPGAttributeSet>(TEXT("AttributeSet"));
        
        CharacterLevel = 1;
        bAbilitiesInitialized = false;
    }
    
    实现GetAbilitySystemComponent()接口
    UAbilitySystemComponent* ARPGCharacterBase::GetAbilitySystemComponent() const
    {
        return AbilitySystemComponent;
    }
    
    初始阶段:赋予Ability、触发被动effect
    void ARPGCharacterBase::AddStartupGameplayAbilities()
    {
        check(AbilitySystemComponent);
        
    // 确认是否在服务端
        if (Role == ROLE_Authority && !bAbilitiesInitialized)
        {
            // Grant abilities, but only on the server  
            for (TSubclassOf<URPGGameplayAbility>& StartupAbility : GameplayAbilities)
            {
    //赋予技能(技能是必须被赋予后才能激活的)
                AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(StartupAbility, GetCharacterLevel(), INDEX_NONE, this));
            }
    
            // Now apply passives
            for (TSubclassOf<UGameplayEffect>& GameplayEffect : PassiveGameplayEffects)
            {
    // 创建effect context ,即effect的施放者,施放者位置等等其他的数据
                FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
                EffectContext.AddSourceObject(this);
    //生成gameplay effect spec供应用
                FGameplayEffectSpecHandle NewHandle = AbilitySystemComponent->MakeOutgoingSpec(GameplayEffect, GetCharacterLevel(), EffectContext);
                if (NewHandle.IsValid())
                {
    //正式的激活效果
                    FActiveGameplayEffectHandle ActiveGEHandle = AbilitySystemComponent->ApplyGameplayEffectSpecToTarget(*NewHandle.Data.Get(), AbilitySystemComponent);
                }
            }
    
            AddSlottedGameplayAbilities();
    
            bAbilitiesInitialized = true;
        }
    }
    
    激活item slot里的技能
    bool ARPGCharacterBase::ActivateAbilitiesWithItemSlot(FRPGItemSlot ItemSlot, bool bAllowRemoteActivation)
    {
        FGameplayAbilitySpecHandle* FoundHandle = SlottedAbilities.Find(ItemSlot);
    
        if (FoundHandle && AbilitySystemComponent)
        {
            return AbilitySystemComponent->TryActivateAbility(*FoundHandle, bAllowRemoteActivation);
        }
    
        return false;
    }
    
    通过tag来激活技能
    bool ARPGCharacterBase::ActivateAbilitiesWithTags(FGameplayTagContainer AbilityTags, bool bAllowRemoteActivation)
    {
        if (AbilitySystemComponent)
        {
            return AbilitySystemComponent->TryActivateAbilitiesByTag(AbilityTags, bAllowRemoteActivation);
        }
    
        return false;
    }
    

    还有几个ability system component的函数值得注意:

    • 使用effect query来获取效果的持续时间
    FGameplayEffectQuery const Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(CooldownTags);
            TArray< TPair<float, float> > DurationAndTimeRemaining = AbilitySystemComponent->GetActiveEffectsTimeRemainingAndDuration(Query);
    
    • 利用handle返回ability spec
    FGameplayAbilitySpec* FoundSpec = AbilitySystemComponent->FindAbilitySpecFromHandle(*FoundHandle);
    

    相关文章

      网友评论

          本文标题:十五、RPGCharacterBase (GAS related

          本文链接:https://www.haomeiwen.com/subject/pporqctx.html