虛幻四Gameplay Ability System入門(mén)(1)

虛幻四Gameplay Ability System入門(mén)(2)

我最近在學(xué)習(xí)虛幻四的Gameplay Ability System,這個(gè)名字可以被理解為技能系統(tǒng)框架(大概)扇救,接下來(lái)我就簡(jiǎn)稱(chēng)為GAS或技能系統(tǒng)吴菠。在網(wǎng)上找了很久杰刽,發(fā)現(xiàn)相關(guān)的中文教程比較少十拣,所以打算把自己的學(xué)習(xí)過(guò)程和對(duì)技能系統(tǒng)的理解寫(xiě)成文章祭饭,既幫助我理解图毕,也希望可以幫助到其它想要學(xué)習(xí)GAS的朋友惫皱。之前寫(xiě)過(guò)一篇教程像樊,但感覺(jué)很不滿意,于是打算重寫(xiě)一遍旅敷。接下來(lái)進(jìn)入正題生棍。

什么是Gameplay Ability System?

在很多的游戲中,角色會(huì)擁有很多的技能媳谁,比如火球術(shù)涂滴,治療術(shù)等等友酱。這些技能會(huì)消耗法力值,存在冷卻時(shí)間柔纵,可以造成傷害缔杉。同時(shí)一個(gè)角色可以擁有多個(gè)技能,技能之間也會(huì)相互關(guān)聯(lián)搁料,比如火球術(shù)無(wú)法對(duì)使用冰霜護(hù)盾的敵人造成傷害或详。

實(shí)現(xiàn)以上的種種效果需要一個(gè)較為復(fù)雜的框架,而虛幻四的GAS系統(tǒng)就為我們提供了一個(gè)管理技能的系統(tǒng)郭计,可以很方便的實(shí)現(xiàn)技能需要霸琴,但GAS目前離不開(kāi)C++,而且官方目前還沒(méi)有提供方便入門(mén)的教程與文檔拣宏,因此學(xué)習(xí)起來(lái)還是比較痛苦的沈贝,以下是我認(rèn)為比較好的入門(mén)教程:

Bilibili

UE4官方的視頻教程,中文

https://www.bilibili.com/video/BV1X5411V7jh

Youtube

有條件的可以翻墻去看

UE4官方視頻教程勋乾,英文,相較于中文的視頻嗡善,我認(rèn)為這個(gè)教程講解的更深入一點(diǎn)辑莫。

https://www.youtube.com/watch?v=YvXvWa6vbAA

Github

這一篇是我認(rèn)為最好的文檔了,包含一個(gè)項(xiàng)目和較為完整的說(shuō)明罩引,但仍然較為復(fù)雜各吨,建議看完上面兩個(gè)視頻對(duì)GAS有了一定了解再看。

https://github.com/tranek/GASDocumentation

