UE4动作游戏实例RPG Action解析三:实现效果,三连击Combo,射线检测,显示血条,火球术

一、三连Combo

实现武器三连击,要求:

1.下一段Combo可以随机选择,

2.在一定的时机才能再次检测输入

3. 等当前片段播放完才播放下一片段

1.1、蒙太奇设置

通过右键-新建蒙太奇片段,在蒙太奇里创建三个片段,并且移除相关连接,这样默认只会播放第一个片段

不同片段播放动画从 资产浏览器拖入,

1.2、创建JumpSection 动画通知类

重载NotifyBegin和NotifyEnd方法

NotifyBegin 设置一个bool变量 开启检测攻击输入

NotifyEnd 设置bool变量为false,关闭检测攻击输入

创建一个数组,用于编辑下段Combo可选的名字

1.3、在攻击期间检测 输入,实现连击

主要函数 蒙太奇设置下个片段, 如果想立刻跳转也可以设置 蒙太奇调至片段

目标 是当前 动画实例

Section Name to Change是当前正在播放的片段

Next Section是要跳转的片段

Montage 是当前激活的蒙太奇

至此,三连击的功能就实现完了。

二、射线检测获取目标

2.1、创建球体射线检测TargetType

BlueprintNativeEvent 表示希望蓝图里被重载,这样定以后,会优先调用蓝图中的Event,如果蓝图中该Event没有方法体,则调用C++的方法_Implementation

/** Called to determine targets to apply gameplay effects to */
	UFUNCTION(BlueprintNativeEvent)
	void GetTargets(ARPGCharacterBase* TargetingCharacter, AActor* TargetingActor, FGameplayEventData EventData,
		TArray<FHitResult>& OutHitResults, TArray<AActor*>& OutActors) const;

主要方法:对象的多球体检测

注意!!!

UCLASS(Blueprintable, meta = (ShowWorldContextPin))
class ACTIONRPG_API URPGTargetType : public UObject

加了ShowWorldContextPin之后,对于继承UObject的RPGTargetType 蓝图 才能显示对象的多盒体检测等方法 ,需要指定WorldContextOject对象

Start :初始位置,添加一个OffsetFromActor向量

End:结束位置 Actor向前向量,添加一个长度 变量

SphereRadius, 检测半径

ObjectTypes :

DrawDebug 可以绘制检测框

根据检测的结果 获取命中结果信息列表 作为返回值,中间判断了一下Hit Actor是否有效

2.2、蒙太奇 创建Send EventTag 动画通知类事件

发送EventTag, Payload数据为空

蒙太奇 添加该动画通知类事件,并编辑EventTag

通过解析八可知,在Player攻击的GameplayAbility添加GameplayEffects,这样收到EventTag后,就会根据TargetType获取目标,然后应用对应的TargetGameplayEffect效果

2.3、结果如下

第三段攻击创建了一个胶囊体碰撞框,绿色是检测到了目标

三、AttributeSet

3.1、Attribute Set 介绍:

PreAttributeChange : 任意属性发生变化前都会调用,通常用于强加规则给数值

PostGameplayEffectExecute: 任意影响Attribute的GameplayEffect执行之后都会调用,通常用于clamp数值,触发游戏中的事件

原文链接:GAS - Gameplay Attributes

Attribute
属性,记录Actor数值信息,类型为FGameplayAttributeData(目前就是float),常见的属性有血量、蓝量、攻击力、移动速度等等。通常使用Gameplay Effect来作用于Attribute,对属性值进行修改。
Gameplay Attribute可以说是这个系统的数据核心了,我们使用GAS的目的就是改变Actor的数值属性和状态(状态通常就是个二进制数Yes or No,使用Gameplay Tag)。设计技能也是从Actor拥有的属性出发的。


Attribute Set
Define and Configure attribute(定义和配置属性)
如何给Actor添加属性呢?这里要使用AttributeSet类,顾名思义,属性集类。在这个类中定义的float(被UPROPERTY标记)就是Attribute。

 



RPGAttributeSet,h

上图中的Health,MaxHealth,Mana都是属性,当然还有一些函数和宏定义,它们的功能后面细说。
创建好自己的AttributeSet类之后,必须使用AbilitySystemComponent注册它。实现方式有两种:
1、将其设为拥有AbilitySystemComponent的Actor的SubObject。

 



RPGCharacterBase.h


在构造函数中:
 



RPGCharacterBase.cpp


