墨墨昧昧,其光必远。
有些问题在书本中并不能找到答案。
这一节参考英文教程Packt Publishing - Basics of Coding with Unreal Engine 4,使用第三人称C++模板进行实例测试,正好补充上一节中所没有处理的问题。
1)、使用UE_LOG打印人物起跳次数
重写Jump函数,创建存储起跳次数的变量
virtual void Jump() override;
void AUnrealScriptingBasicCharacter::Jump()
{
Super::Jump();
UE_LOG(LogTemp, Warning, TEXT("Player is Jumping"));
JumpTimes++;
FString JumpsText = FString::Printf(TEXT("The Player has jumped %d times..."),JumpTimes);
UE_LOG(LogTemp, Warning, TEXT("%s"), *JumpsText);
}
2)Actor的创建,设置Component,与实例化Actor
先给代码,再分析要点
为MagicPill赋予一个StaticMeshComponent
1)、MagicPill.h
UCLASS()
class UNREALSCRIPTINGBASIC_API AMagicPill : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMagicPill();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
//My added items to the class
protected:
//the amount of health that the pill has
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category="Values")
float PillEffect;
public:
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category="Components")
UStaticMeshComponent* PillMesh;
};
这里主要创建两个EditAnyWhere成员变量,其中一个是StaticMesh,用于在场景中显示
2)、MagicPill.c
// Sets default values
AMagicPill::AMagicPill()
{
PillEffect = 0.0f;
PillMesh = CreateDefaultSubobject<UStaticMeshComponent>("BaseMeshComponent");
auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>
(TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_NarrowCapsule.Shape_NarrowCapsule'"));
if (MeshAsset.Object != nullptr)
{
PillMesh->SetStaticMesh(MeshAsset.Object);
}
}
// Called when the game starts or when spawned
void AMagicPill::BeginPlay()
{
Super::BeginPlay();
PillMesh->SetSimulatePhysics(true);
}
这里用于初始化成员变量并且设置仿真物理模拟
创建一个PillSpawner用于动态生成MagicPill对象
创建PillSpawner
protected:
UPROPERTY(EditAnywhere,Category="Spawning")
TSubclassOf<class AMagicPill> ItemToSpawn;
private:
UFUNCTION(BlueprintPure , Category="Spawning")
FVector GetRandomPointInVolume();
UPROPERTY(VisibleAnyWhere,BlueprintReadOnly,Category="Spawning",meta=(AllowPrivateAccess="true"))
class UBoxComponent* SpawningVolume;
//this function will spawn pills
void SpawnPills();
想要实例化对象首先使用TSubClassof说明要实例化的对象类型
创建SpanPills方法用于实例化操作
PillSpawner.cpp
#include "UnrealScriptingBasic.h"
#include "PillSpawner.h"
#include "MagicPill.h"
#include "Classes/Kismet/KismetMathLibrary.h"
// Sets default values
APillSpawner::APillSpawner()
{
SpawningVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnVolumeBox"));
RootComponent = SpawningVolume;
//this establishes the the item to spawn
ItemToSpawn = AMagicPill::StaticClass();
}
// Called when the game starts or when spawned
void APillSpawner::BeginPlay()
{
Super::BeginPlay();
SpawnPills();
}
//This is the function returns a random point int the volume
FVector APillSpawner::GetRandomPointInVolume()
{
FVector Origin = SpawningVolume->Bounds.Origin;
FVector Extent = SpawningVolume->Bounds.BoxExtent;
return UKismetMathLibrary::RandomPointInBoundingBox(Origin, Extent);
}
void APillSpawner::SpawnPills()
{
if (ItemToSpawn != NULL)
{
UWorld* const World = GetWorld();
if (World) {
FVector SpawnLocation = GetRandomPointInVolume();
FRotator SpawnRotation;
SpawnRotation.Pitch = FMath::FRand()*360.f;
SpawnRotation.Roll = FMath::FRand()*360.f;
SpawnRotation.Yaw = FMath::FRand()*360.f;
AMagicPill* SpawnedPill = World->SpawnActor<AMagicPill>(ItemToSpawn, SpawnLocation, SpawnRotation);
}
}
}
涉及要点有三:
1)、Actor中的Component设置
和蓝图类似,蓝图类中的component类型都可以添加
2)、定义和蓝图以及UE4Editor的交互
UPROPERTY设置变量的交互
UFUNCTION设置函数的交互
注意到一个事,无论是udemy等国外的教程中都是使用C++创建一个基类,
具备基本的要素(StaticMesh,TriggerVolume,Varibles等),再使用基于C++类派生的
蓝图类进行细化这些要素,staticmesh具体长什么样,TriggerVolume该有多大,Varible的具体值等
很少直接把C++的Actor直接放到场景之中。
总结就是C++类定义数据和行为,蓝图来细化这些数据和行为,十分像多态的行为。
3)、类对象的实例化,体现反射机制
主要需要记忆的是格式:
我要实例化什么?--通过Tsubclassof
UPROPERTY(EditAnywhere,Category="Spawning")
TSubclassOf<class AMagicPill> ItemToSpawn;
我怎么初始化?--通过StaticClass()
//this establishes the the item to spawn
ItemToSpawn = AMagicPill::StaticClass();
怎么样在场景中实例化?--UWorld的SpawnActor方法
UWorld* const World = GetWorld();
if (World) {
FVector SpawnLocation = GetRandomPointInVolume();
FRotator SpawnRotation;
SpawnRotation.Pitch = FMath::FRand()*360.f;
SpawnRotation.Roll = FMath::FRand()*360.f;
SpawnRotation.Yaw = FMath::FRand()*360.f;
AMagicPill* SpawnedPill = World->SpawnActor<AMagicPill>(ItemToSpawn, SpawnLocation, SpawnRotation);
}
3)、内存管理
内存管理对于一个高效并且没有bug的程序是一件十分重要的工作,包含常规操作和UE4提供的智能指针
1)、malloc和free
int * JumpHeight; //声明指针变量
JumpHeight=(int*)malloc(Sizeof(int));//分配空间
*JumpHeight=10; //指针变量赋值
FString jumpheightText=FString::Printf(TEXT("The Player jumps %d up in the air.")
,JumpHeight);
UE_LOG(Log_Temp,Warning,TEXT("%s"),*jumpheightText);
free(JumpHeight); //释放指针所指向的内存空间
JumpHeight=0; //指针赋值为空
2)、new和delete
int * JumpHeight; //声明指针变量
JumpHeight=new int();//分配空间
*JumpHeight=10; //指针变量赋值
FString jumpheightText=FString::Printf(TEXT("The Player jumps %d up in the air.")
,JumpHeight);
UE_LOG(Log_Temp,Warning,TEXT("%s"),*jumpheightText);
delete JumpHeight; //释放指针所指向的内存空间
JumpHeight=0; //指针赋值为空
如果是对象的动态创建,new会调用构造函数,delete会调用析构函数
3)、UObject或是AActor提供了动态内存处理机制
SpawnActor<>用来创建AActor
NewObject<> ConstructObject<>用来创建UObject
4)、TSharedPtr的使用:
class MyClass{
int values;
};
TSharedPtr<MyClass> emptySharedClass;//this is an Empty shared
TSharedPtr<MyClass> firstSharedObject<New MyClass());//声明和初始化shredptr
TSharedPtr<MyClass> anotherObj=firstSharedObject;
if(firstSharedObject.IsValid()){//通过IsValid方法判断指针非空}
通过sharedptr访问内存,类似于常规指针,sharedptr会自动释放
5)、Garbage Collection使用了反射机制,关于C++的反射机制,等我学通后再梳理一遍
要想使用UE4中的垃圾收集系统:
使用UPROPERTY的类成员将会使用动态的内存管理
只使用基于UObject的类型或者是智能指针。
强制进行垃圾收集:
GetWorld()->ForceGabageCollection(true);
至此,相应的初级code视频教程内容也结束了,后续还有中级code和高级的code视频
接下来一篇仍然是看书做笔记,遇到问题后再看相关视频找如何解决