1、本文为题主在学习中翻译,同时在UE4.10.2 版本上尝试运行,翻译过程中遇到翻译不出会暂时留白,翻译有误请指出,谢谢!
2、本文在翻译过程中遇到题主不懂的地方可能会添加题主的知识扩展链接。
3、转载请注明出处。谢谢!
4、原文地址:点击打开链接
---------------------------------------------------------------------------------------------
感谢:
在此对题主好友Erin表示感谢。感谢Erin在这一系类中指出并校正有误的地方。
-------------------------------------------------------------------------------------------
第一人称射击C++教程
Warning: This tutorial may be outdated for newer versions of Unreal Engine.
警告:该教程可能不适用新版本虚幻引擎
PS:以下目录默认链接为官网连接,翻译完成后将更改为CSDN上翻译后的博客链接。不便之处,还请原谅。谢谢!
PS:已更改为翻译后CSDN博客链接。
PS:所有章节已整合在一起。
PS:该教程适合入门,涉及到了C++、蓝图、碰撞、动画等知识,按照该教程,可初步熟悉UE4引擎。
Over the course of this tutorial, you will transform a blank project template into the beginnings of a first-person shooter, with a character that moves and strafes, camera control, and projectiles you can fire at the environment. Using C++, you will create a GameMode, Character and HUD.
本教程中,你会从一个空白的项目模板入手,从而开始第一人称射击,在该环境中包括了角色的移动和扫射、摄像机控制,以及你可以开火的子弹。使用C++,你可以创建GameMode、角色和HUD。
---------------------------------------------------------------------------------------------
We will create a blank project as the starting point for our FPS game, using Unreal Engine 4's Project Browser.
我们将使用UE4的项目浏览器,新建空项目作为我们FPS游戏的初始点。
1. Open Unreal Editor.
打来虚幻编辑器。
2. In the Project Browser, click on the New Project tab.
在项目浏览器中点击NewProject标签页。
3. Select the Blank project.
选择Blank project。
4. Name the project FPSProject and uncheck the Copy starter content into new project? checkbox. (Uncheck "Include starter content checkbox" for UE 4.2.0)
项目名命名为FPSProject,不勾选Copy starter content into new project?选项框。(PS:UE4.10选择"without starter content")
Note that some of the code samples provided in this tutorial will require alteration if the project's name is different, and we will make note of that at the appropriate step.
要的注意的是,如果项目名不一样的话,则需要改变本教程提供的一些代码样本,我们会在相应步骤进行注释。
5. Click on Create.
点击Create。
6. Your project is now open in Unreal Editor. You can play in the starting level by clicking on the Play In button in the Level Editor Toolbar. The WASD keys will allow you to fly around within the level, and the mouse will aim your camera. Press Escape when you are ready to exit Play in Editor (PIE) mode.
现在,你的工程已经在虚幻编辑器打开。你可以点击关卡编辑工具栏上的Play按键从而在开始关卡中玩耍了。其中WASD按键可以让你在关卡中飞行,鼠标可以移动你的相机视角。按下Escape即可退出PIE模式。
7. Create a Maps folder within the Content folder.
在Content文件夹下新建Maps文件夹。
8. In the File menu, select Save as... to save your map as FPSMap within the Maps folder.
在File 菜单中选择Save as... 将你的map命名为FPSMap保存到Maps文件夹下
9. In the Edit menu, click on Project Settings.
在Edit 菜单中,选择Project Settings。
10. Under the Game heading on the left side of the Project Settings tab, click on Maps & Modes.
在Project Settings 标签左侧Game标题下,点击。Maps & Modes
11. Using the dropdown, select FPSMap as the Editor Startup Map. Now, whenever you re-open your project in the editor, you will automatically load this map.
使用下拉,选择FPSMap作为Editor Startup Map。现在,无论你何时在编辑器中重启你的项目,都会自动加载该map。
12. Close the Project Settings menu.
关闭Project Settings菜单
---------------------------------------------
Let's create a GameMode. A GameMode contains the definition of the game itself, such as game rules, win conditions, etc. It also sets the default classes to use for some basic gameplay framework types, including Pawn, PlayerController, and HUD. Before we set up our FPS character, we need to create the GameMode that will reference it.
创建GameMode。GameMode包含了游戏本身的定义,如游戏规则,过关条件等等。它还为游戏架构类型设置了默认类,包括Pawn, PlayerController, and HUD。在我们创建我们的FPS角色之前,我们需要创建一个与之相关的GameMode。
First, we are going to use the C++ Class Wizard to add a new class to our project.
首先,我们将使用C++类向导为项目添加一个类。
1.In the File menu, select Add Code to Project.
在File菜单中,选择Add Code to Project。
2. Scroll down and select GameMode as the parent class. Click Next.
向下滚动,选择GameMode作为父类,点击Next.
3. Name the new class FPSGameMode, then click Create.
类名命名为FPSGameMode,点击Create。
4. Click on Yes to open the class in Visual Studio or XCode for editing.
点击Yes在VS或XCode中打开进行编辑。
Since this is the first code we've added to the project, the wizard will also create the initial files needed to compile and run our project.
由于这是我们添加到项目中的第一个代码,该向导还将创建项目编译和运行所需的初始文件。
We will add a log message to the FPSGameMode, so that when we start playing in our level, we can see that we are actually using our new GameMode. We will add code to FPSGameMode's constructor, so that it will run when gameplay begins.
我们将为FPSGameMode添加一个日志信息,这样当我们开始在我们的关卡中运行的时候,我们可以看到,我们实际上是在使用新的GameMode。我们将代码添加到FPSGameMode构造函数中,这样它会游戏开始时运行。
1. Your code IDE will open.
打开你的代码编辑器。
2. In the Solution Explorer, expand FPSProject > Source > FPSProject.
在Solution Explorer中,按FPSProject > Source > FPSProject扩展开。
3. Here, you will see the header file for your new FPSGameMode class, FPSGameMode.h. Double-click it to open it for editing.
在这里,你会看到你新建类FPSGameMode的头文件——FPSGameMode.h。双击打开。
4. Find the class declaration, which looks like:
找到类声明,如下:
UCLASS() class FPSPROJECT_API AFPSGameMode : public AGameMode { GENERATED_BODY() };
5. Under GENERATED_BODY()
, add the following lines then save the file.
在GENERATED_BODY()下,添加下面代码后保存
virtual void StartPlay() override; // Note that engine version 4.3 changed this method's name to StartPlay(), because of this engine versions before 4.3, or older tutorials, use BeginPlay()
This function declaration will allow you to override the StartPlay() function inherited from the `AActor` class, so that you can print a message to the screen when gameplay begins.
该函数声明将重写继承自 'AActor' 的StartPlay()函数,因此你可以在游戏开始时在屏幕上输出消息。
Note: 4.6 needs below line to be included (before or after StartPlay(). This is the definition of constructor whose signature is also different from older versions.
注意:4.6需要加入以下代码(在StartPlay()之前之后,这是与旧版本签名不同的构造函数的定义)
AFPSGameMode(const FObjectInitializer& ObjectInitializer);
6. Open FPSGameMode.cpp. It is located in FPSProject > Source > FPSProject as well.
打开FPSGameMode.cpp,它同样位于FPSProject > Source > FPSProject。
If your project has a different name, your code will be located in [ProjectName] > Source > [ModuleName]. The module name is the same as your project name because you used the C++ Class Wizard.
如果你有不同的项目名,你的代码将位于 [ProjectName] > Source > [ModuleName].模块名和你的项目名一致,因为你是用的C++类向导。
First, at the top of the file, add the following line under the other #include lines:
首先,在文件的开头,包含如下头文件
#include "Engine.h" //for version 4.4+ // Note that this may no longer be necessary as this file will likely already include [ProjectName].h, which, by default, will include "Engine.h" itself
7. Find FPSGameMode's constructor. It looks like:
找到FPSGameMode的构造函数,如下:
Note: In 4.6 this is no longer correct as the procedure for constructors has changed, you will not find this code. You will need to write the following line of code in if it is not present For users of previous versions, FPostConstructInitializeProperties is replaced with FObjectInitializer and variable name PCIP with ObjectInitializer (though variable name can be anything, its recommended to change as a good practice)
注意:在4.6这不再正确,因为构造函数的程序已改变。你不会找到这条代码。如果它不存在,你需要编写以下代码。对于以前版本的用户,FPostConstructInitializeProperties已替换为FObjectInitializer,且变量名由PCIP替换为ObjectInitializer(虽然变量名可以是任何东西,它推荐的做法更为妥当)
AFPSGameMode::AFPSGameMode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }The prefixed name of FPSGameMode is AFPSGameMode, because it derives from a class which eventually derives from the Actor class.
FPSGameMode 的前缀名为 AFPSGameMode,因为他的父类继承与Actor类
8. After the constructor, add the following lines, then save the file.
在构造函数后面,添加以下代码并保存。
// Note that engine version 4.3 changed the method's name to StartPlay(), because of this engine versions before 4.3, or older tutorials, use BeginPlay() void AFPSGameMode::StartPlay() { Super::StartPlay(); StartMatch(); if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("HELLO WORLD")); } }
This function definition will print "HELLO WORLD" to the screen in yellow text when gameplay begins.
在游戏开始时,该函数将在屏幕上打印出黄色文本"HELLO WORLD"。
We will now compile our project, so that we can see our code changes reflected in the game. If you are using Unreal 4.6 or below, you need to close the editor, compile, and then reopen the project in the editor to reload the game module.现在编译我们的项目,这样就可以在游戏中我们
代码实现。如果你使用4.6或更低版本,你需要关掉编辑器,编译,然后在编辑器重启项目或则重新加入游戏模块。(PS:入门4.10,表示不需要……^_^)。
1. If you are using Visual Studio, make sure that you have set up Visual Studio for compiling with Unreal Engine.
如果你使用VS,确保你设置了VS可为UE编译。
2. Close Unreal Editor. (Not required in 4.7)
关掉虚幻编辑器(4.7不需要,PS:4.10同样不要)。
3. Compile.
编译。
4. After the build finishes, open Unreal Editor, and then open FPSProject.
完成build,打开FPSProject项目。
We need to set the project to use FPSGameMode as the default GameMode.
我们需要在项目中将FPSGameMode设置为默认的GameMode.
1. In the Edit menu, click on Project Settings.
Edit -> Project Settings.
2. Under the Game heading on the left side of the Project Settings tab, click on Maps & Modes.
在Project Settings 标签左侧Game标题下,点击。Maps & Modes
3. Select FPSGameMode in the Default GameMode dropdown.
在Default GameMode下拉列表中选择FPSGameMode
4. Close the Project Settings menu.
关闭Project Settings 菜单。
5. Click on the Play In button in the Level Editor Toolbar. "HELLO WORLD" should be displayed in the upper left corner of the viewport.
点击Play.Viewport左上角出现"HELLO WORLD"。
You can also look in the Scene Outliner while your game is running to see FPSGameMode listed.
游戏运行时,在Scene Outliner 中可以看到FPSGameMode .
6. Press Escape to exit Play in Editor (PIE) mode.
按下Escape退出PIE模式
--------------------------------------------------------------------------------------------------------------
PS:按照以上教程,题主在UE4.10.2版本中实现上述功能。
附代码.h
The engine has a built-in class called DefaultPawn which is a Pawn with some simple disembodied flying movement. We want to have a human-like avatar walking on the ground, so let's create our own Pawn to control. The engine includes a class for this called Character, which derives from Pawn but has built in functionality for bipedal movement like walking, running, and jumping. We will use Character as the base class for our FPS Pawn.
引擎有一个内置的DefaultPawn类,它是一个可简单飞行运动的Pawn。我们希望有类似人类行走的avatar,那么就创建一个可控制的Pawn把。引擎含有一个叫做Character的类,它继承自Pawn,但是具有类似行走、跳跃的双足运动功能,我们将使用Character作为FPS Pawn的基类
Again, we will use the C++ Class Wizard to add this new class to our project. It is possible to manually add the *.h and *.cpp files to your Visual Studio solution to add new classes, but the C++ Class Wizard fills in header and source templates which set up the Unreal-specific macros for us, which simplifies the process.
接着,我们使用C++类向导新建类到我们的项目中。可以手动添加Visual Studio
1. In the File menu, select Add Code to Project.
在File菜单中,选择 Add Code to Project.
2. Scroll down and select Character as the parent class. Click Next.
下滑选择Character 作为基类,点击Next。
3. Name the new class FPSCharacter, then click Create.
新类命名为FPSCharacter,点击Create。
4. Click on Yes to open the class in Visual Studio for editing.
点击Yes并在VS中打开类。
5. Visual Studio will prompt you asking to reload the project, since the C++ Class Wizard modified it. Select Reload.
Visual Studio会提示你是否重新加载项目,由于C ++类向导修改了它,因此选择刷新。
First, we will edit our GameMode, so that FPSCharacter is the default Pawn used when starting gameplay.
首先,我们编辑GameMode,从而开始游戏时FPSCharacter作为被使用的默认Pawn.
1. First go to FPSGameMode.h. Below GENERATED_BODY() we will now add a constructor for the class, the following will be what our class looks like now (Engine Version 4.6).
首先前往GENERATED_BODY() 下为类添加构造函数,以下就是我们的程序(UE4.6)
UCLASS() class FPSPROJECT_API AFPSGameMode : public AGameMode { GENERATED_BODY() AFPSGameMode(const FObjectInitializer& ObjectInitializer); // Our added constructor virtual void StartPlay() override; };
2. Return to FPSGameMode.cpp. First, at the top of the file, add the following line under the other #include lines:
返回FPSGameMode.cpp。首先,在文件顶部其他的#include下添加下面的的头文件
#include "FPSCharacter.h"
3. Then, we will find the constructor we previously added in FPSGameMode.cpp:
接着,找到我们之前在FPSGameMode.cpp添加的构造函数。
AFPSGameMode::AFPSGameMode(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
4. And following that we add the following line to the constructor:
在构造函数添加下面的代码
DefaultPawnClass = AFPSCharacter::StaticClass();
This tells the GameMode which type of Pawn to spawn for the player when starting the game.
它会告诉GameMode在游戏启动时那种类型的Pawn会生成给玩家(PS:spawn for不知道怎么翻译好)
The constructor for FPSGameMode will now look like:
现在FPSGameMode的构造函数是这样的:
AFPSGameMode::AFPSGameMode(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DefaultPawnClass = AFPSCharacter::StaticClass(); }
Now, save the files.
现在,保存文件。
Let's also add an on-screen message to FPSCharacter, so we can be sure our new class is being used properly.
让我们也给FPSCharacter添加一个屏幕消息,以确保我么的新类被正确使用。
1. Open FPSCharacter.h. It is located in FPSProject > Source > FPSProject.
打开FPSCharacter.h,它位于 FPSProject > Source > FPSProject.
If your project has a different name, your code will be located in [ProjectName] > Source > [ModuleName]. The module name is the same as your project name because you used the C++ Class Wizard.
如果你的项目名和教程不同,你的代码会位于[项目名] > Source > [模块名],项目名与模块名一致。
2. Find the class declaration, which looks like:
找到类声明,类似这样:
class FPSPROJECT_API AFPSCharacter : public ACharacter { GENERATED_BODY() };
3. Under GENERATED_BODY()
, add the following line, then save the file.
在GENERATED_BODY()下,添加以下代码:
virtual void BeginPlay() override;
This function declaration will allow you to override the BeginPlay() function inherited from the AActor class, so that you can print a message to the screen when gameplay begins.
这个函数声明允许你重写继承自AActor的BeginPlay()函数,从而在启动游戏时屏幕输出消息。
4. Now open FPSCharacter.cpp and add the following lines, then save the file.
打开FPSCharacter.cpp,添加下面代码并保存。
void AFPSCharacter::BeginPlay() { Super::BeginPlay(); if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("We are using FPSCharacter!")); } }
This function definition will print "We are using FPSCharacter!" to the screen in blue text when gameplay begins.
游戏启动时,该函数会在屏幕显示蓝色文本"We are using FPSCharacter!"
We will again close the editor and compile our project, so that we can see our code changes reflected in the game. (Note that you should be able to hot-reload if you are using the latest engine version, which means you can compile without closing the Unreal Editor.)
关掉编辑器编译项目,可以在游戏中反映出代码的改变。
1. Close Unreal Editor.
关掉虚幻编辑器
2. Compile.
编译(PS:4.10版本可直接编译,因为它具有热更新功能)
3. After the build finishes, open Unreal Editor, and then open FPSProject.
编译完成后,打开虚幻编辑器,打开FPSProject.
4. Click on the Play In button in the Level Editor Toolbar. Your new Character does not have any movement controls yet, so you will not be able to move around in the level. So, if you are stuck and unable to move, you are using the FPSCharacter as your Pawn correctly! Your log message should also be displayed on the screen.
点击Play.你的Character还没有运动控制,所以你还不能在关卡中移动。所以如果你动不了,便表示正确使用了作为Pawn的FPSCharacter.你的日志消息也会显示在屏幕上。(PS:以后类似点击关卡编辑工具栏上的Play按键就直接说点击Play了,这几个章节用下来,基本上能找到哪里是哪里,就不再赘述了。)
You can also look in the Scene Outliner while your game is running to see FPSCharacter listed.
5. Press Escape to exit Play in Editor (PIE) mode.
Esc退出。
---------------------------------------------------------
4.10上运行,源码如下(PS:题主GameMode类命名为MyFPSProjectGameMode了)
MyFPSProjectGameMode.h
--------------------------------------------------------------------------------------------------------------
Let's get our new Character moving around.
让我们的新角色遛起来。
We will go through specifics of input processing in the next several steps, but you may also find the general overview of input framework useful to refer to.
我们将在接下来的几个步骤了解input(输入)细节,但你也会发现input框架的概述值得去参考(PS:这里可能是说参考官方说明文档)。
The input controls for walking around in the world, such as WASD or arrow keys, are usually set up with axis mappings.
如WASD或者方向键的行动输入控制,通常设置了轴映射。
Map keyboard, controller, or mouse inputs to a "friendly name" that will later be bound to continuous game behavior, such as movement. The inputs mapped in AxisMappings are continuously polled, even if they are just reporting that their input value is currently zero. This allows for smooth transitions in movement or other game behavior, rather than the discrete game events triggered by inputs in ActionMappings. Hardware axes, such as controller joysticks, provide degrees of input, rather than discrete 1 (pressed) or 0 (not pressed) input. That is, they can be moved to a small degree or a large degree, and your character's movement can vary accordingly. While these input methods are ideal for providing scalable amounts of movement input, AxisMappings can also map common movement keys, like WASD or Up, Down, Left, Right, to continuously-polled game behavior.
映射键盘、控制器或者输入 到一个“友好名字”将会在之后绑定到连续的游戏行为,比如行动。轴映射中的的输入映射不断轮询,即使他的输入值近乎为0。它允许在运动或其他游戏行为中平滑过渡,而不是由ActionMappings中的输入触发的离散游戏事件。如摇杆控制器提供了输入量而不是离散的1(按下)或0(抬起)输入。也就是说,它们可大可小,而你的角色运动速度也会随之而变。虽然这些输入方法很好的提供了可伸缩的运动输入量,但是轴映射也可以映射常见的移动按键,如WASD,上下左右,来不断轮询游戏行为。
First, we will set up axis mappings for the W, A, S, and D keys.
首先,为WASD设置轴映射。
6. Now, click on the plus sign next to MoveForward
点击MoveForward旁边的加号
7. In the second dropdown menu, select S. Type "-1" in the Scale field. Your input settings should now look like the following:
在第一个下拉菜单中选择S,Scale中输入-1,设置如下
8. Under Bindings, click on the plus sign next to Axis Mappings.
点击Axis Mappings旁的加号.
9. Type "MoveRight" into the text field that appears, then click on the arrow to the left of the text box to expand the axis binding options. "MoveRight" .
10. In the dropdown menu, select D. Your input settings should now look like the following:
如添加“W”一样添加“D”.
11. Under Bindings, click on the plus sign next to MoveRight.
点击MoveForward旁边的加号。
12. In the second dropdown menu, select A. Type "-1" in the Scale field. Your input settings should now look like the following:
如添加“S”一样添加“A”.Scale设置-1.
13. Close the Project Settings menu.
关闭 Project Settings。
14. Switch to your project in Visual Studio.
切换到VS。
15. The Character class has a function called SetupPlayerInputComponent that is called when the PlayerController possesses the Character. We will override this function to bind our own handlers for the MoveForward and MoveRight axis mappings.
当PlayerController操纵Character的时候,Character类有一个名为SetupPlayerInputComponent 方法被调用。我们将重写该方法来绑定自己MoveForward 和MoveRight轴映射的处理程序 。
16. In FPSCharacter.h
, add the following declaration under virtual void BeginPlay() override;
:在FPSCharacter.h,在virtual void BeginPlay() override;下一行添加以下声明:
protected: virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;
17. We also want to declare our handler functions, so add these lines under the SetupPlayerInputComponent
declaration inFPSCharacter.h
and save the file.
声明自己的处理方法,在FPSCharacter.h
中SetupPlayerInputComponent声明的下一行添加以下代码,保存。
//handles moving forward/backward UFUNCTION() void MoveForward(float Val); //handles strafing UFUNCTION() void MoveRight(float Val);
UFUNCTION() Macro —— UFUNCTION () 宏
The UFUNCTION macro is used above each of these functions. By itself, the UFUNCTION macro makes the engine aware of these functions, so that they can be included in serialization, optimization, and other engine functionality. You may also have noticed the UCLASS macro above your new FPSGameMode and FPSCharacter class declarations, which does the same thing but for classes, and there is also a UPROPERTY macro for properties. There are a number of specifiers you can supply to these macros to change the function, class, and property behaviors in the engine, which can be found in ObjectBase.h.
UFUNCTION宏被用于上面的每个方法。通过自身,UFUNCTION宏使引擎意识到这些函数的存在,从而使它们可以被包含于序列化、优化和其他引擎功能。你可能也会在上面的FPSGameMode和FPSCharacter类声明中注意到UCLASS宏为类做同样的事情,还有一个针对属性的UPROPERTY宏。有许多修饰符供你提给宏以改变引擎中的方法、类以及属性行为,它们可以在ObjectBase.h找到。
After setting up our function dhoneclarations, we will implement them in FPSCharacter.cpp
.
完成设置我们的方法声明后,我们将在FPSCharacter.cpp实现它们。
1. First, we will define SetupPlayerInputComponent
. The following lines set up the gameplay key bindings. Add them below the constructor in FPSCharacter.cpp
.
首先,定义SetupPlayerInputComponent,下面代码设置游戏案件绑定,将他们添加到FPSCharacter.cpp中的构造函数的下方。
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* InputComponent) { // set up gameplay key bindings InputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward); InputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight); }
An InputComponent is a component that defines how to handle input data and can be attached to an actor that wants to receive input.
输入组件定义了如何处理输入数据,可以被附加到需要接受输入的Actor上。
We also need to implement our MoveForward
and MoveRight
functions. In a typical FPS control scheme, the movement axes are camera-relative. That is, "forward" means "direction the camera is pointing", right means "to the right of the direction the camera is pointing", and so on. We will get the control rotation from the PlayerController. Also, since we want to move along the ground even while we are looking up or down (as opposed to trying to push into the ground), our MoveForward
function will ignore the pitch component of the control rotation and restrict our input to the XY plane.
MoveForward
和 MoveRight
方法。典型的FPS控制方案中,运动轴与相机相对。那就是说,前方代表相机指向的方向,右方代表相机指向方向的右边,以此类推。我们将从PlayerController获取control rotation.同样,由于我们想在向上或向下看时沿着地面移动(而不是试图进入地下),MoveForward
方法将会忽略control rotation的俯仰组件,并且限制我们对XY平面的输入。
FPSCharacter.cpp
:
FPSCharacter.cpp
:
void AFPSCharacter::MoveForward(float Value) { if ( (Controller != NULL) && (Value != 0.0f) ) { // find out which way is forward FRotator Rotation = Controller->GetControlRotation(); // Limit pitch when walking or falling if (GetCharacterMovement()->IsMovingOnGround() || GetCharacterMovement()->IsFalling() ) { Rotation.Pitch = 0.0f; } // add movement in that direction const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X); AddMovementInput(Direction, Value); } }
MoveRight
is very similar, except we will move along a different axis of our control rotation. We also don't need to worry about zeroing the pitch in this case because pitching doesn't affect the Y direction vector. 除了沿着不同的旋转轴移动,MoveRight
代码与之类似。我们无需担心俯仰归零的情况,因为俯仰不影响Y方向向量。
3. Add the following function to FPSCharacter.cpp
:
void AFPSCharacter::MoveRight(float Value) { if ( (Controller != NULL) && (Value != 0.0f) ) { // find out which way is right const FRotator Rotation = Controller->GetControlRotation(); const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::Y); // add movement in that direction AddMovementInput(Direction, Value); } }
以下代码添加到FPSCharacter.cpp
:
Let's test out the Character now, and see how we can move throughout the level.
现在,让我们测试下角色吧,看看我们是如在关卡中移动的。
1. Close Unreal Editor.2. Compile3. After the build finishes, open Unreal Editor, and then open FPSProject.4. Click on the Play In button in the Level Editor Toolbar. You should be able to move and strafe throughout the level, although your camera will be fixed in place.5. Press Escape to exit Play in Editor (PIE) mode.
运行方法如故。
--------------------------------------------------------------------------------------------------------------4.10 运行成功。
代码如下:
FPSCharacter.h
----------------------------------------------------------------------------------------------------
Let's add the ability to look around and steer with the mouse.
让我们添加拖动鼠标,环顾四周的功能吧。
First, let's set up axis mappings for Turn and LookUp.
首先,为 Turn 和 LookUp设置轴映射。
1. In the Edit menu, click on Project Settings.
进入Project Settings。
2. Under the Engine heading on the left side of the Project Settings tab, click on Input.
在Project Settings中选择Input。
3. Under Bindings, click on the plus sign next to Axis Mappings.
在bingding下点击加号添加轴映射。
4. Type "Turn" into the text field that appears, then click on the arrow to the left of the text box to expand the axis binding options.
输入“Turn”文本,点击它左侧的箭头扩展选项。
5. In the dropdown menu, select MouseX.
下拉菜单中选择MouseX。
6. Under Bindings, click on the plus sign next to Axis Mappings.
点击Axis Mappings旁边的加号。
7. Type "LookUp" into the text field that appears, then click on the arrow to the left of the text box to expand the axis binding options.
类似“Turn”设置“LookUp”.
8. In the dropdown menu, select MouseY and enter "-1" for Scale. Your input settings should now look like the following:
类似MouseX设置MouseY,起值设为-1.设置图如下:
9. Close the Project Settings menu.
关闭Project Settings。
Now, let's add some code to handle those inputs.
现在,为输入控制添加代码。
The Character class defines the two necessary functions for us: AddYawInput
and AddPitchInput
.
Character为我们定义了两个必要的方法:
If we wanted to do additional processing, such as adding support for sensitivity or axis inversion, we could provide our own functions to adjust the values before passing them to these functions, but in this case let's bind our inputs directly to them.
如果我们想添加一些如支持灵敏度和轴反转的处理,我们可以在给这些方法传递参数前提供自己的函数调整这些值,但这种情况我们的输入直接绑定它们。
1. Add the following lines to SetupPlayerInputComponent in FPSCharacter.cpp:
在FPSCharacter.cpp中为SetupPlayerInputComponent添加如下代码:
InputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput); InputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
Because we only changed an existing function instead of making a new function, we can compile within the editor.
由于我们只是改变现有的方法而不是新建一个方法,因此我们可以在编辑器内直接编译(PS:4.10 哪里都可以编译,这里的意思是不用像MoveFoward那样定义方法了。)。
1. Switch back to Unreal Editor, and click on the Compile button.
返回虚幻编辑器点击编译。
2. The Compiling C++ Code notification will pop up in the bottom right of the screen. Wait for it to finish - it will say Compile Complete and then fade out.
屏幕右下角会显示Compiling C++ Code,他将提示Compile Complete并淡出。
3. Click on the Play In button in the Level Editor Toolbar. Now, you can control the camera direction with your mouse.
Play,你可以通过鼠标控制相机方向。
4. Press Escape to exit Play in Editor (PIE) mode.
Esc键退出。
----------------------------------------------------------------------
PS:4.10.2 亲测成功。
--------------------------------------------------------------------------------------------------------------
Now, let's add jumping to our movement abilities. Our movement and camera control steps used axis mappings, which handle continuous inputs needed for those types of controls. There are also action mappings, which deal with inputs for discrete events.
现在,让我们添加跳跃功能吧,我们的运动和相机控制步骤使用了轴映射,他们处理这类控制所需的连续输入。这里还有处理离散事件输入的动作映射。
Map a discrete button or key press to a "friendly name" that will later be bound to event-driven behavior. The end effect is that pressing (and/or releasing) a key, mouse button, or keypad button directly triggers some game behavior.
一个离散按键映射到一个"friendly name" 后将会绑定到事件驱动行为。它导致的结果是,点击(释放)按键、鼠标键或者键盘按键(key)会直接触发一些游戏行为。
Let's add a new action mapping called Jump in the editor.
让我们在编辑器添加一个Jump动作映射。
1. In the Edit menu, click on Project Settings.
打开Project Setting.
2. Under the Engine heading on the left side of the Project Settings tab, click on Input.
选择Input.
3. Under Bindings, click on the plus sign next to Action Mappings.
在Action Mappings旁边点击加号。
4. Click on the arrow to the left of Action Mappings to expand the Action Mappings settings.
点击小箭头扩展动作映射的设置。
5. Type "Jump" in the text field.
输入文本。"Jump"
6. Expand the dropdown, and select Space Bar.
下拉选择Space Bar。
7. Close the Project Settings menu.
关闭Project Settings。
Now we want to bind this action to some code that will cause our character to jump.
现在我么想将动作绑定到可以控制角色跳跃的代码。
If we look at Character.h, we can see there is jump support built in, tied to the bPressedJump variable. So all we need to do is set that flag to 1 when the jump action is pressed, and 0 when it is released. We need two functions to accomplish this.
在Character.h中,我们可以看到Jump已被内置,它绑定在bPressedJump变量。所以我们要做的是在跳跃键按下设置为1,释放按键设置为0。这需要两个方法来完成。
1. In FPSCharacter.h, add the following public function declarations:
在FPSCharacter.h,添加如下方法声明。
//sets jump flag when key is pressed UFUNCTION() void OnStartJump(); //clears jump flag when key is released UFUNCTION() void OnStopJump();
2. In FPSCharacter.cpp, we can implement them very simply:
在FPSCharacter.cpp,简单的实现它们。
void AFPSCharacter::OnStartJump() { bPressedJump = true; } void AFPSCharacter::OnStopJump() { bPressedJump = false; }
Finally, we need to bind the Jump action to our new functions.
最后,我们需要绑定跳跃动作到我们的新方法中。
3. In SetupPlayerInputComponent
, add the following:
在SetupPlayerInputComponent中,添加以下代码:
InputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::OnStartJump); InputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::OnStopJump);
Because we added new functions instead of just altering existing functions like in the previous step, we need to compile in Visual Studio instead of in the editor.
1. Close Unreal Editor.
2. Compile.
3. After the build finishes, open Unreal Editor, and then open FPSProject.
编译方法照旧。
4. Click on the Play In button in the Level Editor Toolbar.
5. Press Spacebar to jump! You should now have a good set of starting movement controls, with WASD moving and strafing, camera control with the mouse, and jumping.
6. Press Escape to exit Play in Editor (PIE) mode.
点击Play。
按下空格键跳跃。到此为止,你会有WASD移动、鼠标控制相机和跳跃功能。
Esc退出
-----------------------------------------------------
4.10亲测可行。
--------------------------------------------------------------------------------------------------------------
Now let's give ourselves a body in the world. The Character class creates a SkeletalMeshComponent object for us by default, so all it needs to know is which SkeletalMesh asset to use. Let's make a Blueprint of our FPSCharacter
class so we can easily set this asset and manipulate any future components we might want to add. We'll start by importing a third person Skeletal Mesh. Eventually, we will set it up so that there is one mesh that the player sees, and one mesh that other players would see in a multiplayer mode.
现在,让我们在虚拟世界中给我们自己添加个身体吧。Character类默认为我们创建了一个SkeletalMeshComponent对象,所以只需知道的是去使用哪种SkeletalMesh资源。让我们为FPSCHaracter类创建一个蓝图,从而让我们可以轻松的设置资源以及操作以后我们想添加的任何组件。
1. Download the following zip file, and unzip it to get the third person mesh file.
下载下面的ZIP文件,解压活得第三人称mesh文件(获取FBX文件)。
Generic Male
2. Open Unreal Editor.
打开虚幻编辑器。
3. Right-click in the Content Browser, and select Import to /Game in the menu that appears.
在Content Browser中右键选择Import to /Game 。
4. Navigate to wherever you saved the FBX file, then select it and click Open.
选择你的FBX后点击打开。
5. Open the Advanced dropdown and check Import Materials, then click on Import.
点击Advanced下拉,勾选Import Materials,。(博主在4.10版本是直接拖拽FBX到Content的,跳出窗口默认选择,然后import.)
6. Click on the Save icon in the Content Browser to save your new Skeletal Mesh and its associated assets.
在 Content Browser点击Save图标来保存你新建的Skeletal Mesh,它会关联资源。
Now, we can create a Blueprint of our FPSCharacter class and assign this new Skeletal Mesh to the SkeletalMeshComponent.
现在,我们可以创建FPSCharacter类的蓝图,指定新建的SkeletalMesh到SkeletalMeshComponent。
1. Right-click in the Content Browser and select New Folder. Name this new folder Blueprints.
在Content Browser 新建名为Blueprints的文件夹。
2. Double-click on the folder to open it.
双击打开文件夹。
3. Click on the New dropdown, and select Blueprint.
点击New,选择Blueprint。(也可以右键选择)
4. Expand the Custom Class dropdown, and type "FPSCharacter" into the search box.
扩展开Custom Class,搜索FPSCharacter。(PS:4.10 的是叫做All Classes)
5. Click on FPSCharacter to select it as the parent class for your new Blueprint and then click on Select.
选择FPSCharacter作为新建蓝图的基类,点击Select.
6. Name this new Blueprint BP_FPSCharacter, then double-click its icon to open it.
蓝图命名为BP_FPSCharacter,双击打开。
The Blueprint Editor will open in Components Mode, so we will be able to easily set our third-person mesh.
蓝图编辑器会以组件模式打开,你可以轻而易举的看到第三人称mesh.(PS:4.10打开蓝图可在左侧上部看到,如下图)
1. Click on the Mesh component in the Components tab.
在component选项卡中点击Mesh组件。
2. In the Details tab, scroll down to the Mesh section. Click on the dropdown that says None, then select your recently imported Skeletal Mesh asset. You may have to resize the Details tab to see this menu.
在Details选项卡,下滑到Mesh部分它显示none.点击下;希腊选择你新导入的Skeletal Mesh资源。你可能需要调整Details 选项卡来看到这个菜单(PS:这里应该是指……还是用图来说明吧,见下图)。
3. Align the SkeletalMeshComponent to the CapsuleComponent by setting its Z location to -88 in the Details tab.
在选项卡中通过设置它的Z值为-88来使SkeletalMeshComponent对齐CapsuleComponent(胶囊体)。
When using your own Skeletal Mesh assets, you may need to adjust them differently, but the overall goal is always to have the mesh contained within the CapsuleComponent, and facing the same direction that the ArrowComponent is pointing. This will ensure that your Character moves correctly through the world. You can also move components around with widgets in the Preview Viewport, rather than setting values in the Details tab.
使用你资源时,你可能需要不同程度上的调整它们,但整体上始终是要包含在CapsuleComponent里面的的,并且面向方向与相同ArrowComponent 。这将确保你的角色在世界中正确移动。你也可以在Viewport中通过坐标移动components,而不仅是在Details选项卡中设置值。
4. Compile and save your Blueprint, then close the Blueprint Editor.
编译并保存你的蓝图,然后关闭。
Now we need to tell our GameMode to use our Blueprint class for the player pawn, instead of the FPSCharacter class we set earlier.
现在我们需要告诉我们的GameMode为玩家pawn使用我们的蓝图类,使其替代早先我们设置的FPSCharacter类。
1. Switch to Visual Studio.
切换到VS。
2. Go to the FPSGameMode constructor in FPSGameMode.cpp, and replace the existing DefaultPawnClass assignment:
进入 FPSGameMode.cpp中的FPSGameMode构造函数,替换DefaultPawnClass的值。
DefaultPawnClass = AFPSCharacter::StaticClass();
with the following code:
使用以下代码:
// set default pawn class to our Blueprinted character static ConstructorHelpers::FClassFinderPlayerPawnObject(TEXT("Pawn'/Game/Blueprints/BP_FPSCharacter.BP_FPSCharacter_C'")); if (PlayerPawnObject.Class != NULL) { DefaultPawnClass = PlayerPawnObject.Class; }
This code will find the class generated by your blueprint and assign it as your default pawn class. (Note the "_C" suffix in the asset path, this is what distinguishes the actual class used by the game from the Blueprint asset, which is an editor-only concept.) At this point, you could also remove the #include "FPSCharacter.h" from the top of FPSGameMode.cpp, since you are no longer referring to the FPSCharacter C++ class.
这些代码会找到你的蓝图产生的类,并使其成为默认的pawn类。(注意资源路径中带“_C”的后缀,这是游戏实际使用的类与蓝图资源之间唯一编辑器原则的区别,PS:这里不大懂。),同时,你也可以在FPSGameMode.cpp顶部移除#include "FPSCharacter.h" (PS:可以注释掉),因为你不再需要关联FPSCharacter类了。
Note that if you put your Blueprint in a different folder in the asset tree, you can get the full path by right-clicking on it in the Content Browser and selecting "Copy Reference". The full path will be placed on your clipboard for handy pasting.
注意:如果你把你的蓝图放在了不同的资源文件夹中,你可在内容浏览器右键选择获取完整路径。完整路径将放置在方便粘贴的剪贴板中。
1. Switch back to Unreal Editor, and click on the Compile button.
2. The Compiling C++ Code notification will pop up in the bottom right of the screen. Wait for it to finish - it will say Compile Complete and then fade out.
3. Click on the Play In button in the Level Editor Toolbar. If you move the camera around, you should be able to see your character's shadow.
4. Press Shift+F1 to regain your mouse cursor, then click on Eject in the toolbar. You are no longer possessing the character, so you can move the camera around freely and see your character's mesh.
5. Click on Stop to exit Play in Editor (PIE) mode.
编译。
运行。
如果你移动摄像机,你会看到你的角色阴影。
按住Shift+F1 ,显示鼠标光标,点击工具栏上的Eject。你不在占有角色,所以你可以自由一定相机看到你的角色mesh。
Esc退出。
--------------------------
4.10版本已测试成功。
--------------------------------------------------------------------------------------------------------------
At the end of the previous step, the default camera is positioned inside the mesh's neck. Let's set up a proper camera that we can use to adjust the camera's properties such as location and field of view. We're going to do this by adding a CameraComponent to our FPSCharacter. First, let's add a property to the FPSCharacter to hold a reference to our CameraComponent.
在前面步骤的后面,默认相机是定位在mesh的脖子部位的。让咱设置一个适当的相机,我们可以用它调整相机的位置和视野等属性。
1. Go to FPSCharacter.h
in Visual Studio and add the following to create a public property:
在 FPSCharacter.h
添加以下代码:
/** First person camera */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) UCameraComponent* FirstPersonCameraComponent;
We will also need to add a constructor to our FPSCharacter.h
file.
我们需要为 FPSCharacter.h
添加构造函数。
// Constructor for AFPSCharacter AFPSCharacter(const FObjectInitializer& ObjectInitializer);
We will create the actual component in the FPSCharacter constructor.
我们将在FPSCharacter构造函数创建实际组件。
2. Add the following code in FPSCharacter.cpp to create the CameraComponent and attach it to the CapsuleComponent.
在FPSCharacter.cpp 中添加以下代码来创建 CameraComponent,并附加到CapsuleComponent。
AFPSCharacter::AFPSCharacter(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Create a CameraComponent FirstPersonCameraComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT("FirstPersonCamera")); FirstPersonCameraComponent->AttachParent = CapsuleComponent; }
Finally, let's adjust the camera's position to be a little above the character's eye location.
最后,调整相机位置到角色眼睛位置。
3. Add this to the constructor, after the component is created. You can tweak the camera's position in the BP_FPSCharacterBlueprint later as well, but this gives a good starting location for the CameraComponent. Also, you will only set the CameraComponent's location, not its rotation, because our earlier Turn and LookUp functions will control the camera's orientation.
当组件创建之后,添加下面代码到构造函数中。你之后也可以在中调整相机位置,但这里为CameraComponent给出一个好的出事位置。同样,你也可仅设置CameraComponent的位置量,而不是旋转量,因为早先我们的Turn和LookUp方法会控制相机的方向。
// Position the camera a bit above the eyes FirstPersonCameraComponent->RelativeLocation = FVector(0, 0, 50.0f + BaseEyeHeight); // Allow the pawn to control rotation. FirstPersonCameraComponent->bUsePawnControlRotation = true;
Because we added a new property, we need to compile in Visual Studio instead of in the editor.
因为我们添加了新的属性,我们需要在VS中编译。
1. Close Unreal Editor.
2. Compile.
3. After the build finishes, open Unreal Editor, and then open FPSProject.
4. Click on the Play In button in the Level Editor Toolbar.
编译如之前所述。运行。(4.10直接编译)
5. Your camera should be above the character's head now, and if you look down, you will be able to see the top of your character's head.
现在你的相机会在角色的头顶上,如果你想下看,你会看到角色的头顶。
6. Press Escape to exit Play in Editor (PIE) mode.
ESC退出
A common FPS approach is to use 2 separate meshes. One is the normal full-body mesh, used when seeing the character from third person but hidden when in first person. The second is a "weapon and hands" mesh that is attached to the camera and is visible only to the player when the player is in a first person perspective.
通常FPS设置了2个独立的mesh.一种是全身mesh,在第三人称看到角色时被用到,第一人称时隐藏。第二种是绑定在相机的“武器和手”,当玩家处于第一人称视角时可见。
To implement this, we'll keep the existing component named Mesh as our third person mesh and make a new SkeletalMeshComponent
to be our first person mesh.
为了实现它,我们会保留现有的名为Mesh的第三人称mesh组件,新建一个SkeletalMeshComponent作为第一人称mesh.
1. First add a public variable to FPSCharacter.h
to keep a reference to this new mesh:
首先为FPSCharacter.h添加新的public变量来关联新的mesh.
/** Pawn mesh: 1st person view (arms; seen only by self) */ UPROPERTY(VisibleDefaultsOnly, Category=Mesh) USkeletalMeshComponent* FirstPersonMesh;
2. Then, in the constructor for FPSCharacter.cpp, we'll add code to create and configure this mesh after our code that configures the FirstPersonCameraComponent:
然后,在的构造函数中,于配置FirstPersonCameraComponent的后面,添加代码创建并配置这个mesh。
// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn) FirstPersonMesh = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("FirstPersonMesh")); FirstPersonMesh->SetOnlyOwnerSee(true); // only the owning player will see this mesh FirstPersonMesh->AttachParent = FirstPersonCameraComponent; FirstPersonMesh->bCastDynamicShadow = false; FirstPersonMesh->CastShadow = false;
We are using SetOnlyOwnerSee
here to indicate that this mesh is only visible to the "owning" player, in this case the PlayerController who has possessed this Character. We also set the mesh to be attached to the camera. Finally, we disable some environmental shadowing since seeing shadows of these camera-attached arms would look odd and destroy the illusion.
这里我们使用来声明这个mesh是仅对玩家拥有着可见的,这种情况下, PlayerController占有Character。我们同样把mesh附加到相机上。最后,我们关掉环境阴影,因为与相机连接的手臂的阴影看起来会不和谐。
3. Finally, we have to change the settings for Mesh, the existing third person SkeletalMeshComponent. Add the following lines to the constructor to set its visibility so it is hidden from the owning player.
最后,我们需要为Mesh改变设置——已存的第三人称SkeletalMeshComponent。在构造函数中添加以下代码来设置它的可见性,所以他会对所属玩家隐藏。
// everyone but the owner can see the regular body mesh Mesh->SetOwnerNoSee(true);
As before, we will set the mesh asset in the Blueprint, so let's compile and run the editor.
如之前一样,我们会在蓝图中设置mesh,所以编译运行编辑器吧。
1. Close Unreal Editor.
关闭虚幻编辑器(4.10省略该步骤)
2. Compile.
编译
3. After the build finishes, open Unreal Editor, and then open FPSProject.
完成编译后,打开FPSProject(4,10省略该步骤)
4. Download this zip file and unzip it to receive the first person mesh FBX file, which contains a SkeletalMesh with just arms.
下载你解压ZIP文件获得第一人称mesh FBX文件,它只有手臂的 SkeletalMesh 。
First Person Skeletal Mesh
5. Navigate to the Game folder in the Content Browser.
到内容浏览器中的Game文件夹。
6. Right-click in the Content Browser, and select Import to /Game in the menu that appears.
右键点击Content Browser选择 Import to /Game。
7. Navigate to wherever you saved the FBX file, then select it and click Open.
进入你FBX所在的文件夹,选择并点击打开。(4.10可直接拖拽FBX)
8. Open the Advanced dropdown and make sure Import Materials is checked, then click on Import.
打开Advance下拉,确保勾选Import Materials ,点击import.
If you receive an error about smoothing groups, you can disregard it. This mesh will still work to illustrate the first person mesh setup, and will work with the animations set up in a later step.
你可以忽略遇到的有关平滑组的错误。这个mesh依然仍然有用,用来说明第一人称mesh的设置,以及后面步骤中的动画设置。
1. Click on Save in the Content Browser to save your new Skeletal Mesh and its associated assets.
点击Save 保存你的Skeletal Mesh,它会关联资源。
2. Navigate back to the Blueprints folder in the Content Browser.
回到Content Browser中的Blueprints文件夹。
3. Open BP_FPSCharacter and switch to Components Mode.
打开BP_FPSCharacter ,切换到Components Mode。(4.10直接打开就行了)
(NOTE: There is an additional step required as a workaround to an current issue we are looking into. To be able to find the FirstPersonMesh in the component list, you will need to delete the BP_FPSCharacter blueprint and recreate it. After doing this you can continue with step 4.)
(注意:我们在这里使用了一个额外的步骤解决当前我么正在调查的问题。为了能在component列表中找到FirstPersonMesh,你需要删除BP_FPSCharacter蓝图重建它。之后你可以继续步骤4.)PS :4.10不需重建蓝图,已测试。
4. Find the new FirstPersonMesh we added. Notice that it is a child of the FirstPersonCameraComponent, so it will always be attached to the camera. You may have to expand the FirstPersonCameraComponent dropdown.
找到我们添加的FirstPersonMesh,注意他是FirstPersonCameraComponent的子类,因此它会始终附着于相机。你可能需要打开FirstPersonCameraComponent扩展。
You may encounter an issue where the new FirstPersonMesh and FirstPersonCameraComponent do not appear in your blueprint. If this happens to you, you can remove the blueprint BP_FPSCharacter and create it again as described above, and the new properties will appear.
你可能会在蓝图中找不到FirstPersonMesh 和 FirstPersonCameraComponent。如果是这样,你可以如上面说的移除并重建BP_FPSCharacter蓝图,这样它们就会出现了。
5. Click on the FirstPersonMesh component in the Components tab.
在 Components选项卡中点击FirstPersonMesh。
6. In the Details tab, scroll down to the Mesh section. Click on the dropdown that says None, then select your recently imported Skeletal Mesh asset. You may have to resize the Details tab to see this menu. Now, the arms should appear in the Viewport, although you may have to zoom out to see them.
在Details选项卡中,下滑到 Mesh部分。点击None选择新导入的Skeletal Mesh。你可能需要调整Details的大小来找到这个选项。现在,手臂会出现在Viewport,虽然你可能需要缩小才能看到它们的。(PS:感觉应该是放大吧)PS:博主在这里手臂没出来,于是关掉了蓝图,在虚幻编辑器编译一下,重新打开蓝图就出现了。
7. To adjust the relative transform so the arms appear on the camera, set the Location to {240,0,35} and the Rotation to {-180, 50, -180}. You will readjust this position after the arms are animated, but for now, this position lets you see that you are using this first person mesh when playing.
为了调整相关的位置使手臂出现在相机的面前,设置Location为 {240,0,35},Rotation为 {-180, 50, -180}。当手臂动起来的后你需要重新调整位置。但是现在,这个位置让你看到了游戏运行时,你正在使用第一人称mesh.
8. Compile and Save your Blueprint, then close the Blueprint Editor.
编译,保存,关闭蓝图。
9. Click on the Play In button in the Level Editor Toolbar.
点击Play.
10. At this point, you will no longer be able to see the third person SkeletalMesh, but you will be able to see the disembodied arms of the first person SkeletalMesh.
这里,你在也无法看到第三人称SkeletalMesh,但你能看到第一人称的虚拟手臂SkeletalMesh。
11. Press Shift+F1 to regain your mouse cursor, then click on Eject in the toolbar. You are no longer possessing the character, so you can move the camera around freely and see both the third person and the first person meshes.
按下Shift+F1 重现鼠标光标,点击Eject,你不再占据角色,依次你可以自由移动相机,同时看到第一人称和第三人称的mesh.
12. Press Escape to exit Play in Editor (PIE) mode.
ESC退出
-----------------------------------------
4.10测试成功。
--------------------------------------------------------------------------------------------------------------
Now that the character is set up, let's implement a simple projectile weapon - when you fire, a simple grenade-like projectile will shoot from the center of the screen and fly until it hits the world. While we have the editor open, let's add an input and create a new code class for our projectile.
既然角色已经建立起来,那么让咱实现简单的子弹发射吧。当你开火时,会有简单的类似子弹的东西从屏幕射击知道与世界中的物体碰撞。打开编辑器,为我们的子弹添加输入和代码类。
1. In the Edit menu, click on Project Settings.
进入Project Settings。
2. Under the Engine heading on the left side of the Project Settings tab, click on Input.
进入Input选项。
3. Under Bindings, click on the + next to Action Mappings.
点击Action Mappings旁边的+。
4. Click on the arrow to the left of Action Mappings to expand the Action Mappings settings.
点击Action Mappings左边的扩展箭头
5. Type "Fire" in the text field.
输入文本"Fire"。
6. Expand the dropdown, and select Left Mouse Button.
下拉选择 Left Mouse Button。
7. Close the Project Settings menu.
关闭Project Settings。
Now let's create the projectile class.
现在,让我们创建子弹类。
1. Go to File > Add Code to Project.
选择。
2. Choose Actor, then click Next.
选择Actor类,点击下一步。
3. Name your new class FPSProjectile, then click on Create.
类名命名为FPSProjectile,点击Create。
4. Click on Yes to open the class in Visual Studio for editing.
点击Yes在VS中打开类。
5. Visual Studio will prompt you asking to reload the project, since the C++ Class Wizard modified it. Select Reload.
VS会提示是否重新加载项目,因为C++类向导修改了他。选择reload.
First, we should decide on a simplified physical representation to use for collision and simulation. For our case, let's use a USphereComponent.
首先,我们决定简化用于碰撞和仿真的物理表示。在我们的案例中,我们使用USphereComponent.
1. Add a reference to this component in your FPSProjectile class declaration in FPSProjectile.h.
在 FPSProjectile.h的 FPSProjectile声明中添加组件引用。
/** Sphere collision component */ UPROPERTY(VisibleDefaultsOnly, Category=Projectile) USphereComponent* CollisionComp;
2. Add a constructor to FPSProjectile.h
.
在FPSProjectile.h添加构造函数声明。
AFPSProjectile(const FObjectInitializer& ObjectInitializer);
3. Create the component in the FPSProjectile constructor in FPSProjectile.cpp. We'll make it the root component since the simulation will drive it, and we can attach visual components to it later in a Blueprint.
在FPSProjectile构造函数中创建组件。由于simulation驱使它的需要,我们将它设为根组件,然后我们可以在之后的蓝图中将可视化组件附件到它上面。
AFPSProjectile::AFPSProjectile(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Use a sphere as a simple collision representation CollisionComp = ObjectInitializer.CreateDefaultSubobject<USphereComponent>(this, TEXT("SphereComp")); CollisionComp->InitSphereRadius(15.0f); RootComponent = CollisionComp; }
UE4 comes with a ProjectileMovementComponent that can be used to easily do simple ballistic-style movement, so let's add that to FPSProjectile.
UE4有一个可以做简单弹道运动的ProjectileMovementComponent ,因此我们将它添加给FPSProjectile.
1. First, add a public reference in your FPSProjectile class declaration in FPSProjectile.h.
首先,在FPSProjectile类声明中,添加public 相关变量。
/** Projectile movement component */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Movement) UProjectileMovementComponent* ProjectileMovement;
2. Then, add the following lines to the FPSProjectile constructor in FPSProjectile.cpp to create this component:
然后,在FPSProjectile.cpp的构造函数中添加以下代码来创建组件。
// Use a ProjectileMovementComponent to govern this projectile's movement ProjectileMovement = ObjectInitializer.CreateDefaultSubobject<UProjectileMovementComponent>(this, TEXT("ProjectileComp")); ProjectileMovement->UpdatedComponent = CollisionComp; ProjectileMovement->InitialSpeed = 3000.f; ProjectileMovement->MaxSpeed = 3000.f; ProjectileMovement->bRotationFollowsVelocity = true; ProjectileMovement->bShouldBounce = true; ProjectileMovement->Bounciness = 0.3f;
We've also set a few properties here to influence the simulation, the most important of which is the UpdatedComponent.
这里我们设置了几个属性来影响仿真,其中最重要的是UpdatedComponent。
Looking ahead, we're also going to want a function to "launch" our projectile by setting its initial velocity.
往后一点,我们也想要一个可以通过设置初始速度的方法来发射我们的子弹。
1. Declare a public function in the FPSProjectile class declaration in FPSProjectile.h:
在FPSProjectile.h的FPSProjectile类声明中public方法。
/** inits velocity of the projectile in the shoot direction */ void InitVelocity(const FVector& ShootDirection);
2. Implement the function in FPSProjectile.cpp by adding the following definition after the constructor.
void AFPSProjectile::InitVelocity(const FVector& ShootDirection) { if (ProjectileMovement) { // set the projectile's velocity to the desired direction ProjectileMovement->Velocity = ShootDirection * ProjectileMovement->InitialSpeed; } }
Note that our projectile's speed is defined in the ProjectileMovementComponent, so we only need to supply a launch direction.
注意子弹速度已在ProjectileMovementComponent中定义,因此我们只需提供发射方向。
Finally, we will add code to the FPSCharacter so that when the Fire input is pressed, it will launch a projectile. As before, we will declare a public function called OnFire that we will bind to the Fire input we defined earlier.
最后,为FPSCharacter添加代码,从而当开火输入按下时,子弹会被发射。在此之前,我们会声明一个绑定到早先我们声明的Fire input的public的OnFire方法。
1. In FPSCharacter.h, add this function to the class declaration:
在FPSCharacter.h中,添加方法声明:
//handles firing UFUNCTION() void OnFire();
2. In the FPSCharacter.cpp, add the following to SetupPlayerIputComponent to bind the Fire action to our new OnFire function.
在FPSCharacter中添加代码到SetupPlayerIputComponent绑定开火动作到我们的OnFire方法。
InputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::OnFire);
There are two points to consider for the OnFire implementation. We know we want to spawn an FPSProjectile actor, so we have to define:
OnFire的实现需要考虑两点。我们知道我们想要生成一个FPSProjectile actor,纳闷我们需要定义:
To determine a spawn location, we'll use a camera-space offset vector as an editable parameter, so we can set and tweak it in our BP_FPSCharacter Blueprint. We can then calculate an initial location for the projectile based on this data.
为了确定产生地点,我们将使用相机的空间偏移量作为可编辑参数,从而使我么可以在BP_FPSCharacter蓝图中设置和调整它。我们可以在数据的基础上为子弹计算之后的初始位置。
1. Add the following to the FPSCharacter class declaration in FPSCharacter.h:
在FPSCharacter.h的FPSCharacter类声明中添加以下代码。(PS:这里吧FPSCharacter错搞成了FPSProjectile,害博主调试蛋疼了半天)
/** Gun muzzle's offset from the camera location */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay) FVector MuzzleOffset;
The EditAnywhere specifier allows you to change the value of the muzzle offset either within the Defaults mode of the Blueprint Editor, or within the Details tab for any instance of the character. The BlueprintReadWrite specifier allows you to both get and set the value of the muzzle offset within a Blueprint.
EditAnywhere修饰符允许你在蓝图编辑器的默认模式或者任何角色实例的Details选项卡中更改炮口偏移量。BlueprintReadWrite 修饰符允许你在蓝图中读写炮口偏移值。(PS:炮口偏移有点怪怪的)
Let's also introduce a projectile class as an editable parameter. This will allow us to later specify a Blueprint derived from FPSProjectile as the projectile we want to spawn.
让我们介绍作为可编辑参数的子弹类。这将使我们在之后指定作为我们所想产生的子弹、继承自FPSProjectile的蓝图。
1. Add the following to the FPSCharacter class declaration in FPSCharacter.h as well:
/** Projectile class to spawn */ UPROPERTY(EditDefaultsOnly, Category=Projectile) TSubclassOf<class AFPSProjectile> ProjectileClass;
在FPSCharacter.h的FPSCharactere类声明中添加以下代码。
Here, we use the EditDefaultsOnly specifier, which means that you will only be able to set the projectile class as a default on the Blueprint, not on each instance of the Blueprint.这里,我们使用 EditDefaultsOnly修饰符,他可以让我们在特定蓝图默认只能写入子弹类,而不是每个蓝图都有。
Our OnFire function will involve several steps.在我们的OnFire方法将会射击到几个步骤。
1. Add the following function to FPSCharacter.cpp
:
FPSCharacter.cpp添加以下方法。
void AFPSCharacter::OnFire() { // try and fire a projectile if (ProjectileClass != NULL) { // Get the camera transform FVector CameraLoc; FRotator CameraRot; GetActorEyesViewPoint(CameraLoc, CameraRot); // MuzzleOffset is in camera space, so transform it to world space before offsetting from the camera to find the final muzzle position FVector const MuzzleLocation = CameraLoc + FTransform(CameraRot).TransformVector(MuzzleOffset); FRotator MuzzleRotation = CameraRot; MuzzleRotation.Pitch += 10.0f; // skew the aim upwards a bit UWorld* const World = GetWorld(); if (World) { FActorSpawnParameters SpawnParams; SpawnParams.Owner = this; SpawnParams.Instigator = Instigator; // spawn the projectile at the muzzle AFPSProjectile* const Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams); if (Projectile) { // find launch direction FVector const LaunchDir = MuzzleRotation.Vector(); Projectile->InitVelocity(LaunchDir); } } } }
2. Add an #include at the top of FPSCharacter.cpp, since we're using FPSProjectile from within FPSCharacter.由于我们在FPSCharacter.cpp中添加#include头文件。
#include "FPSProjectile.h"
3. Close Unreal Editor.
4. Compile.
5. After the build finishes, open Unreal Editor, and then open FPSProject.
编译。
Now let's finalize our projectile by creating a Blueprint and adding a mesh so we can see the effect of shooting our projectile.
最后,让我们通过创建蓝图、添加可以看到射击效果的mesh来完成我们的子弹。
6. Download this zip file and unzip it to receive the sphere FBX file, which contains the StaticMesh you will use for your projectile.
下载并解压ZIP活得球形FBX,它包含了你需要的子弹StaticMesh.
Sphere Mesh
7. Navigate to the Game folder in the Content Browser.
8. Right-click in the Content Browser, and select Import to /Game in the menu that appears.
9. Navigate to wherever you saved the FBX file, then select it and click Open.
10. Open the Advanced dropdown and make sure Import Materials is checked, then click on Import.
If you receive an error about smoothing groups, you can disregard it. This mesh will still work to illustrate the first person mesh setup, and will work with the animations set up in a later step.
11. Click on Save in the Content Browser to save your new StaticMesh.
12. Navigate back to the Blueprints folder in the Content Browser, then right-click in the Content Browser and create a new Blueprint.
13. Expand the Custom Classes dropdown and search for FPSProjectile, then select that as the parent class for your Blueprint.
14. Name your new Blueprint BP_FPSProjectile, then double-click it to open it in the Blueprint Editor.
导入FBX,新建名为 BP_FPSProjectile类型为FPSProjectile的蓝图并打开(详细过程之前有翻译)。
15. To add a child StaticMeshComponent to the root SphereComponent, click on CollisionComp in the Components tab, then select Static Mesh from the Add Component dropdown.
为了添加 子StaticMeshComponent 给根 SphereComponent,在Components选项卡中CollisionComp点击,从Add Component选择Static Mesh。
16. Name this new component ProjectileMesh.
新组件命名ProjectileMesh
17. Set its Static Mesh asset to your sphere StaticMesh using the dropdown menu under Mesh in the Details panel.
在Details中的mesh部分设置你自己的sphere StaticMesh。
Note that if you are making a multiplayer game, that you must also uncheck "Initial Velocity in Local Space" in the "MovementComp" Component in order for this projectile to replicate correctly over a server.
注意:如果你创建的是多人游戏,你不需要勾选 "MovementComp" Component中的"Initial Velocity in Local Space",从而让服务器能正确的复制子弹。
18. Set the scale to 0.09 in X, Y, and Z.
设置XYZ的比例为0.9.
Clicking on the the lock icon locks all three axes so they preserve their relative scale.
点击锁定图标锁定三条轴,从而使他们保持相应的规模。
19. Set the ProjectileMesh's Collision Presets value to NoCollision, since we're using the SphereComponent for collision and not this Static Mesh.
设置ProjectileMesh的Collision Presets(碰撞预设)值为 NoCollision(无碰撞),因为我们为碰撞使用了SphereComponent而不是它的Static Mesh.
20. Compile and Save your Blueprint, then close the Blueprint Editor.
编译保存你的蓝图,然后关闭。
21. Now open BP_FPSCharacter for editing, and open Defaults Mode.
打开编辑BP_FPSCharacter,打开Defaults Mode。
22. Find the Projectile Class property and set it to BP_FPSProjectile.
找到Projectile Class 属性,并将其设置为BP_FPSProjectile。
23. Set the MuzzleOffset property to {100, 0, 0} in order to spawn the projectile slightly in front of the camera.
设置MuzzleOffset属性为{100, 0, 0},以使得子弹在相机前方产生。
24. Compile and Save your Blueprint, then close the Blueprint Editor.
编译保存你的蓝图,然后关闭。
25. Click on the Play In button in the Level Editor Toolbar.
点击Play运行。
26. Left-click to fire your projectiles
鼠标右键开火发射子弹。
27. Press Escape to exit Play in Editor (PIE) mode.
ESC退出。
4.10亲测成功 就是自己翻译错了 ,调试半天没找到问题,蛋疼。
After adding our projectiles, there are two interesting things to notice that we should address.
完成子弹添加后,有两个有趣的事情值得去注意,且我们应该去解决。
Fortunately, all Actors in UE4 can have a limited lifespan, controlled by the InitialLifeSpan property.
幸运的是,在UE4中所有的Actor可有生命限制,它由InitialLifeSpan属性控制。
1. Add the following lines to the FPSProjectile constructor to set the projectile's lifespan. You could also modify the Initial Life Span default in the BP_FPSProjectile Blueprint.
为FPSProjectile蓝图中修改初始生命周期。
// Die after 3 seconds by default InitialLifeSpan = 3.0f;
(PS:使用代码无法实现生命周期,使用蓝图可以。推测可能是蓝图默认无限生命周期覆盖了代码实现的生命周期,以后再做讨论。)
UE4 comes with several useful collision channels, but also provides several customizable channels that game projects can use. Let's define a custom channel for projectiles, so everything can explicitly choose how to interact with a projectile in our game.
UE4带有几个有用的碰撞通道,同时也提供了几个游戏项目可使用的自定义通道。让我们为子弹定义一个自定义通道,使得游戏中的一切事物可以选择如何与子弹交互。
1. To customize a channel, open the Project Settings and select Collision.
打开Project Setting,选择Collision,进行通道自定义。
2. Select New Object Channel... to make a new collision channel. Name this Projectile and be sure the Default Response is set to Block
选择New Object Channel... to创建新的碰撞通道。命名为Projectile ,确保Default Response为Block。
3. Now select New...under Preset. Name this one Projectile as well. Set the settings for this collision preset as shown in the image below.
在 Preset下面选择 New...。同样命名一个FPS
This profile means that the projectile will be blocked by Static Actors, Pawns, Dynamic Actors, Actors simulating Physics, Vehicles, and Destructible Actors.
此配置意味着子弹会被Static Actor, Pawns, Dynamic Actors, Actors simulating Physics, Vehicles, and Destructible Actors限制。
Now we'll set our projectile to use this profile.
现在,我们会设置我们的子弹使用这个配置。
1. In the FPSProjectile
constructor in FPSProjectile.cpp
, add the following line after the creation of CollisionComp
.
在 FPSProjectile.cpp的
FPSProjectile
构造函数中,在创建后面添加以下代码。
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile");
2. Close Unreal Editor.
3. Compile.
编译
In the next step, we will set up how the projectile interacts with objects that it collides with.
在下一个步骤中,我们将设置子弹是如何与被碰撞的对象进行交互的。
Now that we can detect our projectile's collision interactions, we can determine how to respond to them. In our projectile collision settings, we've set our interactions to be Blocks, so let's add a function to FPSProjectile called OnHit to respond to these events.
现在我们可以检测子弹的碰撞,我们可以决定做出何种反应。在子弹碰撞提的设置中,我们设置了交互方式为Blocks,让我们为FPSProjectile添加OnHit方法作为响应事件。
1. In the FPSProjectile
class definition, add the following function declaration:
在FPSProjectile类定义中,添加以下方法声明。
/** called when projectile hits something */ UFUNCTION() void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
Now, we will implement OnHit with functionality to add a physics impulse to whatever the projectile hits.
现在我们实现OnHit方法来为任何子弹碰撞的物体添加物理脉冲。
1. Add the following to FPSProjectile.cpp:
为FPSProjectile.cpp添加以下代码。
void AFPSProjectile::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { if ( OtherActor && (OtherActor != this) && OtherComp ) { OtherComp->AddImpulseAtLocation(ProjectileMovement->Velocity * 100.0f, Hit.ImpactPoint); } }
Lastly, we need to hook this function to the projectile's SphereComponent's OnComponentBeginOverlap
delegate.
最后,我们需要将这个方法绑定到 SphereComponent's OnComponentBeginOverlap 委托。
1. In the FPSProjectile
constructor, add the following after CollisionComp
is created.
在FPSProjectile
构造函数中,在构建CollisionComp的后面添加以下代码。
CollisionComp->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);
2. Compile.
3. After the build finishes, open Unreal Editor, and then open FPSProject.
编译
4. Select the SM_Template_Map_Floor floor StaticMesh.
选择SM_Template_Map_Floor 地面StaticMesh(PS:直接复制World Outline中的floor ,粘贴得到floor2)
5. Copy and paste the floor mesh, then rescale the copy to {0.2, 0.2, 3.0}.
复制粘贴 floor mesh,复制体缩放到{0.2, 0.2, 3.0}。(PS:复制地面构建一个立方体,注意设置movable,以及勾选 Smulate Physics)
6. Position the mesh copy at {-230, 0, 160}.
复制体位置设为{-230, 0, 160}.
7. Scroll down to the Physics section and check Simulate Physics.
下滑到Physics 部分,勾选Simulate Physics。
8. Save your map.
保存你的地图。
9. Click on the Play In button in the Level Editor Toolbar.
点击Play运行。
10. Left-click to fire your projectiles and move the cube around your level. Your projectiles are now complete!
右键发射子弹,正方体会被弹动。你的子弹已完成功能。
11. Press Escape to exit Play in Editor (PIE) mode.
ESC退出。
--------------------------------------------------------------------
4.10亲测成功,需要改动部分已在文中PS中注明。
Now that you are able to shoot projectiles while playing your game, let's add a HUD with crosshairs to show where you are aiming.
既然你已经可以在游戏中射击了,那就让给我们添加一个用来瞄准的十字准心HUD
1. Download the following file, and unzip it to get the crosshair image crosshair.TGA.
下载并解压ZIP文件,获取十字准心图片—— crosshair.TGA.
Crosshair
2. In Unreal Editor, navigate to the Game folder in the Content Browser.
3. Right-click in the Content Browser, and select Import to /Game in the menu that appears.
4. Navigate to wherever you unzipped the crosshair.TGA file, then select it and click Open.
5. Click on Save in the Content Browser to save your new asset.
导入crosshair.TGA。保存。(与导入FBX类似)
UE4 comes with a basic HUD class we can extend, so let's add a new class derived from that.
UE4带有基础的HUD类,让我们为其创建一个派生类。
1. Go to File > Add Code to Project.
2. Select HUD as the parent class for your new class, and click Next.
3. Name your new class FPSHUD, then click on Create.
4. Click on Yes to open the class in Visual Studio for editing.
5. Visual Studio will prompt you asking to reload the project, since the C++ Class Wizard modified it. Select Reload.
创建类型为HUD名为FPSHUD 的类。
What we want to do here is to draw a crosshair icon on the center of the screen. First, we need a reference to our texture asset.
我们想要做的是使十字准心图标至于屏幕中间。首先,我们需要关联贴图资源。
1. First we must set up the constructor for this new class. Place the following code in FPSHUD.h, under GENERATED_BODY().
首先我们需要在FPSHUD.h中GENERATED_BODY()的下面为新类构建构造函数。
AFPSHUD(const FObjectInitializer& ObjectInitializer);
2. Next we need to implement the constructor. Place the following code in FPSHUD.cpp.在FPSHUD.cpp实现构造函数。
AFPSHUD::AFPSHUD(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
3. Add the following to the FPSHUD class definition in FPSHUD.h. We're only going to use this internally to this class, so let's make it private.在FPSHUD.h中声明以下代码。由于它只供类内部使用,因而设为private类型。
private: /** Crosshair asset pointer */ UTexture2D* CrosshairTex;
4. We can then get a reference to our desired asset in the FPSHUD constructor.我们可以在FPSHUD构造函数中关联我们所想要的资源。
As a reminder, you can get the asset path to your texture in the editor by right clicking the asset in the Content Browser and selecting Copy Reference.提醒下,你可以在Content Brower右键贴图中的Copy Reference获取资源路径。
AFPSHUD::AFPSHUD(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer) { // Set the crosshair texture static ConstructorHelpers::FObjectFinderCrosshairTexObj(TEXT("Texture2D'/Game/crosshair.crosshair'")); CrosshairTex = CrosshairTexObj.Object; }
The HUD base class has a virtual function called DrawHUD that we can override to add our custom drawing code and draw the crosshairs on the screen.HUD基类有一个叫DrawHUD的虚方法,我们可以重写添加我们自定义的绘制代码,将十字准心绘制到屏幕上。
1. Add a function declaration to the FPSHUD class declaration, below GENERATED_UCLASS_BODY():在FPSHUD类声明中GENERATED_UCLASS_BODY()下面添加以下方法声明。
/** Primary draw call for the HUD */ virtual void DrawHUD() OVERRIDE;
2. Implement the DrawHUD override in FPSHUD.cpp.在FPSHUD.cpp实现DrawHUD重写。
void AFPSHUD::DrawHUD() { Super::DrawHUD(); // Draw very simple crosshair // find center of the Canvas const FVector2D Center(Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f); // offset by half the texture's dimensions so that the center of the texture aligns with the center of the Canvas const FVector2D CrosshairDrawPosition( (Center.X - (CrosshairTex->GetSurfaceWidth() * 0.5)), (Center.Y - (CrosshairTex->GetSurfaceHeight() * 0.5f)) ); // draw the crosshair FCanvasTileItem TileItem( CrosshairDrawPosition, CrosshairTex->Resource, FLinearColor::White); TileItem.BlendMode = SE_BLEND_Translucent; Canvas->DrawItem( TileItem ); }
Finally, we need to tell our GameMode to use our custom HUD class when creating players.最后,我们需要在创建玩家的时候在告诉GameMode使用自定义的HUD。
1. In The FPSGameMode constructor, add:在FPSGameMode构造函数中添加:
HUDClass = AFPSHUD::StaticClass();
2. Add an include statement at the top of FPSGameMode.cpp.在FPSGameMode.cpp添加头文件:
#include "FPSHUD.h"
3. Close the editor, build FPSProject, and open the editor with FPSProject one more time. This is the last step of the tutorial that utilizes Visual Studio, so you can close it now.
编译。
4. Play your game in the editor. At this stage, you can move around, jump, control the camera, and shoot projectiles that interact with physics objects!
运行游戏。你可以移动、跳跃、切换镜头、射击并交互物理对象。
Now let's get some animation into our game, by animating the first person arms we added a few steps back.
现在让我们为游戏添加点动画,让之前添加的第一人称手臂动起来。
1. Download the following file, and unzip it to get the five animations we will be working with in this step.
下载解压ZIP,获取5个动画。
Animations
2. Back in the editor, navigate to the Game folder in the Content Browser. Right-click in the Content Browser and create a new folder called Animations.
3. Open the Animations folder, then right-click and select Import to /Game/Animations.
4. Navigate to the location you saved the five animations to, select all five, and then click on Open.
类似导入FBX导入五个动画到新建的Animations文件夹中。
5. Select HeroFPP_Skeleton under the Select Skeleton heading, then click on Import.
Select Skeleton标题下选择HeroFPP,点击Import.(PS:4.10位置有点不同)
6. Repeat for the other four FBX Import Options prompts.
重复设置其他四个FBX Import Options提示。
7. Click on Save in the Content Browser to save your new assets.
点击Content Browser里的Svae保存资源。
Now that we have our assets imported, we need to create an Animation Blueprint.
既然已导入资源,我们需要创建一个动画蓝图。
1. Right click and select Animation > Animation Blueprint.
右键选择Animation > Animation Blueprint.
2. Choose AnimInstance as the Parent Class and choose /Game/HeroFPP_Skeleton as the Target Skeleton.
选择AnimInstance作为基类,选择/Game/HeroFPP_Skeleton作为Target Skeleton。
3. Name it Arms_AnimBP and open it for edit.
命名为Arms_AnimBP并打开。
Looking at our animation data, we have 5 animations to hook up:
浏览我们的动画数据,有5个动画连接。(PS:个人截图如下)
We'll use a state machine to set up these animation states and their transitions. But first, thinking about how to drive this state machine, we are going to need 2 pieces of data - whether the pawn is walking (versus standing still), and whether the pawn is airborne (versus on the ground). Let's add 2 variables to the Blueprint to store this information. For an overview of variable creation, see the Blueprint Variables documentation.
我们使用状态机来设置这些动画状态和转换。但首先需要考虑如何驱动状态机。我们需要2个数据块 ——无论pawn行走与否,悬空与否。让我们为蓝图添加2个变量来存储这些信息。关于创建变量的概述,请参考 Blueprint Variables文档。
1. In the My Blueprint tab, click on the New Variable button.
在My Blueprint选项卡,点击New Variable按键。
2. Make the variable a Boolean called IsRunning.
创建一个Boolean类型的IsRunning变量。
3. Click on the New Variable button again and add a boolean called IsFalling.
点击 New Variable按键便添加类型为boolean的IsFalling变量。
To set these variables properly while the game is running, we'll edit the Event Graph.
为了在游戏运行时正确设置这些变量,我们需要编辑Event Graph。
1. Open the EventGraph by double-clicking on EventGraph in the My Blueprint tab.
在My Blueprint选项卡中双击打开EventGraph。
2. Right-click in the graph to bring up the context menu.
右键点出文本菜单
3. Type Update in the context menu search, then click on Event Blueprint Update Animation to add that node.
输入Update搜索,点击来添加Event Blueprint Update Animation节点。
The Event Blueprint Update Animation node will allow us to update our state variables every time the Animation updates, so they are always in sync with the game state.
Event Blueprint Update Animation节点允许我们在每次动画更新的时候更新我们的状态变量,因此他们总是与游戏状态同步。
We can find the proper values for our variables by querying the character's CharacterMovementComponent. To get this, we must first get a reference to the animation's owning Character.
我们可以通过请求角色的CharacterMovementComponent来获取合适的值。为此,首先我们需要关联动画自己的Character。
1. Right-click in the graph to bring up the context menu.
右键点开Content menu.
2. Type Owner in the context menu search, then click on Try Get Pawn Owner to add that node.
搜索选择Try Get Pawn Owner并添加该节点。
3. Drag off the output pin and select Cast to Character from the context menu.
添加Cast to Character节点。
4. Wire the output execution pin on Event Blueprint Update Animation to the input execution pin on Cast to Character.
如图连连看。
5. Drag off the As Character output pin and select Get Character Movement.
拖拽As Character输出引脚,选择Get Character Movement。
6. Drag off the Character Movement output pin and select Get Movement Mode.
拖拽Character Movement输出引脚选择Get Movement Mode。
Now we can query the CharacterMovementComponent's MovementMode and set IsFalling to true if we're in the falling state, or false otherwise.
现在我们可以请求CharacterMovementComponent's MovementMode,如果我么处于下落状态设置isFalling为true,否则为false。
1. Drag off the Movement Mode output pin and select Equal (Enum).
拖出Movement Mode输出引脚,选择Equal (Enum).
2. Set the dropdown value on the Equal (Enum) node to Falling.
在Equal (Enum) 节点中下拉选择Falling。
3. Alt-click on IsFalling in the My Blueprint tab and drag into the graph to create a Set Is Falling node.
将IsFalling变量拖入并选择Set Is Falling。
4.Connect the unlabeled output execution pin of the Cast to Character node to the input execution pin of the Set Is Falling node, and connect the output Boolean data pin of the Equal (Enum) node to the input Boolean data pin of the Set Is Falling node.
如图连连看。
Then, to determine if we're running or standing still, we can get the character's velocity and set IsRunning to true if the magnitude is >0, or false otherwise.
然后,通过获取角色速度以及当magnitude>0时设置IsRunning为true(<0时,为false),来决定角色是停是动。
1. Go back to the Cast To Character node and drag off the As Character pin again. This time, select the Get Velocity node.
如图连连看。
2. If the character is not standing still, the length of its velocity vector will be >0. So, drag off the Return Value vector output pin, and select Vector Length to add that node to the graph.
如果角色不是静止的话,速度向量的模会大于0.那么,如图连连看。
3.Drag off the Return Value float output pin, and select the > (float) node.
如图连连看。
4. Alt-click on IsRunning in the My Blueprint tab and drag into the graph to create a Set Is Running node.
将IsRuning变量拖进来,设为set节点.
5. Connect the output execution pin of the Set Is Falling node to the input execution pin of the Set Is Running node, and connect the output Boolean pin of the > (float) node to the input Boolean pin of the Set Is Running node.
如图连连看。
--------------------------------------------------------------------------------------------------------------
Now that our variables are being set properly, we can put together our state machine.
既然我们的变量已设置好了,我们可以玩弄我们的状态机了。
1. Double-click on AnimGraph in the My Blueprint tab to open it.
在My Blueprint选项卡双击打开AnimGraph。
2. Right-click the graph and select State Machines >Add New State Machine... in the context menu.
右键选择State Machines >Add New State Machine...
3. Right-click on New State Machine in the My Blueprint tab, and rename the state machine to Arms State Machine.
在My Blueprint选项卡中右键New State Machine,重命名为Arms State Machine。
4. Connect the output execution pin on the Arms State Machine node to the Result input execution pin on the Final Animation Pose node.
如图连连看。
5. Double-click the Arms State Machine node to open its graph for editing.
双击打开Arms State Machine节点进行编辑。
We need to add our 5 states to this graph.
我们需要在图中添加五个状态。
1. Right-click in the graph and select Add State... from the context menu.
右键选择Add State...
2. Name the state Idle.
3. Double click the state to edit it.
4. Right-click in the graph, and search for "Idle" in the context menu. Click on Play FPP_Idle to insert that node.
5. Connect the output execution pin of the Play FPP_Idle node to the Result input execution pin of the Final Animation Posenode
命名为Idle;
双击打开编辑。
右键搜索Idle。点击插入节点;
连接Play FPP_Idle节点的输出引脚到Final Animation Pose节点的Result输入引脚。
6. Repeat steps 1-5 for each of the other 4 states:
上诉步骤重复对其他四个状态使用。
When you are done, the Arms State Machine graph should look like the below image. Each state should contain the appropriate Play node connected to the Final Animation Pose node.
完成后,看起来应该如下图所示。每个状态都应该包含有连接Final Animation Pose节点的Play 节点。
Now, we will wire up the transitions between our states. Start by dragging a wire from the Entry node to Idle state.
现在,我们将为各状态之间建立过渡。从Entry节点到Idle节点连线开始。
When our character starts moving the state machine should transition from the Idle to the Run state.
当角色开始移动时,状态机会从Idle过渡到Run状态。
1. Drag a wire from the Idle state to the Run state to create a transition.
如图连连看。
2. Double click the transition to edit it. Control-click on IsRunning in the My Blueprint tab and drag into the graph to create a Get Is Running node.
双击编辑过渡线。将My Blueprint选项卡中的IsRunning拖入并建立Get Is Running节点。
3. Connect the output pin on the Get Is Running node to the input Can Enter Transition pin on the Result node.
如图连连看。
When our character stops moving the state machine should transition from the Run state to the Idle state.
角色停止运动时会从Run过渡到 Idle 。
1. Return to the Arms State Machine graph, and drag a wire from the Run state to the Idle state.
如图连连看。
2. Double click the transition to edit it. Control-click on IsRunning in the My Blueprint tab and drag into the graph to create a Get Is Running node.
双击过渡线进行编辑。将My Blueprint选项卡中的IsRunning拖入创建Get Is Running节点。
3. Drag off the output Boolean pin on the Get Is Running node and create a Not Boolean node.
拖出Get Is Running的输出引脚创建Not Boolean节点。
4. Connect the output pin on the Not Boolean node to the input Can Enter Transition pin on the Result node.
连接Not Boolean节点与Result节点的Can Enter Transition输入引脚。
1. Return to the Arms State Machine graph, and drag a wire from the Idle state to the JumpStart state.
如图连连看。
2. Double click the transition to edit it. Control-click on IsFalling in the My Blueprint tab and drag into the graph to create a Get Is Falling node.
双击编辑过渡线。拖入IsFalling创建Get Is Falling 节点。
3. Connect the output Boolean pin on the Get Is Falling node to the input Boolean Can Enter Transition pin on the Result node.
如图连连看。
1. Return to the Arms State Machine graph, and drag a wire from the Run state to the JumpStart state.
如图连连看。
2. Double click the transition to edit it. Control-click on IsFalling in the My Blueprint tab and drag into the graph to create a Get Is Falling node.
双击编辑过渡线。拖入IsFalling创建Get Is Falling 节点。
3. Connect the output Boolean pin on the Get Is Falling node to the input Boolean Can Enter Transition pin on the Result node.
如图连连看。
1. Return to the Arms State Machine graph, and drag a wire from the JumpStart state to the JumpLoop state.
如图连连看。
2. Double click the transition to edit it. For this transition, we want it to happen when the JumpStart animation is nearly finished. Right-click in the graph, then search for and select the TimeRemaining for 'FPP_JumpStart' node.
双击编辑过渡线。此过渡线,我们想要在JumpStart动画近乎完成的时候打开。右键搜索选择TimeRemaining for 'FPP_JumpStart' 节点。
3. Drag off of the Time Remaining output pin, and add a <= (float) node using the context menu.
拖出Time Remaining的输出引脚添加<= (float) 节点。
4. Enter 0.1 in the other input field on the <= (float) node, and then wire the Boolean output pin from that node to the Can Enter Transition input pin on the Result node.
设置连线如图所示。(PS:下图中的FPP_JumpEnd 应为FPP_JumpStart)
1. Return to the Arms State Machine graph, and drag a wire from the JumpLoop state to the JumpEnd state.
如图连连看。
2. Double click the transition to edit it. Control-click on IsFalling in the My Blueprint tab and drag into the graph to create a Get Is Falling node.
双击编辑过渡线。拖入IsFalling创建Get Is Falling 节点。
3. Drag off the output Boolean pin on the Get Is Falling node and create a Not Boolean node. Connect the output Boolean pin on the Not Boolean node to the input Boolean Can Enter Transition pin on the Result node.
拖出Get Is Running的输出引脚创建Not Boolean节点与
1. Return to the Arms State Machine graph, and drag a wire from the JumpEnd state to the Idle state.
如图连连看。
2. Double click the transition to edit it. For this transition, we want it to happen when the JumpEnd animation is nearly finished. Right-click in the graph, then search for and select the TimeRemaining for 'FPP_JumpEnd' node.
双击编辑过渡线。此过渡线,我们想要在JumpEnd动画近乎完成的时候打开。右键搜索选择TimeRemaining for 'FPP_JumpEnd' 节点。
3. Drag off of the Time Remaining output pin, and add a <= (float) node using the context menu.
拖出Time Remaining的输出引脚添加<= (float) 节点。
4. Enter 0.1 in the other input field on the <= (float) node, and then wire the Boolean output pin from that node to the Can Enter Transition input pin on the Result node.
设置连线如图所示。
1. Compile and save the Arms_AnimBP Animation Blueprint, then close it.
编译保存动画Arms_AnimBP蓝图,关闭。
2. Navigate to the Blueprints folder in the Content Browser, then open the BP_FPSCharacter Blueprint.
打开BP_FPSCharacter蓝图。
3. In Defaults mode, find the Animation section, and then the FirstPersonMesh subsection. Set the AnimationBlueprint for theFirstPersonMesh to the Arms_AnimBP Animation Blueprint we just made.
在Defaults模式,找到 Animation 部分,然后找到FirstPersonMesh。为FirstPersonMesh设置AnimationBlueprint成Arms_AnimBP。
4. Also in Defaults mode, change the FirstPersonMesh transform to {0,0,-150} for translation and {0,0,0} for rotation.
改变FirstPersonMesh的位置信息,其中translation为{0,0,-150},rotation为 {0,0,0} 。
5. Compile and save the Blueprint, then close it.
编译保存蓝图,关闭。
6. Play your game in the editor. Your arms will be animated, and will transition through their animations as you play. You have completed the FPS tutorial!
Play运行,你的手臂会动起来,并且在你的操作下过渡动画。你已完成本教程。恭喜你,你已超神。
----------------------------------
4.10 已测试成功,最后的动画只有手臂轻微上抬,没有华丽的动作与特效。
--------------------------------------------------------------------------------------------------------------
1、本文为题主在学习中翻译,同时在UE4.10.2 版本上尝试运行,翻译过程中遇到翻译不出会暂时留白,翻译有误请指出,谢谢!
2、本文在翻译过程中遇到题主不懂的地方可能会添加题主的知识扩展链接。
-------------------------------------------------
在此,再次对博主好友Erin表示感谢。
/** Gun muzzle's offset from the camera location */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay) FVector MuzzleOffset;
UCLASS() class FPSPROJECT_API AFPSGameMode : public AGameMode { GENERATED_BODY() };
virtual void StartPlay() override; // Note that engine version 4.3 changed this method's name to StartPlay(), because of this engine versions before 4.3, or older tutorials, use BeginPlay()
// Note that engine version 4.3 changed the method's name to StartPlay(), because of this engine versions before 4.3, or older tutorials, use BeginPlay() void AFPSGameMode::StartPlay() { Super::StartPlay(); StartMatch(); if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("HELLO WORLD")); } }
UCLASS() class FPSPROJECT_API AFPSGameMode : public AGameMode { GENERATED_BODY() AFPSGameMode(const FObjectInitializer& ObjectInitializer); // Our added constructor virtual void StartPlay() override; };
#include "FPSCharacter.h"
AFPSGameMode::AFPSGameMode(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
DefaultPawnClass = AFPSCharacter::StaticClass();
AFPSGameMode::AFPSGameMode(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DefaultPawnClass = AFPSCharacter::StaticClass(); }