参考资料:
学习大纲
插件应用
并在Build.cs中增加插件依赖:
1
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "GameplayAbilities", "GameplayTags", "GameplayTasks" });
基础
技能 AbilitySystemComponent (ASC)
以英雄联盟为例:
- Lv
- Gameplay Effect (GE)
- 消耗
- HP, MP, Strength
- 伤害
- 魔法,物理
- 消耗
- Gameplay Cue (Cue)
- 特效
- 声音
- Gameplay Task
- 效果(击飞等等)
- Gameplay Tag (Tag)
- 技能之间的相互影响(优先级打断)
属性 Gameplay Attribute (GA)
以英雄联盟为例:
- HP
- MP
- 冷却速度
- 移动速度
- …
项目配置
- 在Project Settings中关闭自动曝光(Auto Exposure)
- 创建BaseCharacter (C++), BP_BaseCharacter, BP_Player, BP_Enemy, BP_GameMode, BP_PlayerController
- 在BP_Player中新增SpringArm和Camera
基本角色与相机控制
角色控制
角色移动、转向、跳跃
将第一人称控制模式转换为第三人称控制:
-
BP_Player:取消勾选Use Controller Rotation Yaw
- SpringArm:勾选Use Pawn Control Rotation
- CharacterMovement:勾选Orient Rotation to Movement
相机锁定模式和夹角限制
在BP_Player中限制夹角
相机视角锁定与非锁定设置
平A与移动动画制作
动画制作:创建BlendSpace和AnimationBlueprint
BS_Walk
ABP_Sinbi
Event Graph:
Anim Graph:
创建状态机StateMachine
Idle/Jog:
JumpStart:
JumpLoop:
JumpEnd:
Idle/Jog to JumpStart
JumpStart to JumpLoop
JumpLoop to JumpEnd
JumpEnd to Idle/Jog
创建蒙太奇 Montage
MA_MeleeAttack
在BP_BaseEnemy中创建CustomEvent
再在PlayerController中调用这个Event
目前存在的问题:边走边平A的时候腿部不动,非常违和
解决方法:动作融合
动画融合
ABP_Sinbi
并在Layered Blend per bone设置:
但存在问题:效果像是在腰部被切断一样
解决方法:在前几帧将动画控制权交给未融合的Montage
在脚离地及落地的时候分别Add Notify,对应StartMontage和EndMontage
在ABP_Sinbi的Event Graph中增加是否需要Move蒙太奇的设置
在AnimGraph中实现是否需要Move蒙太奇的切换实现
创建一个平A及CD
添加AbilitySystemComponent和GameplayAbility基类
在BP_BaseCharacter上新增Ability System
这个Component
创建GAB_BaseAbility(父类是GameAbility)以及GAB_MeleeAttack(父类是GAB_BaseAbility),并给后者增加标签
GAS结合gameplay的做法
在BP_BaseCharacter中新增触发技能函数ActivateAbility,并在Gameplay Tag Container中配置所有的Tag
用触发技能函数实现MeleeAttack Event
在BP_BaseCharacter开始的时候执行GiveAbility
在GAB_MeleeAttack中实现蒙太奇的播放
注意:子类BP_Player的BeginPlay一定要继承父类的方法(即GiveAbility),否则动画无法正常生效
平A的CD设置
新增GE_MeleeCD(父类是GameEffect)并配置0.5s的CD时间
注意还需要在GAB_MeleeAttack中提交CD
平A碰撞检测
在BP_BaseCharacter的Mesh下新增胶囊体碰撞,并设置Parent Socket
为weapon_r,调整位置及大小
碰撞逻辑实现:
解决不在攻击时仍然判定伤害的bug:
增加StartATK和EndATK的Notify
改变BP_BaseCharacter的碰撞设置
角色属性
创建角色属性
创建BaseAttributeSet(C++,父类为AttributeSet)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "BaseAttributeSet.generated.h"
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class UNREALGAS_API UBaseAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "BaseAttributeSet")
FGameplayAttributeData HP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, HP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxHP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxHP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxMP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxMP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData Strength;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, Strength);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxStrength;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxStrength);
};
初始化属性值并给予普攻伤害
创建DT_CharacterAttribute(Row元素类型为AttributeMetaData)
并将这张数据表设置在BP_BaseCharacter的AbilitySystem的AttributeTest中
新建GE_Melee_Damage(基类为GameplayEffect)作为普攻伤害,配置好属性值
在检测碰撞处加上伤害的GameEffect
夹值处理
为了避免属性值低于最小值或高于最大值,需要进行夹值处理
镜头处理(碰撞、延迟跟随)
将BP_Player上的SpringArm中的DoCollisionTest
取消勾选,EnableCameraLag
勾选
不同等级伤害配表
创建MeleeDamageLevel.cvs文件,配置好数值后导入UE,选择为CurveTable和Constant
在GE_Melee_Damage中运用这个表
在ApplyGE的时候运用等级
敌人行为树
创建行为树BT_Behaviour及黑板BBP_Value,在行为树中新建BTT_FindPlayer和BTT_AttackMelee的Task,把Wait时间改成1s
在黑板中新建Player
属性
配置BTT_FindPlayer
配置BTT_AttackMelee
取消MoveTo节点中AllowPatialPath的勾选,并将BlackBoardKey
设置为Player,将BTT_FindPlayer节点中的Player
也设置为Player
新建BP_AIController(基类为AIController),在EventBeginPlay时执行行为树
在游戏场景中增加导航网格NavMesh,按P键显示
在BP_Enemy的AIControllerClass
中配置BP_AIController,将AutoPossessAI
属性值设置为Placed In World or Spawned
生命值变化时进行广播
多播委托参数
使用多播动态委托的原因:多播委托所带的dynamic的才能被蓝图调用
1
2
3
4
5
6
7
8
9
10
11
12
//BasicCharacter.h
#include "GameplayEffectTypes.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChangeEvent, float, NewValue);
class UNREALGAS_API ABaseCharacter : public ACharacter
{
UPROPERTY(BlueprintAssignable, Category = "Ability")
FOnHealthChangeEvent HPChangeEvent;
void OnHealthAttributeChanged(const FOnAttributeChangeData& Data);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//BasicCharacter.cpp
#include "AbilitySystemComponent.h"
#include "BaseAttributeSet.h"
void ABaseCharacter::BeginPlay()
{
Super::BeginPlay();
UAbilitySystemComponent* MyAbilitySystemComponent = this->FindComponentByClass<UAbilitySystemComponent>();
if (MyAbilitySystemComponent)//如果存在
{
MyAbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(UBaseAttributeSet::GetHPAttribute()).AddUObject(this, &ABaseCharacter::OnHealthAttributeChanged);
}
}
void ABaseCharacter::OnHealthAttributeChanged(const FOnAttributeChangeData& Data)
{
HPChangeEvent.Broadcast(Data.NewValue);//广播参数
}
在蓝图中调用
死亡动画
创建死亡的蒙太奇MA_Dead