虚幻引擎GAS入门(二)
MVC框架与技能初始化
- 让一开始创建的蓝图的基础
GameplayAbility
蓝图继承我们写好的BaseGameplayAbility
类
- 创建一个库函数,写一些常用的函数在里面
- 第一个得到玩家与玩家控制器
- 获取角色面对目标的方向
- 将技能UI添加到主UI中
- 在角色蓝图中创建一个函数用来初始化技能
编写回血技能
添加MP与Strength的变化逻辑
- 添加MP与Strength的变化函数
- 绑定他们的通知与广播
- 在角色蓝图中更新MP与Strength
创建回血技能
- 创建技能的步骤
魔法与能量改变时候的通知
- 在BaseAbility蓝图中写入检查通知
- 新建一个继承自基类的GameplayAbility技能蓝图,然后添加标记,选中
- 添加回血技能的效果
- 消耗15点蓝
- 然后继续添加技能CD
- 添加
GameplayCueNotify_Static
蓝图用来添加特效
- 先添加标签
- 在回复技能中添加这个Cue
- 学习技能
- 创建一个激活函数来激活技能
- 技能的图标给上,特效给上
- 制作回血Montage
- 播放回血技能
- 将特效的材质加上
- 在角色蓝图中添加一个判断是否满血的函数
- 运行结果
冲刺技能
- 制作冲刺技能的Montage
- 添加一个继承自BaseAbility技能蓝图的技能蓝图
- 添加标签与技能效果
- 分别设置这些效果属性
- 添加图标
- 在角色蓝图中添加技能,然后添加这个激活的技能标签
- 使用技能
添加技能冲刺的力的作用
- 添加一个事件来作为技能向前的作用力
- 先记录一下摩擦力
- 在角色基类里面添加一个消除摩擦力的函数
- 在角色身上添加一个碰撞球
- 将碰撞到的碰撞的信息发送出去
- 消除摩擦力函数在这调用,然后接收这事件应用添加伤害效果
- 运行结果
- 在敌人蓝图中添加一个被冲刺击晕的事件和一个回复控制器控制的函数
- 新建一个击飞的Montage
- 再添加一个推开的事件
- 调用击退与眩晕函数
- 技能结束时将角色的摩擦力添加上
使用冲刺技能阶段不能被打断
- 冲刺技能这
激活自有标签
- 其他技能
激活阻止标签
激光技能
- 新建激光技能,以及CD、Cost、伤害
- 在角色蓝图中添加我们需要学习的这个新技能
- 提交技能,触发技能
创建激光Actor
- 添加激光骨骼,添加一个碰撞球检测碰撞,添加一个摄像机臂
- 做这个激光的思路,这个骨骼只有三个,我们在动画蓝图中调节这个end位置就可以达到效果了,通过摄像机臂的碰撞检测碰到的第一个物体会进行阻挡
- 给激光骨骼创建动画蓝图,写入修改end骨骼逻辑
- 将动画蓝图给到激光
- 运行结果
激光的生成
- 制作激光的Montage动画
- 在激光Cost上添加一个资产标签,作用于技能结束后清除这个标签
- 技能结束时候删除标签进入CD
- 在角色蓝图中添加一个箭头来表示激光的发射位置
- 触发激光技能时就锁定视角,将激光Actor附加到表示激光发射位置的箭头组件上
- 结束后回复视角
各个技能之间的相互打断
- 手动取消技能,当再次按3的时候就关闭技能,用一个bool变量来标志技能是否在释放,然后使用事件分发去关闭技能
- 在基类技能蓝图中将:
- Cancel Abilities with Tag:取消带有特定标签的能力,让技能之间相互打断
- Activation Blocked Tags:阻止带有某些标签的能力激活,当这个tag被激活的时候,所有带这个tag的都不能被激活,让冲刺技能的优先级最高
给激光技能添加伤害与击飞
- 将激光的碰撞到敌人添加到数组中
- 每隔0.25秒进行一次消息
- 在角色基类蓝图中添加一个函数用来检测魔法值是否消耗完
- 拿到敌人的信息然后应用伤害与击飞眩晕效果
- 运行结果
一般报错处理
- 如果爆这种错误,就去这些位置添加判断
IsValid
,进行防御性编程
山崩地裂技能
- 首先制作这个技能的Montage
- 首先还是添加技能那一套
编写目标函数
- 新建
GameplayAbilityTargetActor
类来编写目标- 这个类主要用于处理游戏能力的目标选择。这个类提供了一个框架,让开发者能够创建自定义的目标选择行为,比如选择一个点、一个区域、一个或多个敌人等。目标选择是许多游戏机制中的关键部分,例如施放技能时需要指定攻击目标或者范围
- 这个类主要用于处理游戏能力的目标选择。这个类提供了一个框架,让开发者能够创建自定义的目标选择行为,比如选择一个点、一个区域、一个或多个敌人等。目标选择是许多游戏机制中的关键部分,例如施放技能时需要指定攻击目标或者范围
- 重写这两个函数
- meta = (ExposeOnSpawn = true):这是一个元数据标签,表示当这个 Actor 作为另一个 Actor 的子对象生成时(例如,通过 SpawnActor 或 BeginPlay),这个属性可以在生成时被设置。
- 实现逻辑
cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "GroundSelectTargetActor.h"
#include "Abilities/GameplayAbility.h"
void AGroundSelectTargetActor::StartTargeting(UGameplayAbility* Ability)
{
Super::StartTargeting(Ability);
// 获取拥有该能力的控制器,并将其转换为 APlayerController 类型
PrimaryPC = Cast<APlayerController>(Ability->GetOwningActorFromActorInfo()->GetInstigatorController());
}
void AGroundSelectTargetActor::ConfirmTargetingAndContinue()
{
//存储玩家注视点位置
FVector LookPoint;
GetPlayerLookAtPoint(LookPoint);
// 定义一个数组来存储重叠结果
TArray<FOverlapResult> OverlapResults;
// 定义一个数组来存储找到的敌对角色
TArray<TWeakObjectPtr<AActor>> OverlapActors;
// 创建碰撞查询参数
FCollisionQueryParams QueryParams;
QueryParams.bTraceComplex = false;
QueryParams.bReturnPhysicalMaterial = false;
// 获取当前玩家控制的角色
APawn* SelfPawn = PrimaryPC->GetPawn();
if (SelfPawn)
{
// 忽略当前玩家控制的角色,防止自撞
QueryParams.AddIgnoredActor(SelfPawn);
}
// 执行重叠检测,查找指定半径内的所有 Pawn
bool QueryResult = GetWorld()->OverlapMultiByObjectType(OverlapResults, LookPoint,
FQuat::Identity, // 旋转(默认为单位四元数)
FCollisionObjectQueryParams(ECollisionChannel::ECC_Pawn), // 只检测 Pawn 类型的对象
FCollisionShape::MakeSphere(selectRadius),// 使用球形碰撞形状,半径为 selectRadius
QueryParams);
if (QueryResult)
{
for (int i = 0; i < OverlapResults.Num(); i++)
{
// 将重叠结果转换为 APawn
APawn* Enemy = Cast<APawn>(OverlapResults[i].GetActor());
if (Enemy && !OverlapActors.Contains(Enemy))//敌人存在且没有重复包含
{
OverlapActors.Add(Enemy);
}
}
}
// 创建一个 FGameplayAbilityTargetDataHandle 来存储目标数据
FGameplayAbilityTargetDataHandle TargetDataHandle;
// 创建一个 FGameplayAbilityTargetData_LocationInfo 对象来存储中心位置
FGameplayAbilityTargetData_LocationInfo* CenterLoc = new FGameplayAbilityTargetData_LocationInfo();
CenterLoc->TargetLocation.LiteralTransform = FTransform(LookPoint);// 设置位置
// 设置位置类型
CenterLoc->TargetLocation.LocationType = EGameplayAbilityTargetingLocationType::LiteralTransform;
//0号负载
TargetDataHandle.Add(CenterLoc);// 将中心位置数据添加到 TargetDataHandle
if (OverlapActors.Num() > 0)
{
// 创建一个 FGameplayAbilityTargetData_ActorArray 对象来存储找到的敌人
FGameplayAbilityTargetData_ActorArray* ActorArray = new FGameplayAbilityTargetData_ActorArray();
ActorArray->SetActors(OverlapActors);// 设置找到的敌人
//1号负载
TargetDataHandle.Add(ActorArray); // 将敌人数据添加到 TargetDataHandle
}
// 检查是否应该生成目标数据
check(ShouldProduceTargetData());
// 检查是否允许确认目标
if (IsConfirmTargetingAllowed())
{
// 广播目标数据准备就绪的委托
TargetDataReadyDelegate.Broadcast(TargetDataHandle);
}
}
bool AGroundSelectTargetActor::GetPlayerLookAtPoint(FVector& Out_LookPoint)
{
FVector ViewLoc;//射线开始位置
FRotator ViewRot;
PrimaryPC->GetPlayerViewPoint(ViewLoc, ViewRot);
FVector ViewEnd = ViewLoc + ViewRot.Vector() * 50000.f;//射线终点位置
FHitResult HitResult;
FCollisionQueryParams QueryParams;//检测
QueryParams.bTraceComplex = true;//复杂检测
APawn* SelfPawn = PrimaryPC->GetPawn();
//忽略自己
if (SelfPawn)
{
QueryParams.AddIgnoredActor(SelfPawn);
}
//碰撞到物体就会返回一个bool值
bool TraceResult = GetWorld()->LineTraceSingleByChannel(HitResult, ViewLoc, ViewEnd,
ECollisionChannel::ECC_Visibility, QueryParams);
if (TraceResult)
{
Out_LookPoint = HitResult.ImpactPoint;//返回碰撞到的点
}
return TraceResult;
}
- 新建一个材质
- 新建这个类的蓝图
- 新建一个施法Montage
技能的取消
- 右键取消技能
- 在敌人蓝图中添加一个向上击飞事件
- 逻辑
- 运行结果
点燃技能
- 标准技能一套
- 创建点燃技能Montage
- 在动画蓝图中去发送Gameplay通知
编写目标函数
- 再次新建
GameplayAbilityTargetActor
类来编写目标
- 实现逻辑
cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "AroundGameplayAbilityTargetActor.h"
#include "Abilities/GameplayAbility.h"
void AAroundGameplayAbilityTargetActor::StartTargeting(UGameplayAbility* Ability)
{
Super::StartTargeting(Ability);
// 获取拥有该能力的控制器,并将其转换为 APlayerController 类型
PrimaryPC = Cast<APlayerController>(Ability->GetOwningActorFromActorInfo()->GetInstigatorController());
}
void AAroundGameplayAbilityTargetActor::ConfirmTargetingAndContinue()
{
APawn* SelfPawn = PrimaryPC->GetPawn();
if (!SelfPawn)
{
return;
}
FVector LookPoint = SelfPawn->GetActorLocation();
TArray<FOverlapResult> OverlapResults;
TArray<TWeakObjectPtr<AActor>> OverlapActors;
FCollisionQueryParams QueryParams;
QueryParams.bTraceComplex = false;
QueryParams.bReturnPhysicalMaterial = false;
if (SelfPawn)
{
QueryParams.AddIgnoredActor(SelfPawn);
}
// 执行重叠检测,查找指定半径内的所有 Pawn
bool QueryResult = GetWorld()->OverlapMultiByObjectType(OverlapResults, LookPoint,
FQuat::Identity, // 旋转(默认为单位四元数)
FCollisionObjectQueryParams(ECollisionChannel::ECC_Pawn), // 只检测 Pawn 类型的对象
FCollisionShape::MakeSphere(AroundRadius),// 使用球形碰撞形状,半径为 selectRadius
QueryParams);
//有重叠结果添加到 OverlapActors 数组
if (QueryResult)
{
for (int i = 0; i < OverlapResults.Num(); i++)
{
APawn* Enemy = Cast<APawn>(OverlapResults[i].GetActor());
if (Enemy && !OverlapActors.Contains(Enemy))
{
OverlapActors.Add(Enemy);
}
}
}
//存储目标数据
FGameplayAbilityTargetDataHandle TargetDataHandle;
if (OverlapActors.Num() > 0)
{
//存储找到的敌人
FGameplayAbilityTargetData_ActorArray* ActorArray = new FGameplayAbilityTargetData_ActorArray();
//设置找到的敌人
ActorArray->SetActors(OverlapActors);
//0号负载
TargetDataHandle.Add(ActorArray);
}
// 检查是否应该生成目标数据
check(ShouldProduceTargetData());
// 检查是否允许确认目标
if (IsConfirmTargetingAllowed())
{
// 广播目标数据准备就绪的委托
TargetDataReadyDelegate.Broadcast(TargetDataHandle);
}
}
- 将这个类生成为蓝图
- 添加两个伤害GE,一个是瞬间的伤害,一个灼烧的伤害
- 在瞬间扣血的GE中添加上这个点燃后的伤害GE。套娃伤害
- 技能逻辑
给点燃加个Cue
- 新建一个
GameplayCueNotify_Looping
蓝图,然后释放特效,记得添加标签
- 然后在灼烧GE里面添加这个Cue标签
- 运行结果