GAS系統(tǒng)的基本構(gòu)成

  1. Ability System Component袁铐,GAS系統(tǒng)的大腦揭蜒,擁有Abilities(技能)和Attributes(屬性),可以把它理解為技能系統(tǒng)的中樞剔桨。
  2. Ability屉更,技能∪髯海可以把它理解為某項(xiàng)能力瑰谜,比如火球術(shù),跳躍等等树绩,它應(yīng)該包含較為完整的邏輯萨脑,可以添加給角色的技能系統(tǒng),也可以從技能系統(tǒng)中移除饺饭。
  3. Attribute和AttibuteSet渤早,屬性和屬性集。Attribute代表了角色的某種屬性瘫俊,比如Health鹊杖,Mana等等悴灵。
  4. Tags,層次化的標(biāo)簽仅淑。它代表了某種狀態(tài)或者屬性称勋。比如角色處于燃燒狀態(tài),那么這個(gè)狀態(tài)的標(biāo)簽就為Character.State.Burning涯竟,我們可以自定義狀態(tài)并在技能和效果中設(shè)置tag之間的關(guān)系赡鲜,比如角色處于燃燒標(biāo)簽時(shí)會(huì)受到傷害,但如果被帶有Water標(biāo)簽的效果影響庐船,就可以移除燃燒標(biāo)簽银酬。我認(rèn)為T(mén)ag應(yīng)該是技能系統(tǒng)的核心和魅力所在了。
  5. Gameplay Effect(GE)筐钟,技能效果揩瞪,它本身只是一個(gè)數(shù)據(jù)集,代表了對(duì)某些Attribute和Tag的修改篓冲。比如GE_Damage中應(yīng)該設(shè)置為對(duì)Attribute:Health修改Add -20李破,表示為傷害效果為扣血20點(diǎn)。它還可以添加修改Tag壹将,或者被Tag所影響嗤攻,和第四點(diǎn)的例子一樣,火焰的傷害效果本質(zhì)是一個(gè)GE诽俯,如果另外有一個(gè)帶有Water標(biāo)簽的GE作用于角色妇菱,那么它會(huì)移除燃燒效果GE。理論上GAS中對(duì)于Tag和Attribute的修改盡可能都要使用GE
  6. Ability Task暴区,表示為Ability中的一個(gè)任務(wù)闯团。比如接下來(lái)幾乎每一個(gè)技能都會(huì)用到的一個(gè)Task是PlayMontageAndWait,可以看到它創(chuàng)建并返回了一個(gè)Async Task.
1.png
  1. Gameplay cue仙粱,GC執(zhí)行的是非游戲邏輯的效果比如聲音特效房交,粒子特效,攝像機(jī)抖動(dòng)等等缰盏,GC通過(guò)關(guān)聯(lián)的Tag觸發(fā)涌萤,還是舉角色燃燒的粒子,當(dāng)角色身上有Burning的標(biāo)簽時(shí)口猜,就可以設(shè)置Gameplay Cue Tag, 然后就會(huì)觸發(fā)GC_Burning负溪,讓角色身上有一個(gè)燃燒的粒子特效。

下圖是我對(duì)GAS各個(gè)組件關(guān)系之間的簡(jiǎn)單理解济炎,并不完整且正確川抡,只是幫助大致理解各個(gè)組件之間的關(guān)系。

2.png

GAS基礎(chǔ)設(shè)置

這一部分涉及到虛幻四C++和藍(lán)圖的知識(shí),需要擁有一定的基礎(chǔ)崖堤。

首先打開(kāi)虛幻四侍咱,創(chuàng)建一個(gè)C++的空白項(xiàng)目,如果覺(jué)得配置麻煩也可以創(chuàng)建一個(gè)第三人稱(chēng)項(xiàng)目密幔。

這里我直接使用了epic商城中的素材楔脯,將素材直接添加到工程

3.png

1.角色基礎(chǔ)配置

因?yàn)檫@篇文章不是介紹虛幻四C++入門(mén)的,因此我就不具體介紹角色基礎(chǔ)配置的說(shuō)明了胯甩。

首先新建Character C++類(lèi)昧廷,命名為CharacterBase

4.png

在Project Setting中的Input添加Axis Mappings

5.png

打開(kāi)CharacterBase.h和Character.cpp

添加Camera和SprintArm,函數(shù)MoveForward和MoveRight

GENERATED_BODY()
    
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Camera", meta=(AllowPrivateAccess = "true"))
    class USpringArmComponent* CameraBoom;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Camera", meta=(AllowPrivateAccess = "true"))
    class UCameraComponent* FollowCamera;

protected:
   // Character Movement
   void MoveForward(float Value);

   void MoveRight(float Value);

cpp實(shí)現(xiàn)

// Sets default values
ACharacterTesting::ACharacterTesting()
{
   // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
   PrimaryActorTick.bCanEverTick = true;

   bUseControllerRotationPitch = false;
   bUseControllerRotationRoll = false;
   bUseControllerRotationYaw = false;

   GetCharacterMovement()->bOrientRotationToMovement = true;

   CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("Camera Boom"));
   CameraBoom->SetupAttachment(RootComponent);
   CameraBoom->TargetArmLength = 300.0f;
   CameraBoom->bUsePawnControlRotation = true;

   FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("Follow Camera"));
   FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
   FollowCamera->bUsePawnControlRotation = false;
}

