UE C++学习笔记

这是siki学院的公开课内容,详细视频教程可见B站链接:

Unreal入门第一季 - 虚幻C++基础训练_哔哩哔哩_bilibili

了解玩这一套基本理论语法之后完全可以上手UE的官方教程进行练习,并对其代码有更深一层的理解。

反射与垃圾回收系统

  1. 反射:程序运行时检查自身的能力,将变量等暴露给蓝图,编辑器,允许运行时调用
  2. 垃圾回收:检测某个对象是否不再被使用,不再适用会被标记成垃圾,在适当时候进行回收
  3. 如何使用:使用宏,之后紧跟的一段代码会参与反射与垃圾回收

 创建UObject子类

  1. 右键 New C++ Classes 选择所需父类,点击Next,进行创建

UCLASS(Blueprintable)//指示可转化为蓝图使用如果父类写了这里不写也可以

class MYBASICTRAINING_API UMyObject : public UObject

{

GENERATED_BODY()

};

  1. 使用UE自己的编译器,在window->Developer Tools->Message Log->Compiler Log可查看编译信息
  2. 右键这个C++类,可生成对应的蓝图

基础宏参数介绍

  1. 变量(希望可在蓝图中被读写)——BlueprintReadWrite——之后在蓝图编辑器中有Get/Set对用的节点
  2. 函数(希望可在蓝图中调用)——BlueprintCallable——之后在蓝图编辑器中右键搜索函数名可调用
  3. 只读——BlueprintReadonly
  4. 分类——Category:UPROPERTY(BlueprintReadWrite,Category="My Variable")

实现打印及实例化一个继承自Object的类

  1. UE_LOG(LogTemp,Log/Warning/Error,TEXT(“Hello World”)),在window->Developer Tools->Output Log中查看
  2. 实例化Construct object from class

 调用类的方法

 如何删除自定义的C++类

  1. 删除该类派生出的蓝图等资源
  2. 关闭对应VS代码
  3. 找到对应项目工程目录,找到Source(存储的就是自定义的类),进入Source找到与工程同名文件夹,找到需要删除的C++的.cpp和.h文件,进行删除
  4. 退回到Source同级目录,找到Binaries文件夹,整个一起删除
  5. 右键uproject文件,重新生成VS文件(Generate Visual Studio project files)

创建Actor子类和学习命名规范

  1. 创建C++类的目录下是不能直接加文件夹的,但是可以在创建时在路径中手动输入
  2. Actor的beginplay在游戏开始或者这个Actor生成(spawn)时回调
  3. 使用Actor.h中定义的变量控制是否每帧都调用:AActor::PrimaryActorTick.bCanEverTick = true;
  4. 继承自Actor使用A开头,Object使用U开头

在C++中创建静态网格组件

  1. 在头文件中声明:

//组件继承自UObject,所以是用U开头

UPROPERTY(VisibleAnywhere,Categroy="My Actor Componets")//对于组件的标记

UStaticMeshComponent* StaticMesh;

  1. 对变量赋初值.cpp构造函数中:

//使用创建子物体函数(前默认为this),参数填写该组件的标识(非名字),使用指针名作为组件名

StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyStaticMesh"));

  1. 为C++类创建组件之后就可以将其直接拖到场景中了(拥有了组件提供的transform)
  2. 场景内的静态网格,选中后使用菜单栏中的蓝图下拉菜单,有转化为蓝图类的选项(Convert Select Actor to Blueprint Class)

UPROPERTY中的参数使用简介

使用SetActorLocation控制位置与宏参数EditInstanceOnly介绍

  1. 设置使用者的位置:SetActorLocation(InitLocation);参数是一个FVector
  2. 对参数FVector可以限定EditInstanceOnly:仅实例化的对象可编辑,对于创建他的蓝图类是不能编辑的

UPROPERTY(EditInstanceOnly, Category = "My Actor Properties | Vector")//|表示到下一级目录

FVector InitLocation;

  1. 默认单位是cm

VisibleInstanceOnly与EditDefaultsOnly宏参数

  1. 只在实例化对象上显示,不可编辑VisibleInstanceOnly
  2. bool型变量须以小写b开头
  3. EditDefaultsOnly只可默认编辑——只可在类模板中编辑

VisibleDefaultsOnly与EditAnywhere宏参数

  1. 带defaults就只能显示在蓝图类中
  2. EditAnywhere任何地方(蓝图类与实例化对象中都可以编辑)

在编辑器中限制输入值的范围及不要将组件指针设置为EditAnywhere

  1. 不要将组件指针设置为EditAnywhere,这将导致该指针指向的对象可改变,那么因为继承关系的存在,子类也可以为这个指针赋值,将导致对象类型不明
  2. 在编辑器中限制输入值的范围:使用meta

