虚幻5---第13部分---敌人

虚幻5---第13部分---

碰撞盒(Collision Box)

------为武器添加盒体碰撞组件

重点与流程:

1.用C++ 在我的剑上添加盒子组件。

(声明类---写指针---添加对应头文件---构造函数)

  1. 调节碰撞盒的范围。

  2. 使用组件开始重叠事件来测试碰撞盒。

示例图

碰撞追踪(Tracing)

------使用盒体形状进行扫掠检测

重点和流程:

  1. 武器与物品无法触发重叠事件的原因?勾选生成重叠事件,查看物品的碰撞设置。
  2. 了解追踪的类型和定义和原理。
  3. 创建场景组件来作为起点和终点来做盒体追踪。在蓝图做一下看看逻辑。
  4. 修改武器的碰撞预设,使它的命中不被胶囊体干扰
示例图:


C++ 中的盒体碰撞追踪(Box Trace in C++)

------通过代码执行碰撞追踪

重点与流程:

  1. 在C++里设置碰撞预设,使用一些方便的函数。
  2. 在C++里新建场景组件变量。然后写盒式追踪函数。
示例图:

动态数组(Dynamic Arrays)

------虚幻引擎的 TArray 容器

重点与流程:

  1. 了解T-array,了解它的不同。(比如:自动扩容,自动缩小容量),崩溃的可能原因。

禁用盒体碰撞(Disabling Box Collision)

------仅在攻击时触发重叠事件

重点与流程:

  1. 进入攻击的蒙太奇动画,在里面设置通知。
  2. 然后再动画蓝图编辑器里面设置,连接。
  3. 在C++里面设置启动与禁用盒子碰撞。(一些可以访问私有变量的技巧)
  4. 在进入蓝图添加连接。
示例图

示例代码(来自SlashCharacter.h)
cpp 复制代码
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include"CharacterType.h"
#include "SlashCharacter.generated.h"

class USpringArmComponent;//提前声明弹簧臂组件
class UCameraComponent;//提前声明摄像机组件
class UGroomComponent;//提前声明毛发组件
class AItem; 
class UAnimMontage;
class AWeapon;

UCLASS()
class SLASH_API ASlashCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	
	ASlashCharacter();
	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	//设置碰撞开关。
	UFUNCTION(BlueprintCallable)
	void SetWeaponCollisionEnabled(ECollisionEnabled::Type CollisionEnabled); 


protected:
	virtual void BeginPlay() override;

	//输入的回调函数
	void MoveForward(float Value); //前进函数。
	void MoveRight(float Value);
	void Turn(float Value);
	void LookUp(float Value);
	void EKeyPressed(); //这是一个动作映射(装备武器),因为是一次性,所以没有参数。
	void Attack(); //攻击的回调函数,用来绑定攻击键。

	//播放蒙太奇动画的函数//重构函数
	void PlayAttackMontage();

	UFUNCTION(BlueprintCallable)
	void AttackEnd(); //攻击结束通知
	bool CanAttack();// 是否可以攻击

	void PlayEquipMontage(const FName& SectionName);//装备动画的函数
	bool CanDisarm();//检查卸下播放装备武器的蒙太奇动画的条件
	bool CanArm();//检查装备武器的蒙太奇动画的条件

	UFUNCTION(BlueprintCallable)
	void Disarm();//武器附着到脊椎上

	UFUNCTION(BlueprintCallable)
	void Arm();//武器从背上拿出的动画,也就是这次的附着点在右手

	UFUNCTION(BlueprintCallable)
	void FinishEquipping();//装备动画结束时
private:

	ECharacterState CharacterState = ECharacterState::ECS_Unequipped; //使用枚举常量来控制游戏逻辑

	UPROPERTY(BlueprintReadWrite,meta=(AllowPrivateAccess="true"))
	EActionState ActionState = EActionState::EAS_Unoccupied; //在攻击过程中阻止继续攻击

	UPROPERTY(VisibleAnywhere)
	USpringArmComponent* CameraBoom;//添加弹簧臂组件

	UPROPERTY(VisibleAnywhere)
	UCameraComponent* ViewCamera;//添加摄像机组件
	
	UPROPERTY(VisibleAnywhere, Category = Hair)
	UGroomComponent* Hair;//添加毛发组件(头发)

	UPROPERTY(VisibleAnywhere, Category = Hair)
	UGroomComponent* Eyebrows;////添加毛发组件(眉毛)

	UPROPERTY(VisibleInstanceOnly)
	AItem* OverlappingItem;  //创建一个重叠的游戏物品,需要在物品重叠时,才能从物品类里设置这个属性

	UPROPERTY(VisibleAnywhere,Category=Weapon)
	AWeapon* EquippedWeapon;//表示当前持有的武器

	//动画蒙太奇,这里保留蒙太奇变量,未来可能添加更多
	UPROPERTY(EditDefaultsOnly,Category=Montages)
	UAnimMontage* AttackMontage;
	//装备武器的蒙太奇动画
	UPROPERTY(EditDefaultsOnly, Category = Montages)
	UAnimMontage* EquipMontage;

	