// Called to bind functionality to input
void ACharacterTesting::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    PlayerInputComponent->BindAxis("MoveForward", this, &ACharacterTesting::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &ACharacterTesting::MoveRight);

    PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
    PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
}

void ACharacterTesting::MoveForward(float Value)
{
    if((Controller != nullptr) && (Value != 0.0f))
    {
        const FRotator Rotation = Controller->GetControlRotation();
        const FRotator YawRotation(0, Rotation.Yaw, 0);

        const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
        AddMovementInput(Direction, Value);
    }
}

void ACharacterTesting::MoveRight(float Value)
{
    if((Controller != nullptr) && (Value != 0.0f))
    {
        const FRotator Rotation = Controller->GetControlRotation();
        const FRotator YawRotation(0, Rotation.Yaw, 0);

        const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
        AddMovementInput(Direction, Value);
    }
}

在UE4 Editor中創(chuàng)建CharacterBase子類(lèi)BP_Character偎箫,給角色選擇mesh

6.png

創(chuàng)建AnimBlueprint,命名為AnimBP_Character,設(shè)置角色相應(yīng)的動(dòng)畫(huà)木柬。

7.png

這里只需要locomotion就夠了,把locomotion連接到output pose上即可

8.png
9.png
10.png

角色基本設(shè)置完成淹办。

2.GAS系統(tǒng)基礎(chǔ)配置

  1. 使用GAS系統(tǒng)首先需要在Plugins中Enable插件Gameplay Abilities
11.png

然后在ProjectName.Build.cs中眉枕,添加三個(gè)依賴(lài),分別是GameplayAbilities, GameplayTasks, GameplayTags

PrivateDependencyModuleNames.AddRange(new string[] { "GameplayAbilities", "GameplayTags", "GameplayTasks" });

然后Build Solution

2. 添加ASC

打開(kāi)CharacterBase.h

創(chuàng)建Ability System Component怜森,這里需要繼承一個(gè)接口速挑,然后實(shí)現(xiàn)接口中的純虛函數(shù)GetAbilitySystemComponent(),它的作用是返回AbilitySystem副硅,這個(gè)函數(shù)的作用是在不知道當(dāng)前角色是否具有AbilitySystem的時(shí)候時(shí)梗摇,我們就可以調(diào)用這個(gè)函數(shù),而不需要使用Cast_To

UCLASS()
class GAS__API ACharacterBase : public ACharacter, public IAbilitySystemInterface
{
    //.......
public:
    // ......
    // Ability System Component
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="CharacterBase")
    UAbilitySystemComponent* AbilitySystem;

    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const;
}

GetAbilitySystemComponent()實(shí)現(xiàn)

ACharacterBase::ACharacterBase()
{
    //......
    AbilitySystem = CreateDefaultSubobject<UAbilitySystemComponent>("AbilitySystem");
}

// override AbilityInterface virtual function
UAbilitySystemComponent* ACharacterBase::GetAbilitySystemComponent() const
{
   return AbilitySystem;
}

這樣子Character就擁有了Ability System Component了想许。

3.接下來(lái)實(shí)現(xiàn)一個(gè)方法可以給ASC添加Ability,這個(gè)功能可以在BP中調(diào)用断序。

// Add Ability to Character
    UFUNCTION(BlueprintCallable, Category="Ability System")
    void GiveAbility(TSubclassOf<UGameplayAbility> Ability);

實(shí)現(xiàn)

void ACharacterBase::GiveAbility(TSubclassOf<UGameplayAbility> Ability)
{
    if(AbilitySystem)
    {
        if(HasAuthority() && Ability)
        {
            AbilitySystem->GiveAbility(FGameplayAbilitySpec(Ability, 1));
        }
        AbilitySystem->InitAbilityActorInfo(this, this);
    }
}

藍(lán)圖中調(diào)用的例子

12.png

4.創(chuàng)建和實(shí)現(xiàn)基礎(chǔ)的AttributeSet