UPROPERTY(EditAnywhere, Category = "My Actor Properties | Vector", meta = (ClampMin = -5.0f, ClampMax = 5.0f, UIMin = -5.0f, UIMax = 5.0f))//Clamp表示限制值的范围,UIMxx表示使用UI拖动时的范围

FVector LocationOffset;

物理系统

简单碰撞与复杂碰撞

  1. 双击打开模型资源文件,勾选Collision中的选项可显示碰撞体;
  2. 创建碰撞则在上方菜单栏下拉框中,选择创建何种类型的碰撞,下方提供了Auto Convert自动生成凸包的一个算法;

模拟物理与重力

  1. 选择场景对象,找到其physical选项卡,勾选Simulate Physic即可启动物理模拟(先要生成其碰撞体才能勾选)
  2. 注意physical中是否启用重力选项,仅仅也只是针对当前模型;
  3. 运行时,使用~键调出控制台,输入命令:show Collision查看场景物体的碰撞体

通过代码添加力与力矩

  1. 提示不完整的类类型,一般是头文件没有包含,查找头文件通过unreal.doc文档进行搜索(搜索不到注意切换为英文),翻到Header栏目,一般是Classes后边就是头文件路径。注意在.h中加入#include包含头文件要加载generate之前,在cpp中就是加最后一个#include之后就可以;
  2. 对模型网格添加力AddForce:

StaticMesh->AddForce(InitForce);//注意AddForce的默认参数,第三个可设置是否忽略质量进行加速

  1. 使用AddTorque添加力矩,用法同上;

使用Sweep在不开启物理模拟的情况下进行碰撞

  1. 是函数AddActorLocalOffset的第二个参数,表示是否扫描,是的时候会对即将移动到的路径上进行一个扫描,当发现有物体时,就不去移动了,产生一个遮挡的效果:AddActorLocalOffset(LocationOffset,true);

碰撞通道与击中信息

  1. 碰撞通道:在Collision Presets(碰撞预设)中修改为custom,由用户自定义检测哪些通道进行碰撞的检测,可用于检测过滤等
  2. AddActorLocalOffset的第三个参数传出碰撞结果信息:

FHitResult hitResult;

AddActorLocalOffset(LocationOffset,true,&hitResult);

UE_LOG(LogTemp, Warning, TEXT("X:%f,Y:%f,Z:%f\n"), hitResult.Location.X, hitResult.Location.Y, hitResult.Location.Z);

常用函数与可探索部分

Get/Set——Location/Rotation/Scale

FMath数学类

创建自己的Pawn类,自己的根组件并将静态网格组件附加到其上

  1. 选择继承于Pawn创建自己的Pawn类;
  2. Pawn相比于Actor多出来一个函数,用于接收玩家输入:

virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

  1. 创建根组件

//创建根组件,可能是从父类继承来的,不需要声明而是直接赋值

RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));

  1. 创建静态网格组件:

MyStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyStaticMesh"));

  1. 将静态网格附加到根组件上,包括获取根组件方式在内有多种方法:

MyStaticMesh->SetupAttachment(GetRootComponent());

MyStaticMesh->SetupAttachment(RootComponent);

MyStaticMesh->AttachTo(RootComponent);

为Pwan设置摄像机

  1. 像添加静态网格体一样作为组件添加到根组件上:

MyCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("MyCamera"));

MyCamera->SetupAttachment(RootComponent);

  1. 控制调整相机相对于根组件的位置:

MyCamera->SetRelativeLocation(FVector(-300.0f, 0.0f, 300.0f));

MyCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));

设置GameMode使之自动持有我们建立的Pawn

  1. GameMode是一种游戏规则的定义,可以在C++ Classes文件夹下找到,是系统自动创建出来的,我们可以对其右键创建其对应蓝图,对里边的量进行设置;
  2. 双击打开建立的蓝图类,在Class Default中找到Default Pawn Class进行设置(选择我们自己想要的)
  3. 找到场景的WorldSetting中的GameMode,选择设置我们自己创建的GameMode蓝图类
  4. 设置操控接收信息:AutoPossessPlayer = EAutoReceiveInput::Player0;

按键映射与轴事件绑定

  1. 在Edit->projectsetting->Input
  2. 间断性的动作使用Action map,连续性动作使用轴映射Axis map,如WSAD操作,前后左右移动

 1.在头文件中声明对应的前后左右移动函数,并创建定义:

void MoveForward(float Value);

void MoveRight(float Value);

void AMyPawn::MoveForward(float Value)

{

}

void AMyPawn::MoveRight(float Value)

