- 1.创建新角色
- FPSCharacter.h
- FPSCharacter.cpp
- 补充:轴映射与动作( *** 作)映射
- 2.设置轴映射
- 3.实现角色移动函数
- FPSCharacter.h
- FPSCharacter.cpp
- 4.实现鼠标摄像机控制
- FPSCharacter.cpp
- Pitch Yaw Roll
- 5.实现角色跳跃
- FPSCharacter.h
- FPSCharacter.cpp
- 6.将网格体添加到角色
- 7.更改摄像机视角
- FPSCharacter.h
- FPSCharacter.cpp
- 8.将第一人称网格体添加到角色(添加手臂)
- FPSCharater.h
- FPSCharater.cpp
- 收尾
- 与本章内容关系不大的话
- 参数解读
本文所有内容皆参考自 实现你的角色 1.创建新角色 FPSCharacter.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AFPSCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
FPSCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
// Sets default values
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// Called every frame
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
至此,新角色创建完毕,我们设置为默认角色,并且创建对应蓝图类。
顺便提一嘴,Charater类继承自Pawn类,而Pawn类又继承自Actor类。
Action *** 作映射:适用于“是/否”输入,当鼠标被按下、松开、双击、按下时间长或者短,都会进行报告,这种一般与射击、跳跃以及开门等物体互动有关。
Axis轴映射:是连续的。
例如手柄上的摇杆、鼠标上的光标等,即使不进行 *** 作,也会逐帧报告,这与我们的视角移动等有关。
会影响到我们行走、四处查看等。
在项目设置中按此设置,完成坐标轴和键盘 *** 作的捆绑。
轴映射会不断被轮询,从而实现无缝的移动过渡和流畅的游戏行为。
下面是官方的说法:
在典型的FPS控制模式中,角色的移动轴是相对于摄像机的。
“向前"移动是指"摄像机指向的方向”,“向右"是指"摄像机指向方向的右侧”。
你将使用 PlayerController 获取角色的控制旋转输入值。
另外, MoveForward 函数将忽略控制旋转输入值的俯仰(Pitch)分量,将输入限制在XY平面上,以确保在你向上或向下看时,你的角色将沿着地面移动。
完成此部分以后,我们的代码应该是这样的:
FPSCharacter.h// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 为此角色的属性设置默认值
AFPSCharacter();
protected:
// 当游戏开始或者重生(Spawn)时被调用
virtual void BeginPlay() override;
public:
// 每一帧都会调用的函数,如果在构造函数中启用的话
virtual void Tick(float DeltaTime) override;
// 被调用,将功能与输入绑定
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//UFUNCTION 宏(位于每个函数上方)让引擎可以发觉这些函数,以便将它们纳入序列化和其他引擎功能中。
//UFUNCTION是处理变量的,而UPRORYTY是处理变量的,功能类似。
//处理前后移动的输入
UFUNCTION()
void MoveForward(float Value);
//处理左右移动的输入
UFUNCTION()
void MoveRight(float Value);
};
FPSCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
// 为此角色的属性设置默认值
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// 当游戏开始或者重生(Spawn)时被调用
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// 每一帧都会调用的函数,如果在构造函数中启用的话
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// 被调用,将功能与输入绑定
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//处理输入数据
//将Axis轴映射的MoveForward与MoveForward()函数绑定
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
//将Axis轴映射的MoveRight与MoveRight()函数绑定
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
}
void AFPSCharacter::MoveForward(float Value) {
//找出前进方向,并记录玩家想向该方向移动
//将此 *** 作和旋转的X轴捆绑
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value) {
//找出右侧的方向并且记录
//此 *** 作与旋转的Y轴进行绑定
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
保存、编译以后,可以直接在地图中试用了。
我们之前说了,移动的坐标轴与玩家的摄像机有关,那么这里我们就设置摄像机并且通过鼠标来控制视角,以此来影响我们的移动。
在项目设置中进行的设置我是直接参考官方文档的,而这里处理鼠标移动的输入,虚幻引擎在Pawn类中,就已经为我们封装好了函数,不需要像"MoveForward"和"MoveRight"那样需要我们自己声明、定义。
在此,我们仅需要修改FPSCharacter.cpp
此时代码应该如下。
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
// 为此角色的属性设置默认值
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// 当游戏开始或者重生(Spawn)时被调用
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// 每一帧都会调用的函数,如果在构造函数中启用的话
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// 被调用,将功能与输入绑定
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//处理输入数据
// 移动的绑定
//将Axis轴映射的MoveForward与MoveForward()函数绑定
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
//将Axis轴映射的MoveRight与MoveRight()函数绑定
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// 观看、视角的绑定
//Yaw对应Z轴
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
//Pitch对应Y轴
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
}
void AFPSCharacter::MoveForward(float Value) {
//找出前进方向,并记录玩家想向该方向移动
//将此 *** 作和旋转的X轴捆绑
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value) {
//找出右侧的方向并且记录
//此 *** 作与旋转的Y轴进行绑定
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
Pitch Yaw Roll
不使用XYZ轴,对应数学的右手坐标系,应该是Pitch、Yaw、Roll,分别和XYZ轴对应。
当时更特别的是,UE4使用的是左手坐标系,跟XYZ轴对应的分别是X——Roll,Y——Pitch,Z——Yaw
5.实现角色跳跃之前我们提到了 *** 作映射和轴映射,实现跳跃这种,按下、松开的时候,才会有相应 *** 作,并不是连续的,我们在 *** 作映射中,按照文档设置出一个Jump参数。
而ACharacter基类中有一个bPressedJump变量与角色跳跃捆绑了,我们只需要通过玩家按键,来修改bPressedJump变量的值,就可以实现跳跃了。
进行相应增加后,对应头文件和源代码如下。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 为此角色的属性设置默认值
AFPSCharacter();
protected:
// 当游戏开始或者重生(Spawn)时被调用
virtual void BeginPlay() override;
public:
// 每一帧都会调用的函数,如果在构造函数中启用的话
virtual void Tick(float DeltaTime) override;
// 被调用,将功能与输入绑定
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//UFUNCTION 宏(位于每个函数上方)让引擎可以发觉这些函数,以便将它们纳入序列化和其他引擎功能中。
//UFUNCTION是处理变量的,而UPRORYTY是处理变量的,功能类似。
//处理前后移动的输入
UFUNCTION()
void MoveForward(float Value);
//处理左右移动的输入
UFUNCTION()
void MoveRight(float Value);
//Acharacter类内置了一个bPressedJump变量与角色跳跃绑定
//按下空格,置跳跃标志为true
UFUNCTION()
void StartJump();
//松开空格,置跳跃标志为false
UFUNCTION()
void StopJump();
};
FPSCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
// 为此角色的属性设置默认值
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// 当游戏开始或者重生(Spawn)时被调用
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// 每一帧都会调用的函数,如果在构造函数中启用的话
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// 被调用,将功能与输入绑定
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//处理输入数据
// 移动的绑定
//将Axis轴映射的MoveForward与MoveForward()函数绑定
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
//将Axis轴映射的MoveRight与MoveRight()函数绑定
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// 观看、视角的绑定
//Yaw对应Z轴,左右是绕着Z轴旋转
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
//Pitch对应Y轴,上下是绕着Y轴旋转
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
//设置跳跃 *** 作的绑定
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}
void AFPSCharacter::MoveForward(float Value) {
//找出前进方向,并记录玩家想向该方向移动
//将此 *** 作和旋转的X轴捆绑
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value) {
//找出右侧的方向并且记录
//此 *** 作与旋转的Y轴进行绑定
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
//按下空格,置跳跃标志为true
void AFPSCharacter::StartJump() {
bPressedJump = true;
}
//松开空格,置跳跃标志为false
void AFPSCharacter::StopJump() {
bPressedJump = false;
}
至此,保存、编译后,便可以 *** 作一个可以前后左右移动、转动视角、实现跳跃的角色了。
这部分没什么好说的,从文档中的链接去下载网格体的压缩包,然后找一个地方解压,再按照文档说明导入就行。
但是在测试的时候,你可以发现摄像机视角很怪,可以看到自己大肚子emmmm,这就需要我们在下一部分作出调整
7.更改摄像机视角现在FPSCharater.h引入两个头文件
并在类中增加一个摄像机组件
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
//下面部分添加为类的成员变量
//添加一个摄像机组件给角色
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
最终。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 为此角色的属性设置默认值
AFPSCharacter();
protected:
// 当游戏开始或者重生(Spawn)时被调用
virtual void BeginPlay() override;
public:
// 每一帧都会调用的函数,如果在构造函数中启用的话
virtual void Tick(float DeltaTime) override;
// 被调用,将功能与输入绑定
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//UFUNCTION 宏(位于每个函数上方)让引擎可以发觉这些函数,以便将它们纳入序列化和其他引擎功能中。
//UFUNCTION是处理变量的,而UPRORYTY是处理变量的,功能类似。
//处理前后移动的输入
UFUNCTION()
void MoveForward(float Value);
//处理左右移动的输入
UFUNCTION()
void MoveRight(float Value);
//Acharacter类内置了一个bPressedJump变量与角色跳跃绑定
//按下空格,置跳跃标志为true
UFUNCTION()
void StartJump();
//松开空格,置跳跃标志为false
UFUNCTION()
void StopJump();
//添加一个摄像机组件给角色
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
};
接着,我们在构造函数中对其摄像机组件进行初始化。
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"
#include "Engine/Engine.h"
// 为此角色的属性设置默认值
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// 创建第一人称摄像机组件
FPSCameraComponent = CreateDefauleSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
// 将摄像机组件附加到我们的"胶囊体"网格体上
check(FPSCameraComponent != nullptr);
// 此代码创建 UCameraComponent,并将其附加到角色的 CapsuleComponent
FPSCameraComponent->SetupAttachment(CastChecked<USceneComponent, UCapsuleComponent>(GetCapsuleComponent()));
// 将摄像机置于略高于眼睛上方的位置,SetRelativeLocation用于设置组件默认值
FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
//启用Pawn控制摄像机旋转
FPSCameraComponent->bUsePawnControlRotation = true;
}
// 当游戏开始或者重生(Spawn)时被调用
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// 每一帧都会调用的函数,如果在构造函数中启用的话
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// 被调用,将功能与输入绑定
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//处理输入数据
// 移动的绑定
//将Axis轴映射的MoveForward与MoveForward()函数绑定
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
//将Axis轴映射的MoveRight与MoveRight()函数绑定
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// 观看、视角的绑定
//Yaw对应Z轴,左右是绕着Z轴旋转
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
//Pitch对应Y轴,上下是绕着Y轴旋转
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
//设置跳跃 *** 作的绑定
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}
void AFPSCharacter::MoveForward(float Value) {
//找出前进方向,并记录玩家想向该方向移动
//将此 *** 作和旋转的X轴捆绑
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value) {
//找出右侧的方向并且记录
//此 *** 作与旋转的Y轴进行绑定
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
//按下空格,置跳跃标志为true
void AFPSCharacter::StartJump() {
bPressedJump = true;
}
//松开空格,置跳跃标志为false
void AFPSCharacter::StopJump() {
bPressedJump = false;
}
8.将第一人称网格体添加到角色(添加手臂)
这里呢,其实和之前导入网格体的流程差不多,同样需要通过链接下载一个网格体,并且给角色添加一个组件。
由于 *** 作和之前基本一致,在此就只放代码了。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "FPSCharacter.generated.h"
class UCameraComponent;
class USkeletalMeshComponent;
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 为此角色的属性设置默认值
AFPSCharacter();
protected:
// 当游戏开始或者重生(Spawn)时被调用
virtual void BeginPlay() override;
public:
// 每一帧都会调用的函数,如果在构造函数中启用的话
virtual void Tick(float DeltaTime) override;
// 被调用,将功能与输入绑定
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//UFUNCTION 宏(位于每个函数上方)让引擎可以发觉这些函数,以便将它们纳入序列化和其他引擎功能中。
//UFUNCTION是处理变量的,而UPRORYTY是处理变量的,功能类似。
//处理前后移动的输入
UFUNCTION()
void MoveForward(float Value);
//处理左右移动的输入
UFUNCTION()
void MoveRight(float Value);
//Acharacter类内置了一个bPressedJump变量与角色跳跃绑定
//按下空格,置跳跃标志为true
UFUNCTION()
void StartJump();
//松开空格,置跳跃标志为false
UFUNCTION()
void StopJump();
//添加一个摄像机组件给角色
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
//第一人称网格体(手臂),仅对所属玩家可见
//添加一个网格体组件
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* FPSMesh;
};
FPSCharater.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSCharacter.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"
#include "Engine/Engine.h"
// 为此角色的属性设置默认值
AFPSCharacter::AFPSCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//************************************************
// 创建第一人称摄像机组件
FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
// 将摄像机组件附加到我们的"胶囊体"网格体上
check(FPSCameraComponent != nullptr);
// 此代码创建 UCameraComponent,并将其附加到角色的 CapsuleComponent
FPSCameraComponent->SetupAttachment(CastChecked<USceneComponent, UCapsuleComponent>(GetCapsuleComponent()));//GetCapsuleComponent()返回一个胶囊体指针,需要强转
// 将摄像机置于略高于眼睛上方的位置,SetRelativeLocation用于设置组件默认值
FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
//启用Pawn控制摄像机旋转
FPSCameraComponent->bUsePawnControlRotation = true;
//************************************************
//************************************************
//为所属玩家创建第一人称网格体组件
FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
check(FPSMesh != nullptr);
//仅手臂所属玩家可以看见此网格体
FPSMesh->SetOnlyOwnerSee(true);
//将FPS网格体附加到FPS摄像机
FPSMesh->SetupAttachment(FPSCameraComponent);
//禁用手臂阴影,不然看着会有点奇怪
FPSMesh->bCastDynamicShadow = false;
FPSMesh->CastShadow = false;
// 所属玩家看不到常规(第三人称)全身网格体,营造第一人称的感觉
GetMesh()->SetOwnerNoSee(true);
//SetOnlyOwnerSee 表示此网格体仅对拥有此角色的 PlayerController 可见。
// 此代码还将网格体附加到摄像机,并禁用某些环境阴影。
让手臂投射阴影会破坏第一人称角色应该只有单个网格体的感觉。
//************************************************
}
// 当游戏开始或者重生(Spawn)时被调用
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
//输出日志方便我们确认BeginPlay()已经运行
check(GEngine != nullptr);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
// 每一帧都会调用的函数,如果在构造函数中启用的话
void AFPSCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// 被调用,将功能与输入绑定
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//处理输入数据
// 移动的绑定
//将Axis轴映射的MoveForward与MoveForward()函数绑定
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
//将Axis轴映射的MoveRight与MoveRight()函数绑定
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// 观看、视角的绑定
//Yaw对应Z轴,左右是绕着Z轴旋转
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
//Pitch对应Y轴,上下是绕着Y轴旋转
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
//设置跳跃 *** 作的绑定
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}
void AFPSCharacter::MoveForward(float Value) {
//找出前进方向,并记录玩家想向该方向移动
//将此 *** 作和旋转的X轴捆绑
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value) {
//找出右侧的方向并且记录
//此 *** 作与旋转的Y轴进行绑定
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
//按下空格,置跳跃标志为true
void AFPSCharacter::StartJump() {
bPressedJump = true;
}
//松开空格,置跳跃标志为false
void AFPSCharacter::StopJump() {
bPressedJump = false;
}
收尾
最后,就是设置一下发射物的声明周期,做一些碰撞规则的定义,再就是添加一个十字准星都屏幕中央。
做完这些,这个FPS游戏的C++部分也就到此为止了,下一步添加动画,官方完全就是以蓝图的形式在制作了,那部分我就不打算深入下去了。
所有的代码在官网文档上面都有,我这个学习的过程也只是照着官网的敲,并且熟悉一下流程。
接下来我打算跟着另外一个实战开发,争取开发出一个像模像样的小游戏。
马上就要面试网易互娱的游戏研发岗了,在宣讲会上面面试官提到了找一个开源游戏引擎,在代码中找到与自己学过理论相关的地方,去进行深入的学习。
这相当于是学习虚幻引擎过程中的一个额外的任务吧。
在此我想提一下这个任务,我的完成情况。
首先,在实现角色移动函数里面,有那么两句代码。
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
从字面意义上BindAxis中去理解,我们可以大概知道它的作用就是"绑定轴映射"。
我再去浏览了对应函数的定义,定义如下。
template<class UserClass>
FInputAxisBinding& BindAxis( const FName AxisName, UserClass* Object, typename FInputAxisHandlerSignature::TUObjectMethodDelegate< UserClass >::FMethodPtr Func )
{
FInputAxisBinding AB( AxisName );
AB.AxisDelegate.BindDelegate(Object, Func);
AxisBindings.Emplace(MoveTemp(AB));
return AxisBindings.Last();
}
参数解读
- 需要传入一个轴映射里面,我们设置好的数据名称。
例如我们前面在轴映射设置的"MoveForward"、"MoveRight"等就是。
- 需要我们传入一个UserClass类的指针。
- 前面两个参数的数据类型都比较正常,第三个就有点奇怪了。
下面我们来细说一下这个参数。
首先,由开始的语句可知这是一个函数模板,而这个typename就是用来给第三个参数使用的。
template<class UserClass>
而这里则是结构体嵌套了一个模板结构体,再嵌套一个模板结构体里面的函数指针。
typename FInputAxisHandlerSignature::TUObjectMethodDelegate< UserClass >::FMethodPtr Func
我之前曾经了解过,怎么在C语言中实现多态,所使用到的方法就是函数指针。
具体可以参考如下链接:
C语言实现多态
因为在C语言里面,并不存在C++那样重写或者重载这样的多态实现方式。
结构体作为C语言的部分,当然也没办法通过C++的方式去实现。
那么想要调用一个结构体的函数,以类似C++调用类里函数,就需要使用函数指针。
在此,就利用函数指针实现了结构体与函数的多态绑定。
——简单一点的说法就是绑定函数。
提到绑定函数,我又想到C++里面使用到的绑定函数有两种方法,一个是std::function,另一个是std::bind。
然后我就试着去想了一下,这个地方能否可以用这两个来代替。
bind是将函数和一些变量或者常量 绑定,类似于 默认参数函数那样,而function也是类似的 *** 作,可以拿一些变量名和函数之间作映射。
但似乎都不适用于这个地方。
因为它这里只是负责传递参数给其他函数,而将要传递参数给到的函数,里面具体是怎么实现的,这个在编写模板类的时候是没法知道的,也就没法使用这两个方法,只能依靠函数指针。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)