虚幻引擎C++学习笔记(二)
五、创建项目
1.创建默认C++空白项目,并重命名项目名称。
2.在Content目录中创建_Game文件夹(下划线开头可避免字母顺序排列)。
3._Game文件夹内创建Character、GameMode、Maps文件夹。
4.保存当前场景至Maps中,重命名DefalutMap。
5.Settings-项目设置(ProjectSettings)-Maps&Modes-Defalut Maps-Editor Startup Map与Game Default Map选择你保存的DefalutMap。
6.进入C++ Classes文件夹,以系统生成的GameModeBase基础上右键点击,创建蓝图于GameMode文件夹中,重命名GameModeBaseBP(BP表示蓝图)。
7.在World Settings-Game Mode设置你创建好的GameModeBaseBP。
8.Settings-项目设置(ProjectSettings)-Maps&Modes-Defalut Mode选择你创建好的ShooterGameModeBaseBP。
9.保存所有(Save All)。
GameMode保存了你当前关卡(Level)的规则内容,包含了默认Pawn、HUD、Player Controller、Game State、Player State、Spectaor。不同关卡切换可以设置不同的GameMode,达成不同的规则需求(例如开始游戏菜单、多人与单机模式的切换等等)。
六、Character类创建
1.C++ Classes文件夹中创建一个Character类,命名为ShooterCharacter。
2.在ShooterCharacter基础上右键创建蓝图,放入Character文件夹中,并命名为ShooterCharacterBP。
3.打开你创建的ShooterGameModeBaseBP,在Classes-Default Pawn Class中选择ShooterCharacterBP,编译保存。
4.Visual Studio的编译快捷键为:Ctrl+Shift+B。
七、调试语句(UE_LOG)
在开发过程中,使用调试语句是十分重要的。使用UE_LOG宏可以在编辑器Output Log窗口看到你在代码中打印的信息。
CategoryName:使用之前需要先定义Log Category,Category会在Log中体现出来,以便在茫茫Log中更容易区分其作用或所属模块。
Verbosity:ELogVerbosity中定义的枚举,在输出窗口中显示不同的颜色来代表不同语义,例如Log、Warning、All等。
Format:输出内容,并可以使用标准格式化输出下一参数,如%d、%f、%s等。如果传入引擎的FString类型的参数,需要加上*号重载。例如:
八、摄像机摇杆创建
SpringArmComponent相当于我们的手机自拍杆或摄像机的机械臂,方便我们调整摄像机的视角,其他引擎要实现这项功能需要自己搭建,而虚幻引擎却已经帮我们写好这项功能。
1.在我们ShooterCharacter的头文件的私有区域写入声明。
变量的开头需要写class来编译器承诺这个组件确实存在,否则编译器会报错。
2.在公有区域写一个getter函数,方便外部获取这个组件。
像这样获取内容的简单函数(函数内部无其他操作,无循环),我们可以在开头写FORCEINLINE讲此函数转为内联函数。内联函数是C++内置的特性,可以将命令编译器跳过一般的ROI 分析(Return On Investment),提高函数的执行效率。在有写时候,编译器会拒绝将一个函数内联,所以加上FORCE可以强行内联。
需要强调的是,内联函数不适合内部代码较长或者存在循环操作的函数,因为导致内存消耗代价较高与调用开销加大。
3.使用UPROPERTY给CameraBoom进行标记,使其暴露给蓝图中。
meta = (AllowPrivateAccess = "true")可以将一个私有变量公开给蓝图,如果不写此句私有变量是不允许被暴露给蓝图的,会造成编译报错。
4.之前向编译器承诺CameraBoom存在,那现在就要实现它。在cpp文件的构造函数内创建CameraBoom。
5.在文件头部添加USpringArmComponent的头文件。
6.头文件地址寻找有两种方法:
①在解决方案资源管理器窗口中搜索组件名称(去掉首字母),并加上.h后缀,点击头文件在属性窗口查看(F4快捷键)。
②在官方API文档中直接搜索组件名称,复制include的代码。地址:
https://docs.unrealengine.com/4.27/en-US/API/
7.编译保存,打开角色蓝图,可以看到摄像机摇杆CameraBoom已经被创建,并且在蓝图详情中看到该属性,且不可被编辑修改。
九、跟随摄像机创建
前面摄像机摇杆创建好之后,加下来就是创建摄像机了。
1.在头文件声明FollowCamera变量与返回函数,正如声明CameraBoom时一样。
2.在构造函数中实现你声明的变量。
3.别忘了引入CameraComponent的头文件。
4.编译保存,打开角色蓝图,可以看到摄像机安装到摇杆上了。
十、控制器(Controller)
[官方文档] https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/GameFramework/AController/
1.控制器Controller是一个不可见、无位置、有方向(一些函数可以获取和设置控制器的旋转)的实体。它可以控制Pawn,从而控制其动作的非实体Actor。
2.我们可以通过控制器的旋转信息(FRotator)来计算得出控制器的方向向量(FVector)。
3.控制器的工作流:用户—>输入鼠标键盘—>控制器—>移动组件—>角色。
十一、实现角色移动
创建输入映射
1.我们需要创建角色移动的操作指令,这里包括键盘与手柄的输入:
Project Setting—Input—Bindings—Axis Mappings—创建MoveForward与MoveRight两个输入映射。
2.使用键盘WASD与手柄的Left Thumbstick X/Y-Axis进行控制绑定。
3.这里使用Axis轴映射而非Action是因为角色需要每帧都接受玩家的输入信息,从而实现即时的控制转向。
控制器控制移动组件
1.打开角色代码,声明控制函数。
2.实现声明函数。
3.实现移动组件的执行。
4.编译保存,测试角色水平方向的移动。
十二、每帧时间(DeltaTime)
DeltaTime:两帧之间的时长。
Frame:帧,一张图片在屏幕中刷新。这是比秒更小的计量单位,程序以每帧进行画面渲染(通常60FPS或120FPS才能保证我们感到画面流畅)。
Frame Rate(FPS):帧率,每秒刷新的帧数。这个数值是不断变动的,帧率越高说明画面越流畅,硬件越稳定帧率变动也越稳定。
Tick:与帧是同义词,函数Tick里执行的事情等同于每帧执行的事情。
帧率并不是一个固定的数值,这影响我们开发的指定性。例如我们需要让物体每秒1cm地进行移动,这时我们就应该这样处理:
为了解决这种问题,Tick函数提供了DeltaTime,方便我们完成需求:
推导过程:
十三、实现角色转向
创建输入映射
1.我们需要创建角色移动的操作指令,这里包括键盘与手柄的输入:
Project Setting—Input—Bindings—Axis Mappings—创建TurnRightRate与LookUpRate两个输入映射。
2.使用键盘上下左右反向键与手柄的Right Thumbstick X/Y-Axis进行控制绑定。
3.这里使用Axis轴映射而非Action是因为角色需要每帧都接受玩家的输入信息,从而实现即时的控制转向。
控制器控制移动组件
1.打开角色代码,声明控制函数。
2.声明基础转向速率。
3.实现声明函数。
4.实现移动组件的执行。
5.编译保存,测试角色的转向功能。
十四、实现鼠标旋转与角色跳跃
鼠标旋转控制视野
1.Project Setting—Input—Bindings—Axis Mappings—创建MouseTurn与MouseLookUp两个输入映射。
2.分别绑定Mouse X/Y鼠标输入,其中MouseY输入值需改为-1适应玩家控制习惯。
3.代码绑定,编译测试。
角色跳跃
1.Project Setting—Input—Bindings—Action Mappings—创建Jump输入映射。
2.绑定空格键与手柄Face Button Bottom。
3.代码绑定,编译测试。
1.打开虚幻商城(Marketplace),搜索Paragon,免费下载你喜欢的角色模型资产包。当然你也可以添加自己准备好的角色模型。
2.打开角色蓝图ShooterGameModeBaseBP,点击Mesh加载你下载的模型。
3.虚幻引擎的游戏对象是以X轴方向为正方向,需要把角色的面向对准X轴方向。
4.把模型位置下拉到与胶囊体平齐,胶囊体要刚好覆盖模型。