2、将类传给Ability System Component的GetOrCreateAttributeSubobject函数。
 



AbilitySystemComponent.cpp


相关的响应函数(不知道该如何称呼,暂且定这个叫法)
当属性值发生变化时,或是施放GameplayEffect时,我们希望做一些处理,此时就需要系统提供的响应函数来进行操作。如ActionRPG中,实现了两个函数:
 



RPGAttributeSet.h


插播:写override是个好习惯!!!
响应函数主要有:

  • PreAttributeBaseChange
  • PreAttributeChange
  • PreGameplayEffectExecute
  • PostGameplayEffectExecute

这里要提一下,Base value和(Current) value的区别。Base value是永久修改的,而value是暂存,这里应该涉及到网络相关,GAS是支持客户端回滚的。
各函数描述:
注意!!只能应用修改符和Setter来改变属性值(current value),应该也是为同步服务的
PreAttributeBaseChange:在base value修改前调用。因为是永久修改,不允许使用temporary modifiers(修改符也是一个类,通常修改属性是使用GameplayEffect,里面定义了基本的修改符,也可以自己拓展),不应该在游戏逻辑中使用。最多用来做数值的Clamp。
PreAttributeChange:同上,只是这里可以使用temporary modifiers。例子:

 



RPGAttributeSet.cpp

PreGameplayEffectExecute,PostGameplayEffectExecute:顾名思义,技能释放前、后会被调用。
 



官方描述


Replication(网络)
需要在UPROPERTY中添加ReplicatedUsing = OnRep_MyAttribute,同时要在GetLifetimeReplicatedProps函数中设置LiftTime,于是最后会变得像是这样。

 


 



ActionRPG中是这样的,LifeTime的设置不一样,如果上图中说的无误,则ActionRPG这样设置在联机时可能会出现Error。

 



RPGAttributeSet.cpp

相关宏(Macro)
在前面的响应函数实现中,我们发现要使用许多Get函数,来获得属性或是属性值。幸好,引擎为我们准备好了宏。

 



AttributeSet.h

数据驱动
你可以用数据表来初始化你的AttributeSet。

 

3.2、RPGAction Health属性解析

3.2.1 定义 一个Health 属性 和一个 MaxHealth属性:

// Uses macros from AttributeSet.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 ACTIONRPGCOPY_API URPGAttributeSet : public UAttributeSet
{
	GENERATED_BODY()
	
public:

	URPGAttributeSet();
	virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
	virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

	/** Current Health, when 0 we expect owner to die. Capped by MaxHealth */
	UPROPERTY(BlueprintReadOnly, Category = "Health")
	FGameplayAttributeData Health;
	ATTRIBUTE_ACCESSORS(URPGAttributeSet, Health)

	/** MaxHealth is its own attribute, since GameplayEffects may modify it */
	UPROPERTY(BlueprintReadOnly, Category = "Health")
	FGameplayAttributeData MaxHealth;
	ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxHealth)
};

3.2.2 PreAttributeChange : 任意属性发生变化前都会调用,通常用于强加规则给数值

RPGAction添加了函数 AdjustAttributeForMaxChange , 其作用是,当属性最大值发生改变时,按比例改变当前值。

void URPGAttributeSet::AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty)
{
//获得UAbilitySystemComponent实例
    UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();、
//Getter方法获取的都是current value而不是base value
    const float CurrentMaxValue = MaxAttribute.GetCurrentValue();
    if (!FMath::IsNearlyEqual(CurrentMaxValue, NewMaxValue) && AbilityComp)
    {
        // Change current value to maintain the current Val / Max percent
        const float CurrentValue = AffectedAttribute.GetCurrentValue();
        float NewDelta = (CurrentMaxValue > 0.f) ? (CurrentValue * NewMaxValue / CurrentMaxValue) - CurrentValue : NewMaxValue;
                //      通过UAbilitySystemComponent实例
        AbilityComp->ApplyModToAttributeUnsafe(AffectedAttributeProperty, EGameplayModOp::Additive, NewDelta);
    }
}


我们要注意到对属性值的修改是通过调用GameplayAbilityComponent的ApplyModToAttributeUnsafe方法实现的。

3.2.3 PostGameplayEffectExecute: 任意影响Attribute的GameplayEffect执行之后都会调用,通常用于clamp数值,触发游戏中的事件

void URPGAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);