{

}

  1. 在Pawn类的SetupPlayerInputComponent函数中绑定操作事件

PlayerInputComponent->BindAxis(TEXT("MoveForward")/*操作明,在Input中的设置*/, this/**绑定到哪个类*/, &AMyPawn::MoveForward/*响应函数的引用*/);

PlayerInputComponent->BindAxis(TEXT("MoveRight")/*操作明,在Input中的设置*/, this/**绑定到哪个类*/, &AMyPawn::MoveRight/*响应函数的引用*/);

  1. 为响应函数添加实现:进入响应函数后,修改变量Velocity的值,并在Tick里边实现调用

void AMyPawn::MoveForward(float Value)

{

Velocity.X = FMath::Clamp(Value, -1.0f, 1.0f)*maxSpeed;

}

void AMyPawn::MoveRight(float Value)

{

Velocity.Y = FMath::Clamp(Value, -1.0f, 1.0f)*maxSpeed;

}

void AMyPawn::Tick(float DeltaTime)

{

Super::Tick(DeltaTime);

AddActorLocalOffset(Velocity*DeltaTime, true);

}

  1. 控制台t.maxFPS 10(调节最大帧率)

添加SpringArm组件

  1. 类似于拍电影的摄像机悬臂:

MySpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("MySpringArm"));

MySpringArm->SetupAttachment(MyStaticMesh);

MySpringArm->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));

MySpringArm->TargetArmLength = 400.0f;//作用相当于摄像机的相对位置设定

MySpringArm->bEnableCameraLag = true;//开启镜头平滑移动

MySpringArm->CameraLagSpeed = 3.0f;//平滑移动速度

MyCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("MyCamera"));

MyCamera->SetupAttachment(MySpringArm);//将摄像机附着在SpringArm上对摄像机的位置设定不需要了

  1. 注意一次编译之后可能看不出效果,要将原来创建的蓝图删除了重新创建生成等;

使用C++代码设置默认的模型Mesh和材质

  1. 加载系统的模型Mesh:

首先包含路径:#include “UObject/ConstructorHelpers.h”

  1. 对以上路径下的静态类进行调用:

static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(/*资源路径*/);

static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));

//材质

static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("Material'/Game/StarterContent/Materials/M_Metal_Gold.M_Metal_Gold'"));

  1. 进行设置:

if (StaticMeshAsset.Succeeded()&& MaterialAsset.Succeeded())

{

MyStaticMesh->SetStaticMesh(StaticMeshAsset.Object);

MyStaticMesh->SetMaterial(0/*材质插槽*/,MaterialAsset.Object);

}

  1. SprintArm的优势在于当场景出现摄像机与待观察模型之间有阻挡时,悬臂会自动调节长度保证我们可以观察到对象,而不是一直保持相对距离角度不改变;等到正常的时候自动回到设定。

将StaticMesh设置为根组件

  1. Sweep只对根组件有效
  2. 将StaticMesh的值直接给到rootComponent

MyStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyStaticMesh"));

RootComponent = MyStaticMesh;

控制视野上下看

  1. 使用Input设置轴映射(同前),绑定好对应的函数之后进行函数的响应计算,再到Tick中变换

void AMyPawn::LookUp(float Value)

{

MouseInput.Y = FMath::Clamp(Value, -1.0f, 1.0f);

}

void AMyPawn::LookRight(float Value)

{

MouseInput.X = FMath::Clamp(Value, -1.0f, 1.0f);

}

PlayerInputComponent->BindAxis(TEXT("LookUp"), this, &AMyPawn::LookUp);

PlayerInputComponent->BindAxis(TEXT("LookRight"), this, &AMyPawn::LookRight);

  1. Tick中对SpringArm进行旋转带动摄像机(相当于眼睛)进行旋转

//XYZ在旋转中对应Row,Pitch,Yaw

FRotator NewSpringArmRotation = MySpringArm->GetComponentRotation();

//控制抬头和低头角度范围

NewSpringArmRotation.Pitch = FMath::Clamp(NewSpringArmRotation.Pitch += MouseInput.Y, -75.0f, 75.0f);

MySpringArm->SetWorldRotation(NewSpringArmRotation);

使用Controller实现角度旋转控制

  1. 直接在Tick中调用:

//左右旋转

AddControllerYawInput(MouseInput.X);

使用系统继承自Controller的方式(前提是开启此继承)

  1. 如何开启起继承:使用系统变量bUseControllerRotationYaw = true;//或是在蓝图中进行一个勾选

注意编写代码实现的时候要注意蓝图中对应勾选栏目是否同步了

猜你喜欢

转载自blog.csdn.net/weixin_44212242/article/details/124800639