UE4_20 Scripting with C++ 01

Unreal Engine 4 Scripting with C++ Cookbook 出了第二版。

新书提供的改进:采用4.21编写全书代码与将旧书的80条策略提升到了100条。全书14章节,其中多出了multiplay network章节(第十四章),另外将integrate c++with UE4 Editor分成了两个章节(第九、十章)。该书对应Code可以从github上获取 https://github.com/PacktPublishing/Unreal-Engine-4.x-Scripting-with-C-Cookbook---Second-edition.。我的学习测试代码使用4.20版本。

单词本:
in conjunction with:与
    It will help you understand the benefits of using C++ in conjunction with the many tools included with this powerful game engine. 
 object-oriented:面向对象
    This book assumes familiarity with the C++ programming language,an understanding of what different programming operators mean, and basic knowledge of the concepts of object-oriented programming
elaborate:精心制作的
    Creating a game is an elaborate task that will require a combination of assets and code
asterisk:星号
    There will be an asterisk * just before the FString variable when using UE_LOG to dereference the FString to a regular C-style TCHAR pointer. 
bloated:臃肿的 
    your console may become bloated with messages and make it difficult to find things you are looking for.

Chapter01:UE4 Development Tools,总结如下(与第一版本内容基本相同)

讲了怎么装软件与基础操作
VS2017:
  编译与运行:    ctrl + shift +B build the project,ctrl +f5 run the project
  在文件之间导航:Ctrl + - 会后退
                 Ctrl + shift + - 会前进
  番茄插件:alt + o用于在.h和.cpp文件间切换
           alt + g 用于查找函数原型
  代码段展开与关闭 : ctrl +M

鼠标操作:
   用于选取单词 crtl +点击 
   box选取单词  alt +left click +drag

信息打印手段:UE_LOG
UE_LOG(LogTemp,Warning,TEXT("Some Warning Message"));
像printf一样的使用:注意点FString类型的需要加*解引用
int intVar=5;
float floatVar=3.7f;
FString fstringVar="an fstring variable";
UE_LOG(LogTemp,Warning,TEXT("TEXT,%d %f %s"),intVar,floatVar,*fstringVar); 

