十五捧弃、RPGCharacterBase (GAS related)

RPGCharacter主要負責(zé)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時調(diào)用:綁定背包的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里對應(yīng)道具的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函數(shù),都會在URPGAttributeSet中被調(diào)用
    friend URPGAttributeSet;
};

頭文件的public方法表明梅割,我們可以通過item slotgameplay tag來activate ability霜第。
character具有初始的ability list,并且負責(zé)所有屬性變化的回調(diào)户辞。


源文件:

只摘取部分講解:

構(gòu)造函數(shù)

注意在此處創(chuàng)建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;
}
實現(xiàn)GetAbilitySystemComponent()接口
UAbilitySystemComponent* ARPGCharacterBase::GetAbilitySystemComponent() const
{
    return AbilitySystemComponent;
}
初始階段:賦予Ability癞谒、觸發(fā)被動effect
void ARPGCharacterBase::AddStartupGameplayAbilities()
{
    check(AbilitySystemComponent);
    
// 確認是否在服務(wù)端
    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)
        {
// 創(chuàng)建effect context 底燎,即effect的施放者,施放者位置等等其他的數(shù)據(jù)
            FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
            EffectContext.AddSourceObject(this);
//生成gameplay effect spec供應(yīng)用
            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的函數(shù)值得注意:

  • 使用effect query來獲取效果的持續(xù)時間
FGameplayEffectQuery const Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(CooldownTags);
        TArray< TPair<float, float> > DurationAndTimeRemaining = AbilitySystemComponent->GetActiveEffectsTimeRemainingAndDuration(Query);
  • 利用handle返回ability spec
FGameplayAbilitySpec* FoundSpec = AbilitySystemComponent->FindAbilitySpecFromHandle(*FoundHandle);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弹砚,一起剝皮案震驚了整個濱河市双仍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桌吃,老刑警劉巖朱沃,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茅诱,居然都是意外死亡逗物,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門瑟俭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翎卓,“玉大人,你說我怎么就攤上這事摆寄∈П” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵微饥,是天一觀的道長逗扒。 經(jīng)常有香客問我,道長欠橘,這世上最難降的妖魔是什么矩肩? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮简软,結(jié)果婚禮上蛮拔,老公的妹妹穿的比我還像新娘。我一直安慰自己痹升,他們只是感情好建炫,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疼蛾,像睡著了一般肛跌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天衍慎,我揣著相機與錄音转唉,去河邊找鬼。 笑死稳捆,一個胖子當(dāng)著我的面吹牛赠法,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乔夯,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼砖织,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了末荐?” 一聲冷哼從身側(cè)響起侧纯,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甲脏,沒想到半個月后眶熬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡块请,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年娜氏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片负乡。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡牍白,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抖棘,到底是詐尸還是另有隱情茂腥,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布切省,位于F島的核電站最岗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏朝捆。R本人自食惡果不足惜般渡,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芙盘。 院中可真熱鬧驯用,春花似錦、人聲如沸儒老。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驮樊。三九已至薇正,卻和暖如春片酝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挖腰。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工雕沿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人猴仑。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓审轮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宁脊。 傳聞我的和親對象是個殘疾皇子断国,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355