public:
	FORCEINLINE void SetOverlappingItem(AItem* Item) { OverlappingItem = Item; } //有了OverlappingItem的公开设置器。小型的的函数设置成内联更高效
	FORCEINLINE ECharacterState GetCharacterState() const { return CharacterState; } //角色状态的公开访问器

};

虚幻引擎接口(Unreal Interfaces)

------使用接口处理受击事件

重点与流程:

  1. 了解接口,比如击中接口。让武器可以在击中的任何对象上调用get hit函数,不需要判断击中的是什么。
  2. 创建接口。
示例图:

敌方单位(Enemies)

------敌方角色类

重点与流程

创建C++类
  1. 创建一个character类,来作为游戏的敌人。
  2. 设置碰撞预设。把敌人设置成世界动态。(毕竟前面的武器忽略了pawn)也要忽略相机的碰撞响应。勾选或者在C++设置生成重叠事件。
新建对应的蓝图
  1. 新建敌人蓝图
  2. 去mixamo选择敌人的网络(Mesh)模型。导入项目,知道那些有用那些没用。
示例图:

根运动动画(Root Motion Animations)

------能实际移动角色的动画

重点与流程:

  1. 去mixamo找一些敌人的动画。(带皮肤)
  2. 了解根部运动动画,以及它的特点,比如使用条件等。(比如我们的角色要有跟骨头才可以使用。如果没有根骨骼,我们无法直接用动画来移动角色
  3. 如果我们下载的角色没有怎么办?把这个网络体导入到Blender这样的网络体编辑软件里。简单说,就是:下载需要的动画,然后用Blender和Mixamo Converter插件来给它们加根骨头。
  4. 使用批量转换。
  5. 进入编辑器,删除原本的一些网络体,导入转化后的动画。进行导入动画的设置。
  6. 给敌人分配一个网络体。给他一个动画播放。
示例图:

注意:

  1. 可能出现重命名错误。这里有解决办法。
  2. 把敌人拖到场景测试劈砍,如果没反应,可能是敌人蓝图里面没有设置物理资产,记得勾选。

实现接口(Implementing Interfaces)

------使用我们的受击接口

重点与流程:

让角色被击中时做出反应。
  1. 在C++里面敌人的代码要继承接口。有个技巧,把敌人写成既是角色也是IHit接口,这样更灵活。
  2. 重写我之前声明的githit函数
  3. 在指定的文件里面测试githit函数。
示例图:

受击反应蒙太奇(Hit React Montage)

------为受击反应创建蒙太奇

重点与流程:

  1. 制作蒙太奇。
  2. 只有在动画蓝图使用的该蒙太奇的插槽时才能播放。所以,我们要为该角色建立一个动画蓝图。并在敌人蓝图里设置。
示例图

播放受击反应蒙太奇(Playing the Hit React Montage)

------使敌人产生踉跄效果

重点与流程:

  1. 回到C++项目,进入敌人类,添加一个HitReact蒙太奇变量。
  2. 编写蒙太奇函数。
  3. 在敌人蓝图里设置动画。测试。
  4. 给动画勾选根运动。
示例图:

注意:

  1. 击中敌人后敌人自动回到原来的位置。开启碰撞检测->胶囊体没动。解决办法:
    我要进入该动画,确保它使用根运动。
  2. 动画不动,记得回到敌人的动画蓝图里勾选循环动画。

点积(Dot Product)

------两个向量之间的夹角

重点与流程

  1. 如何让敌人朝不同的方向倒?击中向量。了解击中的角度和对应的蒙太奇逻辑。
  2. 点积可以计算两个向量之间的角度。

原理图:

  1. 回到C++,创造击中向量。计算好角度与逻辑。
  2. 让我们的调试向量与地面平行,这样更好判断角度。
示例图:

叉积(Cross Product)

------另一种高级向量运算

重点与流程:

  1. 反余弦总是返回正数,但是叉积可以根据叉积的方向来判断角度的正负。这对判断左右击中方向很重要。
  2. 数学书用的右手定则,但是虚幻引擎是左手定则。

原理图:

  1. 返回Cpp,写叉积的调试办法。
示例图:

方向受击反应(Directional Hit Reactions)

------基于 θ 角选择蒙太奇片段

重点与流程:

  1. 在C++里写各个动画的播放与角度之间的逻辑。(注意大于等于号不要重合)
示例图

注意:

  1. 可能出现一次攻击导致击中多次的情况,下一部分会解决这个问题。

单次挥击单次命中(One Hit Per Swing)

------忽略已命中的 Actor

重点与流程:

  1. 重构一下我们的GitHit函数里的部分内容。
  2. 在武器里编写忽略被击中的角色的函数。
示例图

即使有多个重叠反应,也只有一个击中点。

受击音效(Hit Sounds)

------在敌人受击时播放音效

重点与流程:

  1. 下载一些击中的音效。导入项目
  2. 利用这些音效搞一个MetaSounds。设置好MetaSound,排除掉不合适的声音。
  3. 回到C++,进入敌人类,添加一个变量,用来存放敌人被击中的音效资产。
  4. 写该声音的处理逻辑。ps:热重载快捷键可以方便不按鼠标。
  5. 回到编辑器,设置我们的敌人。
  6. 设置声音,让声音有根据距离衰减的效果。建立声音衰减的资产类型。
  7. 在元音效蓝图里面设置。
  8. 调试声音的一些办法。
示例图

注意

  1. 每一个敌人一开始都是默认的声音蓝图,所以我们要在编辑器选择敌人,一个个设置好。当然,我们也可以在敌人蓝图里一次性设置好。

受击粒子效果(Hit Particles)

------在敌人受击时生成血迹效果

重点与流程:

  1. 了解Cascade(旧)和Niagara(新)。知道一下怎么从这两种方法来生成粒子效果。
  2. 先学一下怎么生成Cascade粒子。先弄一些血液粒子(Cascade类型)。
  3. 学习把整个文件夹导入项目的方法。查看该粒子效果
  4. 让敌方角色有一个这个粒子效果的变量。这样每个敌人有不同的血溅效果。
  5. 在蓝图使用测试一下spawn emitter at location。
  6. 在C++里完成这个效果。新加一个变量给粒子系统。
  7. 回到敌人蓝图,查找我们的变量,设置好它。
  8. 在C++写具体的击中效果函数。测试看看效果是否符合预期,位置是否正确。
  9. 之后去掉调试线条看看效果。记得把武器的调试追踪也关闭,这样每次做盒式追踪时就不会画盒子了。再关闭调试箭头。
示例图

部分代码示例:来自Enemy.h
cpp 复制代码
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interfaces/HitInterface.h"//让敌人可以继承接口里的函数和类
#include "Enemy.generated.h"

class UAnimMontage;

UCLASS()
class SLASH_API AEnemy : public ACharacter,public IHitInterface //继承两个父类
{
	GENERATED_BODY()

public:
	
	AEnemy();

	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	virtual void GetHit(const FVector& ImpactPoint) override;

	void DirectionalHitReact(const FVector& ImpactPoint);

private:
	//动画蒙太奇,这里保留蒙太奇变量,未来可能添加更多
	UPROPERTY(EditDefaultsOnly, Category = Montages)
	UAnimMontage* HitReactMontage;

	UPROPERTY(EditAnywhere, Category = Sounds)
	USoundBase* HitSound; //该变量存储MetaSound资产类型的值

	//击中的效果粒子,可以是血液,小石头等等
	UPROPERTY(EditAnywhere, Category = VisualEffects)
	UParticleSystem* HitParticles;

protected:
	
	virtual void BeginPlay() override;

	//播放蒙太奇函数
	void PlayHitReactMontage(const FName& SectionName);
public:	
	
	

};

注意:

  1. 有一些变量的类型不需要提前声明,因为已经内置了。可以通过热重载来判断。
    ps:热重载快捷键:ctrl+Alt+F11

武器拖尾(Weapon Trails)

------拖尾视觉效果

重点与流程:

  1. 我们需要一个轨道系统的粒子效果。在虚幻商城添加paragon:minions到项目,里面有我们需要的粒子系统。
  2. 进入主角的攻击蒙太奇。加速一下攻击,随便调整一下各个标签位置。
  3. 新建通知来添加尾部(trail)。
  4. Trail应该从哪里开始。选择它的插槽位置。
示例图:



挑战13

  1. 可以给脚加一些脚步声。
  2. 给游戏加一些音频。
相关推荐
寻寻觅觅☆8 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc8 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
l1t8 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿9 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar1239 小时前
C++使用format
开发语言·c++·算法
码说AI10 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS10 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
lanhuazui1010 小时前
C++ 中什么时候用::(作用域解析运算符)
c++
charlee4410 小时前
从零实现一个生产级 RAG 语义搜索系统:C++ + ONNX + FAISS 实战
c++·faiss·onnx·rag·语义搜索
星空下的月光影子10 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言