构造出一个FString:通过FString::Printf()或者FString::Format()
FString name = "Tim"; 
int32 mana = 450; 
FString string = FString::Printf( TEXT( "Name = %s Mana = 
 %d" ), *name, mana );
//////////////////////////////////////////////////////////////
FString name = "Tim"; 
int32 mana = 450; 
TArray< FStringFormatArg > args; 
args.Add( FStringFormatArg( name ) ); 
args.Add( FStringFormatArg( mana ) ); 
FString string = FString::Format( TEXT( "Name = {0} Mana = {1}" ), args );
UE_LOG( LogTemp, Warning, TEXT( "Your string: %s" ), *string );


Chapter02:Creating Classes

创建一个基于Uobject的类UserProfile,

当使用UCLASS时,用户的类的构建和销毁交给了UE4来处理:
使用ConstructObject()来创建,使用UObject::ConditionalBeginDestroy()来销毁
继承自UObject分支的类以U开头,继承自AActor的类以A开头
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "UserProfile.generated.h"
UCLASS()
class CHAPTER_02_API UUserProfile : public UObject
{
	GENERATED_BODY()	
	
};
UE4会基于UCLASS创建一堆的宏,放在XXX.generated.h中,方便用户的操作
注意,UE4.15版本起,要求用户手动添加一些必要的头文件,只有用到的头文件才被加载进去,这样做的好处在于加快编译速度。
用户想要添加头文件需要放在generated.h之前

UCLASS的行为

UCLASS中传入关键字用于定义和蓝图的交互:
Blueprintable:表示该类可以被蓝图类继承
BlueprintType:表示该类作为其他蓝图的一个variable变量类型

基于自定义的UCLASS来创建蓝图

创建蓝图子类的好处在于可以通过Editor来可视化的修改具有UPROPERTY属性的值,
另外可以避免把资源hardcoding硬编码到C++中,更符合面向对象的思想。
There is a way to load resources (such as textures) using FStringAssetReferences and StaticLoadObject. These pathways to loading resources (by hardcoding path strings into your C++ code) are generally discouraged, however. Providing an editable value in a UPROPERTY() and loading from a proper concretely typed asset reference is a much better practice.
上文主要意思是说,也可以在C++中通过FStringAssetReferences来引用Texture资源或
使用StaticLoadObject来引用物体资源,比硬编码的方式要合适,
当然最合适的是使用UPROPERTY暴露给子类蓝图,然子类蓝图来修改

创建一个用户可编辑的UPROPERTY

每个UCLASS类中都可以设置任意数量的UPROPERTY
通过传入关键字定义UPROPERTY的属性:
EditAnywhere,表明可以在Code中修改,或者在蓝图Editor中修改
BlueprintReadWrite,表明子类蓝图可以在任何时间修改该属性。
EditDefaultOnly:表明子类蓝图本身可以修改,在运行时不能够修改
EditInstanceOnly:只能在实例化的对象身上修改,子类蓝图本身不能修改
BlueprintReadOnly:需要C++来设置,蓝图子类上不能修改

修改代码如下:
UCLASS(Blueprintable)
class CHAPTER_02_API UUserProfile : public UObject
{
	GENERATED_BODY()
protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float Armor;
	UPROPERTY(EditAnywhere,BlueprintReadWrite)
	float HpMax;
};
使用蓝图子类,就可以修改属性值

实例化创建的UObject类:

在LevelBlueprint中:(在第一版中只介绍了使用代码ConstructObject<>来实例化,感觉并不如蓝图直观)

扫描二维码关注公众号,回复: 5871862 查看本文章

使用C++来实例化Uobject,这里的思想在于实例化蓝图类,由编译时确定转到运行时确定,使用未来,是一种面向对象的思想

we simply have to provide a user-editable UPROPERTY with aTSubclassOf<C++ClassName> typed variable. Alternatively, you can use FStringClassReference to achieve the same objective.

想要实例化蓝图类对象,需要知道:蓝图类的名称和蓝图类所继承的基类类型

这里说明C++自己不应该知道蓝图类的具体类型,我们可以用TSubclassOf<C++ClassName>或者是 FStringClassReference 来存储类类型,通过UPROPERTY暴露给Editor,在Editor中指定。

通过GameMode类实例化UserProfile蓝图类:.h文件,主要是使用TSubclassOf<C++ClassName>来存储类名称

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "UserProfile.h"
#include "Chapter_02GameModeBase.generated.h"
UCLASS()
class CHAPTER_02_API AChapter_02GameModeBase : public AGameModeBase
{
	GENERATED_BODY()	
public:
	UPROPERTY(EditAnywhere)
        TSubclassOf<UUserProfile> BPClassName;	
};

.cpp文件,使用NewObject体现了工厂模式(设计模式这一块我也是刚开始看,还不明白),NewObject需要传GetTransientPackage(),原书中说使用NewObject比ConstructObject更好,更符合设计模式。另外销毁UObject使用了ConditionalBeginDestroy()方法。

void AChapter_02GameModeBase::BeginPlay(){
	AChapter_02GameModeBase *gm = Cast<AChapter_02GameModeBase>(
		GetWorld()->GetAuthGameMode());
	if (gm)
	{
		UUserProfile* newObject=NewObject<UUserProfile>((UObject*)GetTransientPackage(),
			UUserProfile::StaticClass());
		if(newObject){
			newObject->ConditionalBeginDestroy();
			newObject = nullptr;
		}
	}

}

这里还提到了\Program Files (x86)\Epic Games\Launcher\Engine\Config\BaseEngine.ini记录了GC的时间,并且可以通过GetWorld()->ForceGarbageCollection(true) 强制进行垃圾回收

gc.TimeBetweenPurgingPendingKillObjects=61.1

创建一个结构体;果然印证了我之前的想法,这部分作者是手动用VS创建的代码。。。

。。。
注意几点吧,文件名为ColoredTexture.h
但是具体书写的时候
#include "ObjectMacros.h"
#include "ColoredTexture.generated.h"

USTRUCT(Blueprintable)
struct CHAPTER_02_API FColoredTexture   //加上了F,类似于Object的U和Actor的A
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
		UTexture* Texture; 

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
		FLinearColor Color;
};
         
GENERATED_USTRUCT_BODY()会生成ColoredTexture.generated.h
UTexture* Texture虽然爆红,但是编译通过,另外之前的TSubclassOf<UObject>会爆红,也能通过编译

最后在UserProfile文件中添加#include "ColoredTexture.h"和
UPROPERTY(EditAnywhere)
FColoredTexture Texture;

创建一个UENUM

直接写在了UserProfile中
UENUM()
enum Status {
	Stopped  UMETA(DisplayName = "Stopped"),
	Moving   UMETA(DisplayName = "Moving"),
	Attacking UMETA(DisplayName = "Attacking"),
};

使用的注意事项:使用TEnumAsByte容器来存储变量
	UPROPERTY(EditAnywhere)
	TEnumAsByte<Status>status;

第二版把创建UFUNCTION放到了后面的章节中。

总结可以看出新版的书在细节的说明上更加的清晰。也更注重面向对象的思想。

为了单篇不过长,将后面的内容放到下一节

猜你喜欢

转载自blog.csdn.net/weixin_33232568/article/details/89180073