//GameplayEffectContext结构体存有关于GameplayEffectSpec创建者(Instigator)和TargetData的信息
	FGameplayEffectContextHandle Context = Data.EffectSpec.GetContext();
	UAbilitySystemComponent* Source = Context.GetOriginalInstigatorAbilitySystemComponent();
	const FGameplayTagContainer& SourceTags = *Data.EffectSpec.CapturedSourceTags.GetAggregatedTags();

	float DeltaValue = 0;
	if (Data.EvaluatedData.ModifierOp == EGameplayModOp::Type::Additive)
	{
		DeltaValue = Data.EvaluatedData.Magnitude;
	}

	AActor* TargetActor = nullptr;
	ARPGCharacterBase* TargetCharacter = nullptr;
	if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
	{
		TargetActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
		TargetCharacter = Cast<ARPGCharacterBase>(TargetActor);
	}

	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		SetHealth(FMath::Clamp(GetHealth(),0.0f,GetMaxHealth()));

		if (TargetCharacter)
		{
			TargetCharacter->HandleHealthChanged(DeltaValue,SourceTags);
		}
	}
}

四、创建血条

4.1、创建一个血条UI

1.1 创建一个控件蓝图如下,右下角可以调节大小,

添加一个进度条

1.2 在图表层,添加SetProgress方法,输入参数是 float型,设置百分比

1.3 把控件蓝图 拖入到BP_EnemyCharacter对象上,调整到合适位置

控件类 设置成 刚刚创建的血条控件

空间 设置成屏幕类型

4.2、获取敌人生命值百分比

在上一节中在BP_CharacterBase创建了一个函数OnHealthChanged

	UFUNCTION(BlueprintImplementableEvent)
	void OnHealthChanged(float DeltaValue,const FGameplayTagContainer& EventTags);

当生命值发生变化时,这个函数会调用到

在BP_EnemyCharacter蓝图实现函数:血条百分比 = Health值/MaxHealth值

4.3、创建一个GameplayEffect 扣除Health 效果

在Player 的攻击GA 添加该效果,打到敌人就会扣10点血,BP_Character默认Health值设置100

4.4、最终效果

五、火球术

5.1、创建一个Actor火球

创建一个Actor蓝图类,BP_AbilityProjectileBase,作为远程武器的蓝图基类,

添加球体碰撞组件,箭头组件,

ProjectileMovement组件:具有赋予场景内组件初速度的功能

设置初速度,并且把 发射物重力范围 数值调整为0 这样便不会 受重力影响了

创建一个子蓝图BP_FireBall,添加一个粒子效果,

注意!!!如果材质里元素2 赋值不了,可以重启引擎

把FireBall拖入场景中运行即可看到火球超前飞去

设置FireBall 的生命周期为10s

5.2、在命中到WorldStatic和WorldDynamic对象时,发射一个粒子事件,并销毁自身

设置FireBall 球体碰撞的 碰撞事件,和墙壁等发生阻挡,Pawn触发重叠事件

事件命中:此Actor与阻挡物体发生碰撞,或阻挡另一个与之碰撞的Actor时调用的事件

5.3、添加输入

BP_CharacterBase增加一个激活方法

bool ARPGCharacterBase::ActivateAbilitiesWithTag(FGameplayTagContainer AbilityTags, bool bAllowRemoteActivation)
{
	if (AbilitySystemComponent)
	{
		return AbilitySystemComponent->TryActivateAbilitiesByTag(AbilityTags,bAllowRemoteActivation);
	}

	return false;
}

通过AbilityTags激活技能

5.4、创建释放远程武器技能GameplayAbility

创建一个远程武器技能基类,GA_SpawnProjectileBase,

前面和近战播放技能一样,在收到蒙太奇 发送的技能EventTag之后,调用EventReceived方法

创建一个RPGGameplayEffectContainerSpec结构,再根据ProjectileClass生成Actor, ProjectileClass是刚刚创建的火球基类类型BP_AbilityProjectileBase,获取Actor信息作为生成位置,

DoesEffectContainerSpecHaveEffects 是判断是否有GameEffect

继承GASpawnProjectileBase 创建一个子类GA_PlayerSkillFireBall,设置参数

在蒙太奇播放的选定时间发送EventTag,

5.5、火球在飞行过程中,触发重叠事件和命中事件

重叠事件中,把技能释放中生成的EffectContainerSpec 应用到Actor, 这样Actor便会应用GamepalyEffect效果

在子类的重叠事件中也加一个播放粒子效果并销毁Actor效果

至此,效果便完成了

  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张乂卓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值