张玉婷
(南京传媒学院传媒技术学院,南京 210000)
Unreal Engine 5 虚幻引擎(UE5)广泛应用在游戏、影视、建筑、汽车与运输等行业中。将UE5 和Visual Studio(VS)结合,可以方便快捷地编写代码、编译程序,设计开发出诸如动作、冒险、解密、RPG 等多种类型的电子游戏[1]。本文介绍一款第一人称射击类游戏(FPS)的开发思路。玩家在第一人称视角下,通过鼠标键盘操作,游戏中的角色手持武器射出发射物,击倒目标物体。
游戏开发的流程是首先在UE5 中新建项目,为项目添加C++代码。通过创建第一人称角色的动作轴映射,实现角色移动、旋转、抬头、低头和跳跃的动作。再为角色创建蓝图动画,添加动画状态机。通过在VS 中编写代码,实现用鼠标对摄像机的控制和游戏指令输入[2]。最后导入发射物网格体,设置发射物的碰撞和生命周期,再添加代码实现对目标的射击。
启动UE5 虚幻引擎新建游戏项目,选择Blank template,项目类型改为C++,确定选择No Starter Content。在Content Browser 的Content的空白处单击鼠标右键,创建新文件夹,用来存放游戏相关的文件,命名为MyGame。在Edit菜单中打开Project Settings,在左侧选项卡的Project 中点击Maps & Modes,在Editor Startup Map 下拉菜单下选择MyGame,保存并退出设置。接着在Tools 菜单中选择Open Visual Studio打开C++代码。项目启动之后,在Solution Explorer里会看到.cpp 和.h 文件,编写的代码将存放在这些文件中。
本游戏使用C++类向导将需要创建的角色类添加到项目中。在UE5 引擎界面的Tools 菜单中选择New C++ Class...,创建新的父类。在Choose Parent Class 中选择Character,新的类命名为MyCharacter,点击Create Class。在VS 的Solution Explorer 中,依次打开MyProject 里面的Source的FPSProject。在VS中添加如下代码:
Void AFPSCharacter::SetupPlayerInputComponent(UInputComponent*PlayerInputComponent)
Super::SetupPlayerInputComponent(PlayerInputComponent);
鼠标右键点击MyProject,选择Build 编译项目。再返回虚幻编辑器,新编译的MyCharacter类在Content Browser中就创建完成了。
FPS游戏需要两个分开的网格体代替玩家角色。其中一个全身网格体作为玩家躯体,用于从第三人称视角观察角色。当玩家以第一人称视角进行游戏时,全身网格体是隐藏的。通过设置轴映射、执行代码,实现角色前后左右移动和跳跃的动作。
由于角色类已创建了SkeletalMeshComponent 对象,因此只需要导入已有的SkeletalMesh资产。鼠标右键单击Content 的空白处,打开Import Asset 对话框。点击Import to 中的Game...,打开Import。选择已创建好的MyPeople.fbx 骨骼网格体文件,点击Open,在FBX Import Options对话框中依次点击Import All 和Save,将网格体添加到项目中。
在Content的Blueprints中,双击BP_MyCharacter蓝图类,在蓝图编辑器的Components 选项卡中点击Mesh 组件。在右侧的Details 选项卡的Mesh 里Skeletal Mesh 行的下拉列表中选择无,然后选择MyPeople 骨骼网格体。在Details 的Transform 中将变换的Z轴向位置设置为-70,使SkeletalMeshComponent与CapsuleComponent对齐。
除了全身网格体,第一人称射击类游戏还需要有代表武器和手部的网格体。这个网格体通常附着到摄像机,并且仅当玩家以第一人称视角查看游戏时才对玩家可见。
右键点击内容浏览器的文件框,打开Import Asset对话框。点击Import to的Game...,在Import对话框中找到并选择MyArm.fbx网格体文件,点击Open 将网格体导入到项目中。在FBX Import Options 对话框中将Skeleton 设置为None,然后点击Import All。
打开BP_MyCharacter 蓝图编辑器,在Components 选项卡中找到FPSMesh 组件。在Details选项卡的Mesh条目中点击显示为None的下拉菜单,选择MyArm 骨骼网格体,将手臂添加到Viewport。接着创建网格体组件,并附加到FPS摄像机,变换属性设置为在摄像机前面,Location设置为220,0,35,Rotation设置为180,50,180。在VS中添加如下代码:
FPSMesh=CreateDefaultSubobject<USkeletalMesh-Component>(TEXT(“FirstPersonMesh”));
check(FPSMesh!=nullptr);
FPSMesh->SetupAttachment(FPSCameraComponent);
轴映射是将键盘、鼠标和控制器的输入映射到游戏中,绑定到游戏角色的某个动作上。轴映射中常见的就是通过输入WASD 键或箭头键,控制角色自由地向前后左右移动,触发游戏行为。在UE5 中打开项目,在Edit 菜单中点击Project Settings,在选项卡左侧的Engine 标题栏下点击Input。在Bindings 中点击Axis Mappings 旁边的+号,点击Axis Mappings 左侧的箭头,在文本框中输入MoveForward,然后点击左侧箭头,在下拉菜单中选择W。点击MoveForward 旁边的+号,在第二个下拉菜单中从Keyboard 下拉列表中选择S,在S 旁边的Scale 字段中输入-1。
在典型的第一人称游戏控制模式中,角色的移动是相对于摄像机的。因此需要使用PlayerController 获取角色的控制旋转输入值。MoveForward 函数将忽略控制旋转输入值的Pitch分量,将输入限制在XY 平面上,以确保在向上或向下看时,角色将沿着地面移动。在VS 中添加如下代码:
PlayerInputComponent->BindAxis(“MoveForward”,this,&AFPSCharacter::MoveForward);
PlayerInputComponent->BindAxis(“MoveRight”,this,&AFPSCharacter::MoveRight);
在此步骤中,为角色添加能够环顾四周并用鼠标操纵的功能。在Bindings 中,点击Axis Mappings 旁边的+号,点击Axis Mappings 左侧的箭头。在文本框中输入Turn,然后点击左侧的箭头,从Mouse 下拉列表中选择Mouse X。输入scale 的值为1.0,完成转头的轴映射。用同样的方法,在文本输入框中输入LookUp,从Mouse下拉列表中选择Mouse Y,完成抬头低头的轴映射。
接着将摄像机组件附加到胶囊体组件,编写代码将摄像机的位置调整为略高于角色眼睛的位置,同时允许pawn 控制摄像机的旋转。在VS中添加如下代码:
FPSCameraComponent->SetupAttachment(Cast-Checked<USceneComponent,UCapsuleComponent>(GetCapsuleComponent()));
FPSCameraComponent->SetRelativeLocation(FVector(0.0f,0.0f,50.0f+BaseEyeHeight));
FPSCameraComponent->bUsePawnControlRotation=true;
设置完角色后,需要给游戏添加武器和发射物。首先添加射击动作映射,在Edit菜单中点击Project Settings。在Engine 标题栏下选择Input 中的Bindings,点击Action Mappings 旁边的+号。在文本输入框中输入Fire,从Mouse 下拉列表中选择Left Mouse Button。接着添加发射物类,在File 菜单中选择New C++Class...,以选择新的父类。再打开Choose Parent Class 菜单,向下选择Actor 作为父类,然后点击Next,将新类命名为“MyProjectile”,然后点击Create Class。
接着添加发射物移动组件,设置发射物的初始速度和碰撞半径,绑定发射输入操作,定义发射物的生成位置。初始化射击方向上发射物速度的函数,以及枪口相对于摄像机位置的偏移。在VS中添加如下代码:
UPROPERTY(VisibleDefaultsOnly,Category=Projectile)
USphereComponent*CollisionComponent;
CollisionComponent=CreateDefaultSubobject<USphere-Component>(TEXT(“SphereComponent”));
CollisionComponent->InitSphereRadius(15.0f);
void AFPSProjectile::FireInDirection(const FVector&ShootDirection)
ProjectileMovementComponent->Velocity=Shoot-Direction*ProjectileMovementComponent->Initial-Speed;
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=Gameplay)
FVector MuzzleOffset;
首先创建一个球状的网格体作为发射物,鼠标右键单击Content Browser空白处,打开Import Asset 对话框,点击Import to 下的Game...,找到并选择Bool.fbx网格体文件,点击Open,在弹出的对话框中点击Import All,将网格体添加到项目中。导入的网格体可以根据需要设置适合的材质和缩放大小。通过代码实现在枪口位置生成发射物,射击方向略向上倾斜,设置发射物的初始轨迹。在VS中添加如下代码:
FRotator MuzzleRotation=CameraRotation;
MuzzleRotation.Pitch+=10.0f;
UWorld*World=GetWorld();
if(World)
FActorSpawnParameters SpawnParams;
SpawnParams.Owner=this;
SpawnParams.Instigator=GetInstigator();
AFPSProjectile*Projectile=World->SpawnActor<AFPSProjectile>(ProjectileClass,MuzzleLocation,MuzzleRotation,SpawnParams);
if(Projectile)
FVector LaunchDirection=MuzzleRotation.Vector();
Projectile->FireInDirection(LaunchDirection);
本游戏中,发射物在发出后与其他对象碰撞并销毁,输入InitialLifeSpan=3.0f,每个生成的发射物会在三秒后从场景中消失。
在Object Channels 中选择New Object Channel...,创建新碰撞通道。将新碰撞通道命名为“Projectile”,确 保将Default Response 设 置 为Block, 然 后 点 击Accept。 在Preset 中 选 择New...,将新配置文件命名为“Projectile”,并设置碰撞预设,设定发射物与Pawn重叠。
游戏中需要为角色添加一些动画。在Content Browser中单击鼠标右键,选择Import to,在Game 的Animations 中导入角色动画。在弹出的对话框中选择Select Skeleton 标题下的My-Arm_Skeleton,然后点击Import All导入所有动画。
接着创建动画蓝图,在Content 中单击鼠标右键,在Create Advanced Asset 里展开Animation并选择Animation Blueprint。选择AnimInstance作为父类,并选择MyArm_Skeleton 作为目标骨架。双击新动画蓝图打开Blueprint Editor,在My Blueprint 选项卡中点击Add New 按钮,并选择Variable。
将该变量设置为Boolean,并将其命名为“IsRunning”。在My Blueprint 选项卡中,点击Add New 按钮并选择Variable。将该变量设置为Boolean,并将其命名为“IsFalling”。由此添加状态机过渡变量。
接着编辑动画的事件图表,使动画过渡变量在游戏运行时能够正确触发。打开Arms_AnimBP,双击My Blueprint 选项卡中的EventGraph,打开事件图表。在图表中点击右键,弹出Context Menu。在Context Menu 的搜索字段中输入“Update”,然后点击Event Blueprint Update Animation 以添加该节点。Event Blueprint Update Animation 节点用于在每次更新动画时更新状态变量,使变量始终与游戏状态同步。在图表中点击右键,弹出Context Menu。在Context Menu 的搜索字段中输入“Owner”,然后点击Try Get Pawn Owner 以添加该节点。从输出引脚连出引线,并在Context Menu 中选择Cast to Character。将Event Blueprint Update Animation 节点上的输出执行引脚关联到Cast to Character 节点上的输入执行引脚。从As Character 输出引脚连出引线,并选择Get Character Movement。从Character Movement 输出引脚连出引线,并选择Get Movement Mode。从Movement Mode 输出引脚连出 引 线, 并 选 择Equal(Enum)。 将Equal(Enum)节点上的下拉菜单值设置为Falling。按住Alt 键的同时点击My Blueprint 选项卡中的IsFalling,将其拖到图表中,创建一个Set Is Falling 节点。将Cast to Character 节点的未标记输出执行引脚连接到Set Is Falling 节点的输入执行引脚,并将Equal(Enum)节点的输出布尔数据引脚连接到Set Is Falling 节点的输入布尔数据引脚。返回Cast To Character 节点,并从As Character 引脚再次连出引线。这次选择Get Velocity 节点。如果角色不是站立不动,其速度向量的长度将大于零。因此,从Return Value 向量输出引脚连出引线,并选择Vector Length 以将该节点添加到图表。从Return Value 浮点输出引脚连出引线,并选择>(float)节点。按住Alt键的同时点击My Blueprint选项卡中的IsRunning,将其拖到图表中,创建一个Set Is Running 节点。将Set Is Falling 节点的输出执行引脚连接到Set Is Running节点的输入执行引脚,并将>(float)节点的输出布尔引脚连接到Set Is Running 节点的输入布尔引脚。
本文提供了一个第一人称射击类游戏开发的简单创作思路。在实际开发过程中,一款可发售的游戏还需要有地编、特效、动画、交互等多方面的设计和制作。而游戏的趣味性、难易度和竞技性也是开发人员在设计过程中必须思考的问题。更多的创意设计和文化元素,适当的奖励机制和游戏反馈,都可以给玩家带去更好的游戏体验,提升游戏的品质[3]。