虚幻四引擎学习之C++编程(一)
来源:互联网 发布:c语言入门视频教程 编辑:程序博客网 时间:2024/05/16 10:31
最近因为ACM省赛以及参加笔试面试等原因,许久没有更新博客,由于实习公司的原因,最近开始看虚幻四引擎的官方文档,这篇博客是对官方文档中C++编程部分第一人称FPS部分的代码分析和总结。
一、GameMode
GameMode又称游戏模式(其实就是翻译过来),它存在的意义是制定游戏的规则,比如龟兔赛跑,其规则就是谁先到达终点谁就获胜,它仅存在于服务器上。
在官方文档的第一人称FPS教程部分,有稍微提到过GameMode,代码如下:
FPSProjectGameMode.h
#pragma once#include "GameFramework/GameMode.h"#include "FPSProjectGameMode.generated.h"/** * GameMode类用于构建游戏规则 */UCLASS()class FPSPROJECT_API AFPSProjectGameMode : public AGameMode{ GENERATED_BODY() virtual void StartPlay() override;//重写AGameMode基类的虚函数StartPlay};
FPSProjectGameMode.cpp
#include "FPSProject.h"#include "FPSProjectGameMode.h"void AFPSProjectGameMode::StartPlay(){ Super::StartPlay();//Super类即为AGameMode类 if (GEngine) { // 显示调试信息五秒。 // -1“键”值(首个参数)说明我们无需更新或刷新此消息。 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!")); }}
二、Pawn与Character
Pawn可由玩家或 AI 控制的所有 Actors 的基础类。而Actor可以简单认为是游戏世界中的任何可以动作的物体(我暂时这么理解)。Character是类人的Pawn,它自带许多组件,比如CharacterMovementComponent(移动组件)、CapsuleComponent(胶囊体组件)和SkeletalMesh(骨骼网格组件)。
官方教程在这里给出了FPS基本的动作比如:移动、跳跃、开火)
代码如下:
FPSCharacter.h
#pragma once#include "GameFramework/Character.h"#include "FPSCharacter.generated.h"UCLASS()class FPSPROJECT_API AFPSCharacter : public ACharacter{ GENERATED_BODY()public: // 设置该角色属性的默认值。 AFPSCharacter(); // 游戏开始时或生成时调用。 virtual void BeginPlay() override;//重写Actor的BeginPlay函数 // 每帧调用。 virtual void Tick(float DeltaSeconds) override;//重写Actor的Tick函数 // 调用后将功能绑定到输入。 virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override;//重写Character的SetupPlayerInputComponent函数 // 处理前后移动的输入。UFUNCTION表示将该函数注册到蓝图中 UFUNCTION() void MoveForward(float Value); // 处理左右移动的输入。 UFUNCTION() void MoveRight(float Value); // 按下按键时设置跳跃标记。 UFUNCTION() void StartJump(); // 松开按键时清除跳跃标记。 UFUNCTION() void StopJump(); // 处理开火的函数。 UFUNCTION() void Fire(); // FPS 摄像机。UPROPERTY表示将一个类成员注册到蓝图中 UPROPERTY(VisibleAnywhere) UCameraComponent* FPSCameraComponent;//定义一个UCameraComponent——相机组件 // 第一人称模型(手臂),仅对拥有玩家可见。 UPROPERTY(VisibleDefaultsOnly, Category = Mesh) USkeletalMeshComponent* FPSMesh;//定义一个USkeletalMeshComponent——骨骼网格组件 // 从摄像机位置的枪口偏移。 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay) FVector MuzzleOffset; // 生成的发射物类。 UPROPERTY(EditDefaultsOnly, Category = Projectile) TSubclassOf<class AFPSProjectile> ProjectileClass;//AFPSProjectile类及其子类的类型引用,在蓝图中会使其可以通过下拉菜单来详细指定其类型};
FPSCharacter.cpp
#include "FPSProject.h"#include "FPSCharacter.h"#include "FPSProjectile.h"// 设置默认值AFPSCharacter::AFPSCharacter(){ // 设置此角色每帧调用 Tick()。不需要时可将此关闭,以提高性能。 PrimaryActorTick.bCanEverTick = true; // 创建一个第一人称摄像机组件。 //CreateDefaultSubobject创建一个组件或者子对象 FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera")); // 将摄像机组件附加到胶囊体组件。 //Character类在Pawn基础上含有CharacterMovementComponent、CapsuleComponent和SkeletalMesh组件 //GetCapsuleComponent得到character类中胶囊提组件的指针 FPSCameraComponent->AttachTo(GetCapsuleComponent()); // 将摄像机放置在眼睛上方不远处。 //BaseEyeHeight是Pawn类中的成员 //SetRelativeLocation设置局部空间中的位置 FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight)); // 用 pawn 控制摄像机旋转。 FPSCameraComponent->bUsePawnControlRotation = true; // 为拥有玩家创建一个第一人称模型组件。 FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh")); // 该模型仅对拥有玩家可见。 FPSMesh->SetOnlyOwnerSee(true); // 将 FPS 模型添加到 FPS 摄像机。 FPSMesh->AttachTo(FPSCameraComponent); // 禁用部分环境阴影,保留单一模型存在的假象。 FPSMesh->bCastDynamicShadow = false; FPSMesh->CastShadow = false; // 拥有玩家无法看到普通(第三人称)身体模型。 //GetMesh是character类中的函数,返回绑定在character类(基类)中的骨骼模型 GetMesh()->SetOwnerNoSee(true);}// 游戏开始时或生成时调用。void AFPSCharacter::BeginPlay(){ Super::BeginPlay();//调用基类的BeginPlay函数?? if (GEngine) { // 显示调试信息五秒。-1“键”值(首个参数)说明我们无需更新或刷新此消息。 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter.")); }}// 每帧调用。void AFPSCharacter::Tick(float DeltaTime){ Super::Tick(DeltaTime);}// 调用后将功能绑定到输入。void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* InputComponent){ Super::SetupPlayerInputComponent(InputComponent); // 设置“移动”绑定。 InputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward); InputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight); // 设置“查看”绑定。 InputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput); InputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput); // 设置“动作”绑定。 InputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump); InputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump); InputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);}void AFPSCharacter::MoveForward(float Value){ // 明确哪个方向是“前进”,并记录玩家试图向此方向移动。 //Controller是Pawn定义的成员即为控制该Pawn的控制器,GetControlRotation获得控制器的旋转角,GetScaledAxis的到某一个轴的值(这里是矩阵的第一列即X轴) FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X); AddMovementInput(Direction, Value);}void AFPSCharacter::MoveRight(float Value){ // 明确哪个方向是“向右”,并记录玩家试图向此方向移动。 FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y); AddMovementInput(Direction, Value);}void AFPSCharacter::StartJump(){ bPressedJump = true;}void AFPSCharacter::StopJump(){ bPressedJump = false;}void AFPSCharacter::Fire(){ // 尝试发射物体。 if (ProjectileClass) { // 获取摄像机变换。 FVector CameraLocation; FRotator CameraRotation; //如果存在Controller或它的Pawn,这个函数则返回Controller或他的Pawn的视角。基本上,它会返回玩家从哪个位置和方向观看。 GetActorEyesViewPoint(CameraLocation, CameraRotation); // 将 MuzzleOffset 从摄像机空间变换到世界空间。 FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset); FRotator MuzzleRotation = CameraRotation; // 将准星稍微上抬。 MuzzleRotation.Pitch += 10.0f; UWorld* World = GetWorld(); if (World) { //FActorSpawnParameters是world类中的结构体,表示游戏世界中的一个pawn。。。(大概是这样) FActorSpawnParameters SpawnParams; SpawnParams.Owner = this; //Instigator是可以对pawn造成伤害的actor SpawnParams.Instigator = Instigator; // 在枪口处生成发射物。 //SpawnActor用来创建Actor类型的物体(物体类型,生成地点,生成方向,和世界中的一个物体??) AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams); if (Projectile) { // 设置发射物的初始轨道。 FVector LaunchDirection = MuzzleRotation.Vector(); Projectile->FireInDirection(LaunchDirection); } } }}
三、发射物的实现
这里,因为发射物是一个不需要AI或玩家控制的物体,但是其也会进行运动,所以该类继承自Actor类即可。
我们只需计算它的运动状态(碰撞啊之类的)即可。
FPSProjectile.h
#pragma once#include "GameFramework/Actor.h"#include "FPSProjectile.generated.h"UCLASS()class FPSPROJECT_API AFPSProjectile : public AActor{ GENERATED_BODY()public: // 设置该 actor 属性的默认值。 AFPSProjectile(); // 游戏开始时或生成时调用。 virtual void BeginPlay() override; // 每帧调用。 virtual void Tick(float DeltaSeconds) override; // 球体碰撞组件。 UPROPERTY(VisibleDefaultsOnly, Category = Projectile) USphereComponent* CollisionComponent; // 发射物运动组件。 UPROPERTY(VisibleAnywhere, Category = Movement) UProjectileMovementComponent* ProjectileMovementComponent; // 在发射方向上设置发射物初速度的函数。 void FireInDirection(const FVector& ShootDirection); // 发射物命中物体时调用的函数。 void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);};
FPSProjectile.cpp
#include "FPSProject.h"#include "FPSProjectile.h"// 设置默认值AFPSProjectile::AFPSProjectile(){ // 将此 actor 设为每帧调用 Tick()。不需要时可将此关闭,以提高性能。 PrimaryActorTick.bCanEverTick = true; // 使用球体代表简单碰撞。 CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent")); //BodyInstance存储这个组件的物理信息,并持有一个刚体 CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile")); //OnComponentHit检测碰撞,当发生碰撞后调用某个函数 CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit); // 设置球体的碰撞半径。 CollisionComponent->InitSphereRadius(15.0f); // 将碰撞组件设为根组件。 RootComponent = CollisionComponent; // 使用此组件驱动此发射物的运动。 ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent")); //设置作为碰撞物的组件 ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent); //初始速度 ProjectileMovementComponent->InitialSpeed = 3000.0f; //最大速度 ProjectileMovementComponent->MaxSpeed = 3000.0f; //方向是否受速度影响 ProjectileMovementComponent->bRotationFollowsVelocity = true; //是否反弹 ProjectileMovementComponent->bShouldBounce = true; ProjectileMovementComponent->Bounciness = 0.3f; // 3 秒后消亡。 InitialLifeSpan = 10.0f;}// 游戏开始时或生成时调用。void AFPSProjectile::BeginPlay(){ Super::BeginPlay();}// 每帧调用。void AFPSProjectile::Tick(float DeltaTime){ Super::Tick(DeltaTime);}// 在发射方向上设置发射物初速度的函数。void AFPSProjectile::FireInDirection(const FVector& ShootDirection){ ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;}// 发射物命中物体时调用的函数。//UPrimitiveComponent具有某种形式的表现,如网格,粒子等可见的东西;//HitComponent撞击物体//OtherActor被撞物体//OtherComponent被撞物体的组件//FHitResult存储碰撞结果(发出射线进行碰撞检测然后存储结果)void AFPSProjectile::OnHit(UPrimitiveComponent* HitComponent,AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit){ //IsSimulatingPhysics判断是否遵循物理现象 //注意父组件与子组件是两个实体,如果有二者满足碰撞条件,注意不要让二者重叠, //否则一旦游戏中产生这个Actor,两个组件就会以一定的速度相互排斥开来。 //所以不要随意开启组件的simulate physics并且注意各个组件之间的关系。 //而这里添加OtherActor != this这句话也可以防止该实体自身的组件间的发生碰撞 if (OtherActor != this && OtherComponent->IsSimulatingPhysics()) { //ImpactPoint碰撞点 //AddImpulseAtLocation(冲量,位置)——在某一位置增加一个冲量 OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 1000000.0f, Hit.ImpactPoint); }}
四、HUD准星的实现
FPSHUD.h
#pragma once#include "GameFramework/HUD.h"#include "FPSHUD.generated.h"/** * */UCLASS()class FPSPROJECT_API AFPSHUD : public AHUD{ GENERATED_BODY()protected: // 这将在屏幕中央绘制。 //UTexture2D——2D纹理类型 UPROPERTY(EditDefaultsOnly) UTexture2D* CrosshairTexture;public: // HUD 的主绘制调用。 virtual void DrawHUD() override;};
FPSHUD.cpp
#include "FPSProject.h"#include "FPSHUD.h"void AFPSHUD::DrawHUD(){ Super::DrawHUD(); if (CrosshairTexture) { // 找到画布中心。 FVector2D Center(Canvas->ClipX*0.5f, Canvas->ClipY*0.5f); // 纹理维度一半偏移,使纹理中心和画布中心对齐。 FVector2D CrossHairDrawPosition(Center.X - (CrosshairTexture->GetSurfaceWidth() * 0.5f), Center.Y - (CrosshairTexture->GetSurfaceHeight() * 0.5f)); // 在中心点绘制准星。 FCanvasTileItem TileItem(CrossHairDrawPosition, CrosshairTexture->Resource, FLinearColor::White); TileItem.BlendMode = SE_BLEND_Translucent; Canvas->DrawItem(TileItem); }}
阅读全文
0 0
- 虚幻四引擎学习之C++编程(一)
- 虚幻引擎学习之路:渲染模块之光照系统
- 虚幻引擎学习之路:渲染模块之材质系统
- 虚幻引擎学习之路:动画模块之基础篇
- 虚幻引擎学习之路:相机图像后处理
- 虚幻引擎4系列教程1(霜之小刀)(附视频)--虚幻引擎4(UE4)安装教程
- 学习Linux C编程之网络编程(一)
- Unreal Engine 虚幻引擎 开启我的虚幻之旅
- 学习Linux C编程之进程间通信(一)
- cocos2d学习笔记(十)物理引擎box2d之四
- C专家编程学习笔记——第三章(四):C语言声明之 typedef
- 虚幻引擎源码分析(1)
- 虚幻引擎源码分析(2)
- 虚幻引擎源码分析(3)
- 虚幻引擎源码分析(4)
- 虚幻引擎源码分析(5)
- 虚幻引擎源码分析(6)
- 虚幻引擎源码分析(8)
- 管道重定向
- 错误: -source 1.6 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符)
- React-native IT喵喵~路由之React Navigation
- TypeScript的使用(与Angular2搭配)
- 不平衡语料的分类
- 虚幻四引擎学习之C++编程(一)
- splunk
- WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断
- java环境变量配置注意
- scala小练习四
- g2o小记
- 进程间通信--IPC之共享内存
- zTree学习笔记一:实现checkbox、全选、取消全选功能
- 论文查重