UE5 Sample FPS
第一人称射击游戏 (FPS) 是一种玩家使用枪支并通过可玩角色的视角体验游戏的游戏类型。FPS 游戏非常受欢迎,拥有《使命召唤》和《战地风云》等知名系列。
虚幻引擎是为创建 FPS 游戏而构建的,因此使用它创建一个游戏是有意义的。
- 创建一个可以移动和环顾四周的第一人称 Pawn。
- 创建一把枪并将其附加到玩家 Pawn 上。
- 使用线迹射出子弹——也称为光线投射。
- 对Actor造成伤害。
入门
使用本文开头或末尾的“下载材料”按钮下载项目材料,然后解压缩。导航到名为BlockBreakerStarter 5.0的项目文件夹,然后打开BlockBreaker.uproject。你会看到下面的场景:
绿墙由多个目标组成,这些目标在受到伤害时会变成红色。一旦他们的生命值降为零,他们就会消失。红色按钮重置所有目标。
首先,将创建玩家的 Pawn。
创建玩家 Pawn
如果来自 UE4,可能已经注意到文件夹面板似乎不见了。不要绝望,因为它是隐藏的,允许几乎全屏查看项目。要查找项目文件夹,只需单击屏幕左下角的内容抽屉。
现在,可以看到导航面板,包括文件夹结构和游戏资产。如果想让它在屏幕底部永久打开,只需单击此面板右侧的布局中的停靠。
导航到Blueprints文件夹并右键单击面板背景以创建一个新的Blueprint Class。选择Character作为父类并将其命名为BP_Player。
Character是一种具有附加功能的 Pawn,例如自动处理行走和跳跃等运动的CharacterMovement组件。只需调用适当的函数,它就会移动 Pawn。还可以在该组件内设置步行速度和跳跃速度等变量。
在可以让 Pawn 移动之前,它需要知道玩家何时按下移动键。为此,需要将移动映射到W、A、S和D键。
注意:如果想了解映射,可以在此蓝图教程中了解它们。键映射是定义哪些键将执行操作的方式。
创建运动映射
通过键映射,可以更改玩家角色的属性——例如他们在 XY 平面中的位置或视口的摄像机角度——并将其应用到游戏世界中。这就是操纵角色位移和视角的方式。
选择编辑 ▸ 项目设置并打开引擎部分下的输入设置。
单击Axis Mappings旁边的**+两次,添加两个Axis Mappings。可能必须通过单击添加第一个映射后出现的轴映射前面的展开三角形来展开轴映射列表。将它们重命名为MoveForward和MoveRight。MoveForward将处理向前和向后移动。MoveRight将处理左右移动。
对于MoveForward ,通过首先选择None下拉列表将键更改为W。然后,展开键盘列表,最后选择列表底部的字母W。
之后,通过单击MoveForward旁边的+创建另一个键,并将其设置为S。将S的比例更改为-1.0。
注意:如果想了解有关Scale字段的更多信息,可以参考上面提到的相同蓝图教程。轴值和输入比例部分描述了它是什么以及如何使用它。
稍后,会将比例值与 Pawn 的前向向量相乘。如果比例为正,这将为提供一个指向前方的矢量。如果比例为负,则矢量指向后方。使用生成的矢量,可以让的 Pawn 向前和向后移动。
接下来,需要为左右移动做同样的事情。将MoveRight的键更改为D。之后,创建一个新密钥并将其设置为A。将A的比例更改为-1.0。
现在已经设置了映射,需要使用它们来移动。
实施运动
双击BP_Player打开它,将看到 Viewport 视图。使用窗口顶部的选项卡导航到事件图。
右键单击视图背景以添加MoveForward事件,该事件列在Axis Events下。这个事件将在每一帧执行,即使你没有按下任何东西。
它还输出一个Axis Value,这是之前设置的Scale值。如果按W则输出1,如果按S则输出**-1。如果不按任何一个键,它会输出0。
接下来,需要告诉 Pawn 移动。添加一个Add Movement Input,并像这样连接它:
Add Movement Input获取一个向量并将其乘以Scale Value,将其转换为适当的方向。由于使用的是Character,因此CharacterMovement组件会将 Pawn 朝适当的方向移动。
现在,需要指定要移动的方向。因为你想向前移动,所以使用Get Actor Forward Vector返回一个指向前方的向量。创建一个并像这样连接它:
所以,总结一下:
- MoveForward运行每一帧并输出一个Axis Value。如果按W则此值为1 ,如果按S则此值为**-1。如果不按任何一个,则为0。
- Add Movement Input将 Pawn 的前向向量与Scale Value相乘。这会导致矢量指向前方或后方,具体取决于按下的键。如果不按任何键,则向量没有方向,这意味着 Pawn 不会移动。
- CharacterMovement组件从Add Movement Input获取结果并在适当的方向上移动 Pawn。
对MoveRight重复该过程,但将Get Actor Forward Vector替换为Get Actor Right Vector。
在测试移动之前,需要在游戏模式中设置默认 Pawn。
设置默认 Pawn
单击窗口左上角的编译,然后返回主编辑器。在单击它之前,它会显示一个带问号的黄色圆圈。单击后,它应该有一个绿色圆圈,表示该过程成功。
打开世界设置面板并找到游戏模式部分。将默认 Pawn 类更改为BP_Player。
注意:如果没有“世界设置”面板,请转到窗口右上角的“设置” ,然后单击**“世界设置”。
现在,将在游戏开始时自动使用BP_Player ,它会自动放置在**Player Start资产的位置。按播放键并使用W、A、S和D键四处移动。可能必须先在游戏窗口内单击鼠标才能为该窗口提供键盘焦点。
接下来,将创建环顾四周的映射。
创建外观映射
再次打开项目设置。再创建两个名为LookHorizontal和LookVertical 的**轴映射。
将LookHorizontal的键更改为Mouse X。
当向右移动鼠标时,此映射输出一个正值,反之亦然。
接下来,将LookVertical的键更改为Mouse Y。
当向上移动鼠标时,此映射输出正值,反之亦然。
现在,需要创建环顾四周的逻辑。
实施寻找
如果 Pawn 没有相机组件,Unreal 会自动为创建一个相机。默认情况下,此相机使用控制器的旋转。
注意:如果想了解有关控制器的更多信息,请查看有关人工智能的教程。
尽管控制器是非物理的,但它们仍然有自己的轮换。这意味着可以使 Pawn 和相机朝向不同的方向。例如,在第三人称游戏中,角色和镜头并不总是朝向同一个方向。
要在第一人称游戏中旋转相机,只需更改控制器的旋转。这与为移动所做的过程几乎相同——只是使用旋转而不是平移。
打开BP_Player并创建一个LookHorizontal事件。
要使相机向左或向右看,需要调整控制器的偏航角。创建一个添加控制器偏航输入并连接它:
当水平移动鼠标时,控制器会向左或向右偏转。由于相机使用控制器的旋转,它也会偏航。
对LookVertical重复该过程,将Add Controller Yaw Input替换为Add Controller Pitch Input。
如果现在测试游戏,会注意到垂直方向是倒置的。这意味着当向上移动鼠标时,相机向下看。如果更喜欢非反转控件,请添加一个乘法运算符并将轴值乘以-1。这会反转轴值和控制器俯仰。
单击“编译”,然后按“播放”。使用鼠标开始环顾四周。
现在你已经完成了运动和观察,是时候制造一把枪了!
制造枪支
知道创建蓝图类时如何选择父类吗?那么,也可以选择自己的蓝图作为父级。当拥有共享共同功能或属性的不同类型的对象时,这很有用。
假设想拥有多种类型的汽车。可以创建一个包含速度和颜色等变量的基本汽车类。然后,可以创建使用基本汽车类作为父类的子类。每个孩子也将包含相同的变量。现在,可以轻松地创建具有不同速度和颜色值的汽车。
可以使用相同的方法来制造枪支。只需要先创建一个基类。
创建基础枪类
回到主编辑器,创建一个Actor类型的蓝图类。将其命名为BP_BaseGun,然后双击打开它。
接下来,将创建变量来定义枪支属性。为此,请转到蓝图窗口的“变量”部分,然后单击框架右上角的+按钮。
创建以下浮点变量:
- MaxBulletDistance:每颗子弹可以移动多远。
- Damage:当子弹击中 actor 时应用多少伤害。
- FireRate:枪可以发射另一颗子弹的时间,以秒为单位。
注意:每个变量的默认值为零,这对本教程来说很好。但是,如果希望新的枪支类别具有默认值,可以在BP_BaseGun中设置它。
现在,需要枪支的物理表示。单击Add,键入Static Mesh,选择组件Static Mesh将其添加到蓝图类中,并将其命名为GunMesh。
现在不要担心选择静态网格物体。将在下一节中创建儿童枪支类时执行此操作。在这个父类中,只需定义一把枪必须有一个在游戏中显示枪支几何形状的静态网格组件。
创建儿童枪类
单击Compile,然后返回到主编辑器。要创建子类,请右键单击BP_BaseGun并选择创建子蓝图类。
将其命名为BP_Rifle,然后打开它。打开窗口右上角的Class Defaults ,并设置变量值:
- 最大子弹距离:5000
- 伤害:2
- 射速:0.1
这意味着每颗子弹最多可以飞行5000距离。如果它击中了一个演员,它会造成2 点伤害。连续射击时,每次射击之间的持续时间至少为0.1秒。
接下来,需要指定枪应该使用哪个网格。选择屏幕左侧的GunMesh组件,注意右侧的Details选项卡已更改其内容。查找Static Mesh部分并使用下拉菜单将其设置为SM_Rifle。
枪是完整的。单击编译,然后关闭BP_Rifle。
接下来,将创建自己的相机组件以更好地控制相机放置。它还可以让将枪连接并保持在相机前面。
创建相机
打开BP_Player ,并以与创建BP_BaseGun类的静态网格组件相同的方式添加一个Camera组件。将其命名为FpsCamera。
默认位置有点太低,这可能会让玩家觉得自己很小。在Details面板上,将FpsCamera的位置设置为(X:0, Y:0, Z:90)。
默认情况下,相机组件不使用控制器的旋转。要解决此问题,请转到Details面板并启用Camera Options ▸ Use Pawn Control Rotation。
接下来,需要定义枪支的位置。
定义枪支位置
要创建枪支位置,将使用场景组件。这些组件非常适合定义位置,因为它们只包含一个转换。确保选择了FpsCamera,然后添加一个Scene组件以将其附加到相机。将其命名为GunLocation。
通过将GunLocation附加到FpsCamera,枪将保持相对于相机的相同位置,始终保持枪在视野中。
接下来,在Details面板中,将GunLocation的位置设置为(X:30, Y:14, Z:-12)以将其放置在摄像机的前方并稍微偏向一侧。
之后,将旋转设置为(X:0, Y:0, Z:-95)使其看起来好像在瞄准屏幕中心。
现在,需要生成枪并将其附加到GunLocation。
产卵和附加枪
在BP_Player事件图上找到Event BeginPlay,创建一个Spawn Actor From Class并将其连接到它。将类设置为BP_Rifle。
如果现在编译,将收到一条错误消息,指出 Spawn Transform 节点必须有一个连接到其中的输入。发生这种情况是因为,在当前形式中,此 pin 是一个结构,需要适当的初始化。为避免此错误,请右键单击Pawn Transform并选择Split Struct Pin。这将显示构成引脚的变量并为其分配初始值。现在代码编译成功。
由于稍后需要使用这把枪,因此将把它存储在一个变量中,就像之前为基枪类创建变量一样。现在,创建一个BP_BaseGun类型的变量,并将其命名为EquippedGun。
注意:重要的是变量不是**BP_Rifle类型。这是因为玩家可以使用不同类型的枪支,而不仅仅是步枪。如果生成不同类型的枪支,则无法将其存储在BP_Rifle类型的变量中。这就像试图将一个圆放入一个矩形孔中。
通过创建BP_BaseGun类型的变量,创建了一个可以接受多种形状的大洞。
接下来,将EquippedGun设置为Spawn Actor From Class的返回值。
要附加枪支,可以使用AttachActorToComponent。创建一个并将位置规则和旋转规则设置为对齐目标以使枪与其父枪具有相同的位置和旋转。
接下来,创建对GunLocation的引用并连接所有内容:
所以,总结一下:
- 当BP_Player产生时,它会产生一个**BP_Rifle的实例。
- EquippedGun保留对生成的BP_Rifle 的引用以供以后使用。
- AttachToComponent将枪附加到GunLocation。
单击“编译”,然后按“播放”。现在,当你重生时,你就有了一把枪!当你环顾四周时,枪总是在镜头前。
射击子弹
现在是有趣的部分:射击子弹!要检查子弹是否击中某物,将使用line trace。
线轨迹是一个函数,它接受起点和终点,形成一条线。然后它会检查这条线上的每个点,从开始到结束,直到它碰到什么东西。这是游戏中最常见的检查子弹是否击中物体的方法。
由于射击是枪支的功能,因此它应该属于枪支类而不是玩家。打开BP_BaseGun并通过单击屏幕左侧Functions面板顶部的+创建一个名为**Shoot的函数。
输入 Shoot 函数的名称后,UE5 应该会在屏幕中央自动打开一个带有紫色Shoot节点的蓝图选项卡。如果它没有自动打开,请双击左侧面板上新创建的函数。
然后,在右侧的Input面板上,单击+*创建两个*Vector*输入。将它们命名为*StartLocation*和*EndLocation以表示将从BP_Player传入的线轨迹的起点和终点。请注意,Inputs 被添加到Shoot节点,就像函数参数一样。
可以使用LineTraceByChannel执行线路跟踪。此节点使用可见性或相机碰撞通道检查命中。创建一个并连接它:
接下来,需要检查线路跟踪是否命中任何东西。创建一个分支并连接它:
如果命中则返回值输出真,否则**输出假。
接下来,为了向玩家提供子弹击中位置的视觉反馈,将使用粒子效果。
生成子弹冲击粒子
首先,需要获取跟踪命中的位置。拖动单击Out Hit并在图中释放左键单击。从菜单中选择Break Hit Result。
这为提供了一个节点,其中包含与线路跟踪结果相关的各种引脚。
在 Location创建一个Spawn Emitter并将Emitter Template设置为PS_BulletImpact。然后,将其Location连接到Break Hit Result的Location。
这是到目前为止的功能:
所以,总结一下:
- 当Shoot执行时,它会使用提供的起点和终点执行线条跟踪。
- 如果命中,Spawn Emitter at Location在命中位置生成PS_BulletImpact 。
现在拍摄逻辑已经完成,需要使用它。
调用拍摄功能
首先,需要创建用于拍摄的键映射。单击编译并打开项目设置。创建一个名为Shoot的新**轴映射。将其键设置为Left Mouse Button,然后关闭Project Settings。
接下来,打开BP_Player并创建一个Shoot事件。
要检查玩家是否按下了Shoot键,只需检查Axis Value是否等于1。创建突出显示的节点。一个是Branch,另一个是Equal operator:
接下来,创建对EquippedGun 的引用,然后调用其Shoot函数。
现在,需要计算线条轨迹的起点和终点。
计算线迹位置
在许多 FPS 游戏中,子弹从相机而不是枪开始,因为相机已经与十字准线完美对齐。所以如果你用相机射击,子弹肯定会射到十字准线所在的地方。
注意:有些游戏确实是用枪射击的。然而,它需要额外的计算才能射向十字准线。
仍然在BP_Player Blueprint Class中,创建一个GetWorldLocation (FpsCamera)。
接下来,需要向 FpsCamera添加一个GetForwardVector 。从 FpsCamera单击并拖动并键入**getforwardvector。
现在,需要结束位置。枪支有一个MaxBulletDistance变量,因此结束位置必须是距离相机的MaxBulletDistance单位。单击EquippedGun变量并将其拖到蓝图图表中,然后单击并拖出该节点。然后,键入Max Bullet Distance,并在窗口中选择它。要执行所需的数学计算,从Max Bullet Distance中单击并拖动*,键入以创建乘法节点,从乘法节点单击并拖动并键入**+以创建加法节点。该过程应如下所示:
然后,通过连接节点完成:
之后,连接一切:
所以,总结一下:
- 当玩家按下或按住左键单击时,枪从相机开始发射子弹。
- 子弹向前行进由MaxBulletDistance指定的距离。
单击“编译”,然后按“播放”。按住左键开始射击。
目前,枪在每一帧中射击。这太快了,所以下一步是降低枪的射速。
降低射速
首先,需要一个变量来决定玩家是否可以射击。打开BP_Player并创建一个名为CanShoot的**布尔变量。将其默认值设置为true。如果CanShoot等于true,则玩家可以射击,反之亦然。
将CanShoot变量拖到蓝图图中并放置一个节点以获取其值。从此变量单击并拖动,键入**AND,然后选择相应的逻辑运算。将分支部分更改为:
现在,玩家只能在按下Shoot键**且 CanShoot等于true时进行射击。
枪射击后,需要冷却时间。因此,需要在Shoot功能之后添加更多节点。为此,单击并拖动Shoot*函数调用上的箭头,然后键入*CanShoot*以添加*SetCanShoot*节点。确保未选中此节点上的复选框以将变量设置为 false。接下来,*单击并*从*SetCanShoot*箭头拖动,添加一个*Delay*节点和一个*SetCanShoot*节点。现在,确保选中复选框以将变量设置为 true,从而允许发射下一枪。还记得枪有一个*FireRate*变量吗?获取*射速*从*EquippedGun获取变量的方式与获取MaxBulletDistance 的方式相同。最终结果应如下所示:
刚刚进行了以下更改:
- 玩家只有在按住左键单击且CanShoot等于true时才能射击。
- 玩家发射子弹后,CanShoot将设置为false。这可以防止玩家再次射击。
- CanShoot在**FireRate提供的持续时间后设置回true。
单击Compile,然后关闭BP_Player。按Play并测试新的射速。
接下来,将通过对目标和按钮施加伤害来使它们响应子弹。
施加伤害
在 Unreal 中,每个演员都有能力受到伤害。但是,由决定演员如何回应。
例如,当受到伤害时,格斗游戏角色会失去健康。但是,像气球这样的东西不会有生命值——你可以将它编程为在受到伤害时弹出。
在处理演员如何受到伤害之前,首先需要应用伤害。打开BP_BaseGun ,并在**Shoot函数的末尾添加Apply Damage。
接下来,需要指定被线迹击中的演员应该受到伤害。将Damaged Actor连接到Break Hit Result的Hit Actor。
最后,需要指定要应用多少损坏。获取对Damage 的引用并将其连接到Base Damage。
现在,当调用Shoot时,它会损坏任何被线迹击中的演员。单击Compile,然后关闭BP_BaseGun。
现在,需要处理每个演员如何受到伤害。
处理损坏
首先,将处理目标如何受到伤害。打开BP_Target,并创建一个事件 AnyDamage。只要演员受到不为零的伤害,就会执行此事件。
接下来,调用TakeDamage函数并连接Damage引脚。这将从目标的健康变量中减去健康并更新目标的颜色。
现在,当目标受到伤害时,它会失去生命值。单击Compile,然后关闭BP_Target。
接下来,需要处理按钮如何受到损坏。打开BP_ResetButton并创建一个事件 AnyDamage。然后,调用ResetTargets函数。
当按钮受到损坏时,这会重置所有目标。单击Compile,然后关闭BP_ResetButton。
按播放键,开始射击目标。要重置目标,请按下按钮。