在上一章中,我们实现了敌人的攻击技能的特效和音效。如果我们在多人模式下打开,发现,其它客户端看不到对应的效果。
造成这种问题的原因是因为敌人的技能是运行在服务器端的,它只复制到拥有它的客户端,而敌人的效果对于客户端来说,它们都不拥有此内容,所以无法查看到。
那么如何实现每个客户端都可以查看到和听到所需的效果呢,这里就需要使用gameplay Cue去实现了。它可以实现让每个客户端都能获得同样的视效和音效。
创建GameplayCue
右键点击创建蓝图,搜索gameplaycue。
我们会发现对应的可以创建两种GameplayCue,一种是集成至Actor,它是被实例化的,并且可以做到每一帧更新状态和数据。另一种静态的,是无法被实例化,对于一次性的效果很有用。
我们这里选择GameplayCueNotify_Static作为基类,创建通过通知实现。
我们以简写GC为前缀,表示它是一个GameplayCue,这个作为受击的效果。
进入蓝图,选择重载On Execute,在技能被触发时,将触发此节点的回调。
我们打开传递过来的参数,发现有很多的配置项,这些都是我们在调用时可以设置的。
我们通过Source object获取到角色的受伤特效,生成一个粒子特效
触发Gameplay Cue
现在,我们创建了一个GC,还没有实现对其的触发,让其播放特效。如果要实现特效的播放,我们需要通过标签去触发。
打开项目设置,GameplayTag标签管理器,有一个GameplayCue,这个是专门用于设置GC使用的标签地方。
我们在下面添加一个受击特效标签
然后回到GC里面设置,你会发现,在这里只能选择GameplayCue下面的标签,我们选中标签
这样就实现了GC的制作,我们回到技能蓝图中,要能够触发GC,我们使用Execute GameplayCue Width Params On Owner节点,这个可以通过设置Tag来选择需要激活的标签,并且还能够传入配置项
然后,我们将节点拖出,制作一个配置项,并将所需的内容设置上去
在客户端查看效果即可。可以看到在客户端也能触发特效表现。
修改敌人技能蒙太奇标签
接下来,我们要实现敌人技能的音效在多个客户端上面触发,音效是设置在蒙太奇的结构体当中的,查看配置项,我们是无法直接将配置项传递的。
所以,我们需要修改结构体,增加一个技能独有的索引,并实现一个函数,通过标签去获取对应的结构体数据。
首先我们在C++里面将标签改掉
之前的Montage标签修改为战斗接口标签
cpp
FGameplayTag CombatSocket_Weapon; //使用武器攻击部位标签
FGameplayTag CombatSocket_RightHand; //右手攻击部位标签
FGameplayTag CombatSocket_LeftHand; //左手攻击部位标签
在cpp文件中将注册代码也修改掉
cpp
/*
* CombatSocket
*/
GameplayTags.CombatSocket_Weapon = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("CombatSocket.Weapon"),
FString("使用武器攻击部位标签")
);
GameplayTags.CombatSocket_LeftHand = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("CombatSocket.LeftHand"),
FString("左手攻击部位标签")
);
GameplayTags.CombatSocket_RightHand = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("CombatSocket.RightHand"),
FString("右手攻击部位标签")
);
然后我们增加对于动作设置新的索引,在标签中新增,这里我们新增四个
cpp
//使用攻击动作索引
FGameplayTag Montage_Attack_1;
FGameplayTag Montage_Attack_2;
FGameplayTag Montage_Attack_3;
FGameplayTag Montage_Attack_4;
对UE中进行注册
/*
* Montage Attack Index
*/
GameplayTags.Montage_Attack_1 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Montage.Attack.1"),
FString("第1个蒙太奇攻击标签")
);
GameplayTags.Montage_Attack_2 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Montage.Attack.2"),
FString("第2个蒙太奇攻击标签")
);
GameplayTags.Montage_Attack_3 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Montage.Attack.3"),
FString("第3个蒙太奇攻击标签")
);
GameplayTags.Montage_Attack_4 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Montage.Attack.4"),
FString("第4个蒙太奇攻击标签")
);
接下来,我们在结构体中,增加一个部位的设置,原来的用来设置索引
cpp
//蒙太奇动画和标签以及骨骼位置的映射,用于攻击技能获取和设置攻击范围
USTRUCT(BlueprintType)
struct FTaggedMontage
{
GENERATED_BODY()
//使用的蒙太奇
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UAnimMontage* Montage = nullptr;
//当前数据的索引
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FGameplayTag MontageTag;
//部位对应的标签
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FGameplayTag SocketTag;
//攻击时的触发伤害的骨骼插槽
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FName CombatTipSocketName; //设置技能释放的位置
//攻击时的触发音效
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
USoundBase* ImpactSound = nullptr;
};
接着将代码中使用到的地方修改掉
然后编译,修改UE蓝图中使用的内容
在技能蓝图中,修改使用接收信息的标签
去蓝图中,修改每个角色的攻击蒙太奇的数据,
然后点击进入对应的蒙太奇,修改对应的位置标签
我们将这四个怪物都修改掉,技能有近战攻击和远程攻击两个需求把标签修改掉。修改完成运行查看效果是否有问题,主要查看技能是否都能够正确触发,技能释放的位置是否正确。
实现播放音效的GameplayCue
在上面,我们修改完成了标签重构工作。最后,我们还需要实现一个通过标签从结构体数组中获取对应的结构体。
在战斗接口中增加一个函数
cpp
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
FTaggedMontage GetTaggedMontageByTag(const FGameplayTag& MontageTag); //通过标签获取对应的结构体
然后在角色基类里面覆写它
cpp
virtual FTaggedMontage GetTaggedMontageByTag_Implementation(const FGameplayTag& MontageTag) override;
在cpp里面实现函数,我们只需要遍历数组,判断MontageTag即可
cpp
FTaggedMontage ARPGCharacter::GetTaggedMontageByTag_Implementation(const FGameplayTag& MontageTag)
{
for(FTaggedMontage TaggedMontage : AttackMontage)
{
if(TaggedMontage.MontageTag.MatchesTagExact(MontageTag))
{
return TaggedMontage;
}
}
return FTaggedMontage();
}
编译打开UE,我们接着创建一个新的GC,用来播放攻击音效
这里,我们需要传入一个TagContainer(标签集合)一个位置,以及释放技能的角色,通过标签集合获取到使用的MontageTag,然后去获取结构体,然后通过结构体内的音效配置项和位置进行播放音效。
标签这里,我也创建了一个新的标签
接下来,就是将此部分替换掉
我们将其替换成通过标签触发GC
如果你不确定有没有问题,可以在GC里面打印音效名称
查看是否能够成功打印对应的名称