在第一步我們實(shí)際上還用不到Attribute流纹,但方便起見(jiàn)還是先創(chuàng)建一下。命名為AttributeSetBase

13.png

打開(kāi)违诗。這里我只展現(xiàn)了創(chuàng)建Attribute:Health和MaxHealth的方法漱凝。

最前面的define是一種mecro方法,它在AttributeSet中實(shí)現(xiàn)诸迟,它可以自動(dòng)地幫你實(shí)現(xiàn)Attribute的getter, setter等方法茸炒。

attribute需要一個(gè)ReplicatedUsing方法。

   #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
   GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
   GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
   GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
   GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/**
 *
 */
UCLASS()
class GAS__API UAttributeSetBase : public UAttributeSet
{
   GENERATED_BODY()

public:
   UAttributeSetBase();

   virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

   // Health and MaxHealth
   UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Abilities", ReplicatedUsing=OnRep_Health)
   FGameplayAttributeData Health;
   ATTRIBUTE_ACCESSORS(UAttributeSetBase, Health);

   UFUNCTION()
   virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);

   UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Abilities", ReplicatedUsing=OnRep_MaxHealth)
   FGameplayAttributeData MaxHealth;
   ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxHealth);

   UFUNCTION()
   virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
};
void UAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
   Super::GetLifetimeReplicatedProps(OutLifetimeProps);

   DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Health, COND_None, REPNOTIFY_Always);
   DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always);
}

void UAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
   GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, Health, OldHealth);
}

void UAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth)
{
   GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxHealth);
}

最后一步是把AttributeSet添加給角色阵苇。

UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Abilities")
    UAttributeSetBase* AttributeSet;
AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("Attribute Set");

OK壁公,到這一步角色的基礎(chǔ)GAS配置就完成了

5.測(cè)試

創(chuàng)建一個(gè)GameplayAbility類(lèi)的藍(lán)圖,命名為BP_Test

14.png

打開(kāi)后绅项,這里完成的是啟動(dòng)ability紊册,打印一個(gè)hello在屏幕上,然后結(jié)束Ability

15.png

然后打開(kāi)角色的藍(lán)圖快耿,在beginplay中調(diào)用GiveAbility函數(shù)

16.png

點(diǎn)擊鼠標(biāo)左鍵囊陡,啟用ability芳绩。

17.png

運(yùn)行游戲,點(diǎn)擊鼠標(biāo)左鍵應(yīng)該就可以看到Hello了撞反。

18.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妥色,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子遏片,更是在濱河造成了極大的恐慌嘹害,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丁稀,死亡現(xiàn)場(chǎng)離奇詭異吼拥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)线衫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)凿可,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人授账,你說(shuō)我怎么就攤上這事枯跑。” “怎么了白热?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵敛助,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我屋确,道長(zhǎng)纳击,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任攻臀,我火速辦了婚禮焕数,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刨啸。我一直安慰自己堡赔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布设联。 她就那樣靜靜地躺著善已,像睡著了一般。 火紅的嫁衣襯著肌膚如雪离例。 梳的紋絲不亂的頭發(fā)上换团,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音粘招,去河邊找鬼啥寇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辑甜。 我是一名探鬼主播衰絮,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼磷醋!你這毒婦竟也來(lái)了猫牡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤邓线,失蹤者是張志新(化名)和其女友劉穎淌友,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體骇陈,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡震庭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了你雌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片器联。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖婿崭,靈堂內(nèi)的尸體忽然破棺而出拨拓,到底是詐尸還是另有隱情,我是刑警寧澤氓栈,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布渣磷,位于F島的核電站,受9級(jí)特大地震影響授瘦,放射性物質(zhì)發(fā)生泄漏醋界。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一提完、第九天 我趴在偏房一處隱蔽的房頂上張望物独。 院中可真熱鬧,春花似錦氯葬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至秽澳,卻和暖如春闯睹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背担神。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工楼吃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓孩锡,卻偏偏與公主長(zhǎng)得像酷宵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子躬窜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容