零、开篇
ActionRPG(以下简称示例)是官方GAS系统的使用示例,可于虚幻商城免费下载。本篇教程将围绕UEGameplay框架,GAS做浅析,逐步了解在动作游戏中,官方对虚幻的Gameplay框架和GAS系统的应用。
一、基于MVC思想的Gameplay游戏框架
1、MVC是什么
Model View Controller结构(简称MVC)详细解释请自行百度。
三个模块映射到UE的Gameplay框架中:
Model-GameInstance、GameMode、GameState
View-Actor、Level
Controller-PlayerController、AIController
其中不同的角色拥有不同的功能(服务器、客户端)ActionRPG是一个存粹的单机示例,并没有运用网络相关内容,这里就不详细展开了。
2、将MVC思想与游戏结合
直接说结论,玩家应该以Controller的身份参与到游戏中,通过Posses方法去拥有并控制View,Model则负责监控整个游戏的进度(倒计时),并更新和保存玩家(Controller)相关的状态(得分)
3、回到示例
只看功能结构,具体功能怎么实现的就不细说了
先看Model
示例重新实现了GameMode,添加了几个常用的游戏进度控制功能接口,然后在蓝图中实现功能。
GameMode蓝图共有两种,分别对应主菜单和游戏中,我们只看游戏中。GM主要实现了
- 播放过场动画
- 注册计时器更新倒计时
- 控制玩家和敌人的生成
- 回合控制
- 击杀计数
- 控制游戏结束时的慢动作和弹出结算界面
总体看下来都是整局游戏过程相关的逻辑。
PS:我觉得击杀计数应该写到GameState中,官方重写了GS,但仅仅是创建了个蓝图,并没有实现任何逻辑,感觉只是偷了个懒。
再看Controller
代表玩家的PlayerController和代表敌人的AIController。
PlayerController有C++和蓝图实现,先看C++:
继承自APlayerController和IRPGInventoryInterface
class ACTIONRPG_API IRPGInventoryInterface
{
GENERATED_BODY()
public:
/** Returns the map of items to data */
virtual const TMap<URPGItem*, FRPGItemData>& GetInventoryDataMap() const = 0;
/** Returns the map of slots to items */
virtual const TMap<FRPGItemSlot, URPGItem*>& GetSlottedItemMap() const = 0;
/** Gets the delegate for inventory item changes */
virtual FOnInventoryItemChangedNative& GetInventoryItemChangedDelegate() = 0;
/** Gets the delegate for inventory slot changes */
virtual FOnSlottedItemChangedNative& GetSlottedItemChangedDelegate() = 0;
/** Gets the delegate for when the inventory loads */
virtual FOnInventoryLoadedNative& GetInventoryLoadedDelegate() = 0;
};
主要是查询玩家背包功能相关的接口函数。
而PC主体也只是实现了背包内容的增删改查和相关逻辑通知。
蓝图:
- 大部分按键输入(暂停、打开背包、自动战斗、旋转相机、移动)
- UI控制
- Posses处理
- 背包道具操作的详细实现(获得和消耗灵魂、背包改变事件)
最后是View层
再看一下C++层RPGCharacter,出了继承自ACharacter外,还有两个特别的接口,IAbilitySystemInterface、IGenericTeamAgentInterface,分别为GAS系统和敌人的AI系统提供支持。GAS后面细说,AI后面再开篇单独分析。
- 角色状态相关Getter函数(血量、蓝量、移动速度、等级)
- GAS相关接口实现,并在构造函数中挂载了GAS组件
- 玩法功能事件(回血回蓝受伤之类的)
- 装备改变事件
整个CPP文件中,GAS相关功能实现占了大部分。
蓝图:
直接继承的蓝图有BP_Character,再往下有PlayerCharacter和EnemyCharacter,EnemyCharacter放在AI篇系锁。
BP_Character比较简单,主要还是GAS相关逻辑,如执行攻击、技能、使用道具、播放蒙太奇、判断是否死亡等通用功能
PlayerCharacter:
- 部分输入功能处理(奔跑、攻击、使用道具、翻滚、切换武器)
- 受击与死亡判定(通知控制器更新)
- 切换武器技能道具等相关逻辑
- 慢动作功能
到这里已经可以看出游戏中接触到的大部分功能的定义的位置了,简单分析一下。
- GM主要负责处理游戏整体玩法规则相关逻辑。
- Controller代表了玩家的状态和思想(输入)。且装备、道具之类的所有权应归于Controller也就是玩家,而不是玩家正在扮演的角色(角色只是使用权,道具的所有权属于归腾...玩家)
- 某个角色的逻辑,播放的动画,特效,则实现在Character中,以借助角色体现玩家的思想(输入)。角色不应该有控制整局规则的能力(如暂停、开始与结束)。
4.总结
整体结构就像是在下棋,GM是旁边裁判,规定了卒只能一格一格走。而棋手则负责指挥棋子每一步的行动。棋子会告诉棋手当前所处的位置,便于让棋手根据棋盘上的点和线做决策(而不是根据棋子在棋盘上的坐标。UE也是用这个思路给能够被棋手Controller控制的棋子起名叫做Pawn,这可不是巧合)
二、GAS系统
0、简介
GAS(Gameplay Abilities System 玩法能力系统)是一个官方插件,能够让开发者快速构建技能系统。采用数据驱动的方式,并对网络同步有着良好的支持。ActionRPG中绝大多数的技能甚至平A都是基于GAS构建的。Pawn可以通过继承IAbilitySystemInterface,并挂载UAbilitySystemComponent实现相关功能
1、从玩家的普通攻击Melee开始
在BP_PlayerCharacter中接受了玩家的鼠标点击操作,并调用重载后的DoMeleeAttack,蓝图会通过调用ActivateAbilitiesWithItemSlot进入到C++代码中,C++代码通俗的讲就是:
- ItemSlot->GAHandle->GA
其中ItemSlot以参数形式传入,GAHandle保存在RPGCharacter中的一个成员TMap中,将拿到的Handle交给AbilitySystemComponent处理。
那么GA是如何保存到AbilitySystemComponent中的呢?答案是通过AbilitySystemComponent中的GiveAbility接口实现。从AddSlottedGameplayAbilities函数可以看到相关过程:
void ARPGCharacterBase::AddSlottedGameplayAbilities()
{
TMap<FRPGItemSlot, FGameplayAbilitySpec> SlottedAbilitySpecs;
FillSlottedAbilitySpecs(SlottedAbilitySpecs);
// Now add abilities if needed
for (const TPair<FRPGItemSlot, FGameplayAbilitySpec>& SpecPair : SlottedAbilitySpecs)
{
FGameplayAbilitySpecHandle& SpecHandle = SlottedAbilities.FindOrAdd(SpecPair.Key);
if (!SpecHandle.IsValid())
{
SpecHandle = AbilitySystemComponent->GiveAbility(SpecPair.Value);
}
}
}
其中FGameplayAbilitySpec是负责保存GA生成的具体对象。
FillSlottedAbilitySpecs则是通过数据资源构建的,这些资源保存在/Items文件夹中。
注意:ActionRPG是通过引擎自带的AssetManager管理这些资源的查询和加载,故使用前需要再项目设置-AssetManager提前注册这些资源。
ActionRPG的所有GAS资源文件均继承自URPGItem类型,再细分为Weapon、Skill等。
以URPGWeaponItem举例,资源中出了包含了武器Actor类型、名称等游戏相关内容外,最重要的是Abilities栏中的GrantedAbility。这个值指向了一个具体的GA类型,当我们按下鼠标左键是,GAS具体执行的也就是这个类型中定义的功能。、
如默认武器Axe的普通攻击就是通过GA_PlayerAxeMelee实现。
找到并打开GA_PlayerAxeMelee后,可以看到角色普通攻击使用的蒙太奇动画,至此整个GAS的执行逻辑框架已经浮现。
动画中包含了大量的事件为了实现每个动画部分的具体逻辑功能。
2、Gameplay Effect
GAS中最复杂的模块,目的在于将技能的效果以数据的形式编辑保存。
参数太多了,建议边用边查资料。
程序还有个需要注意的东西
Modifier Magnitude Calculation(MMC)
一个自定义计算器,通过重写float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec & Spec) const;函数并返回一个float值来实现特殊逻辑。
标签:const,游戏,GAS,玩家,案例,Controller,ActionRPG,浅析 From: https://www.cnblogs.com/zshBlog2456/p/16894037.html