Summary of common knowledge points of UE4 C++ programming

1. Add components to the role:
      UCameraComponent* Camera = CreateDefaultSubobject< UCameraComponent >( TEXT ( "Camera0" ));
2, String combination (combining strings in the blueprint):
   BuildString, string +int/float/Object/vector2/boolean……+ string
3. Expose properties to the editor (UE4 Doc)
  UPROPERTY(EditAnyWhere,BlueprintReadWrite,Category="Damage")
  UPROPERTY(BlueprintReadOnly,VisibleAnywhere,Transient,Category="Damage")
  VisibleAnywhere tag means visible in editor but not editable
  Transient means that it cannot be saved or loaded from the hard disk, it should be a derived non-persistent value
  Status updates for editor property values:
  PostInitProperties() function
  #if WITH_EDITOR
  PostEditChangeProperty(FPropertyChangeEvent& PropertyChangedEvent)
  {
  }
  #endif
  The C++ function is displayed in the blueprint in UE4:
  UFUNCTION(BlueprintCallable,Category="Damage")
  C++/Blueprint hybrid implements the same function:
  UFUNCTION(BlueprintNativeEvent,Category="Damage")
  void CalledFromCpp();
  CalledFromCpp_Implementation()
  {
  }
  When the class you created is not inherited from Actor, to find the UCLASS you created, you must turn off the Actors Only in the filter in the Class Viewer (by default, it is detected, which means that non-inheritance will be filtered out from Actor's custom UCLASS). --Excerpt from Cookbook
  Loading resources with FStringAssetReferences and StaticLoadObject is also an option
  Classes inherited from UObject can be created through the global function ConstructObject<> or NewObject<>
  UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=UClassNames)
  TSubclassOf<UUserProfile> UPBlueprintClassName;
  ObjectType* object = ConstructObject<ObjectType>(UClassReference);
  For example:
  AChapterGameMode *gm = Cast<AChapterGameMode>(GetWorld()->GetAuthGameMode());
  if(gm)
  {
     UUserProfile* object = ConstructObject<UUSerProfile>(gm->UPBlueprintClassName);
  }
  //NewObject usage
  UProfile* object = NewObject<UProfile>(GetTransientPackage(),uclassReference);
  Delete a non-used UObject:
   objectInstance->ConditionalBeginDestroy();
   强制GC进行资源回收的方式:
   GetWorld()->ForceGarbageCollection(true)
   结构体的写法:
   #pragma once
   #include "Chapter2.h"
   #include "ColoredTexture.generated.h"
  USTRUCT()
  struct CHAPTER2_API FColoredTexture
  {
  GENERATED_USTRUCT_BODY()
  public:
  UPROPERTY( EditAnywhere, BlueprintReadWrite, Category =
  HUD )
 UTexture* Texture;
 UPROPERTY( EditAnywhere, BlueprintReadWrite, Category =
  HUD )
  FLinearColor Color;
  }
  枚举的写法:
 
UENUM()
enum Status
{
Stopped UMETA(DisplayName = "Stopped"),
Moving UMETA(DisplayName = "Moving"),
Attacking UMETA(DisplayName = "Attacking"),
};
使用方法:
 UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=Status)
TEnumAsByte<Status> status;
继承自Actor的类使用NewObject<>和SpawnActor<>方式进行实例化,例如:
UAction* action = NewObject<UAction>(GetTranientPackage(),UAction::StaticClass());
UObject类的回收(你也可以通过设置引用计数为0的方式来达到释放的目的):
UObject *o  = NewObject<UObject>(……);
o->ConditionalBeginDestory();
或者通过:
GetWorld->ForceGarbageCollection(true);
的方式也可以达到同样的目的。
UObject和它的派生类(创建的任何东西NewObject或ConstructObject)不能使用TSharedPtr!
TSharedPtr,TSharedRef,TWeakPtr,TAutoPtr基本使用方法:
class MyClass{}
TSharedPtr<MyClass> sharedPtr(new MyClass());
weak pointers 与 shared pointers之间有一些不同,弱指针没有能力保留对象的内存当引用计数到0时
弱指针的好处是它回收内存后,指针的引用会变成NULL,可以通过检测弱指针是否可用来进一步处理:
if(ptr.IsValid())
{
}
那些继承自UObjects的类不能使用TSharedRef
TScopedPointer<AWarrior>warrior(this);
TScopedPointer在作用域内避免被销毁的指针类型,也是通过引用计数的方式来进行管理的

生成继承自Actor的对象,例:
SpawnActor = GetWorld()->SpawnActor<AChapter04Actor>(AChapter04Actor::StaticClass(),SpawnLocation);
定时器的基本使用方法:
FTimerHandle Timer;
GetWorldTimerManager().SetTimer(Timer,this,&AUE4GameMode::DestroyActorFunction,10);
设置对象的生命周期可以对Actor进行销毁控制:
SetLifeSpan(10);
初始化物体组件:
auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("Static Mesh'/Engine/BasicShapes/Cube.Cube'"));
if(MeshAsset.Object!=nullptr)
{
Mesh->SetStaticMesh(MeshAsset.Object);
}
需要在头文件中加入:
#include “ConstructorHelpers.h”

Debug信息到屏幕上:
GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red,
FString::Printf(TEXT("%s left me"), *(OtherActor-
>GetName())));

1、委托写法(无参):
DECLARE_DELEGATE(FStandardDelegateSignature)

定义成员:
FStandardDelegateSignature  MyStandardDelegate;

绑定:
MyStandardDelegate.BindUObject(this,&ADelegateListener::EnableLight);
简单的C++类对象函数绑定要用BindRaw
静态函数的绑定:BindStatic
执行:
MyStandardDelegate.ExecuteIfBound();

解除当前的绑定:
MyStandardDelegate.Unbind();

2、委托写法(含参):
DECLARE_DELEGATE_OneParam(FParamDelegateSignature,FLinearColor)
DECLARE_EVENT( OwningType, EventName )
创建一个事件。
DECLARE_EVENT_OneParam( OwningType, EventName, Param1Type )
创建带一个参数的事件。
DECLARE_EVENT_TwoParams( OwningType, EventName, Param1Type, Param2Type )
创建带两个参数的事件。
DECLARE_EVENT_<Num>Params( OwningType, EventName, Param1Type, Param2Type, ...)
创建带 N 个参数的事件。

添加成员:
FParamDelegateSignature MyParamDelegate;

绑定:
同无参绑定类似

执行:
MyParamDelegate.ExecuteIfBound(FLinearColor)

3,多播委托的写法:
DELCARE_MULTICAST_DELEGATE(FMulticastDelegateSignature)

添加成员到指定的类中:
FMulticastDelegateSignature FMultiDelegate;

绑定类似:
FMultiDelegate->AddUObject(this,AMulticastDelegateListener::ToggleLight);

执行:
FMultiDelegate->Broadcast();

解除绑定:
FMultiDelegate->Remove(AMulticastDelegateListener::ToggleLight);
DECLARE_MULTICAST_DELEGATE[_Const, _RetVal, etc.]( DelegateName )
创建一个多播的多播代理。
DECLARE_DYNAMIC_MULTICAST_DELEGATE[_Const, _RetVal, etc.]( DelegateName )
创建一个动态的多播代理。
DECLARE_DYNAMIC_MULTICAST_DELEGATE[_Const, _RetVal, etc.]( DelegateName )
创建一个封装的动态多播代理。

4,自定义事件:
DECLARE_EVENT(AMyTriggerVolume,FPlayerEntered)

定义:
FPlayerEntered OnPlayerEntered;

执行:
OnPlayEntered.Broadcast();
绑定:
OnPlayEntered.AddUObject(this,&ATriggerVolEventListener::OnTriggerEvent);    
获取当前关卡中所有的指定类型AActor:
 UGameplayStatics::GetAllActorsOfClass( const UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, TArray<AActor*>& OutActors)
例如:  
TArray < AActor *> TimeOfDayHandlers;
UGameplayStatics ::GetAllActorsOfClass(GetWorld(), ATimeOfDayHandler ::StaticClass(), TimeOfDayHandlers);
UE4定时器的使用方法:
FTimerHandle MyTimer;
GetWorld()->GetTimerManager().SetTimer(MyTimer,this,&APickupSppawner::SpawnPickup,10,false);
UE4中的迭代器的用法:
AActor的迭代器位于“EngineUtil.h”头文件中,基本使用方法:
for(TActorIterator<AActor> It(GetWorld(),AActor::StaticClass());It;++It)
{
   AActor* Actor = *It;
   IMyInterface* MyInterfaceInstance = Cast<IMyInterface>(Actor);
   if(MyInterfaceInstance)
   {
      MyInterfaceInstances.Add(MyInterfaceInstance); 
   }
}
给指定的静态网格物体组件附加默认模型文件:
auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("Static Mesh'/Engine/BasicShapes/Cube.Cube'"));
if(MeshAsset.Object!=nullptr)
{
   MyMesh->SetStaticMesh(MeshAsset.Object);
}
UINTERFACE(meta=(CannotImplementInterfaceInBlueprint)) 可解决与接口方法UNFUNCTION(BlueprintCallable)的冲突问题
如果非实现的方法,可以在函数里写入unimplemented();比如说接口的方法。

暴露接口供蓝图使用:

首先,在接口中声明函数(当然为了避免蓝图可继承错误,需要借助上面的元数据声明,函数必须为虚函数,这个是从一个帖子上看到的, https://www.2cto.com/kf/201608/532601.html
UFUNCTION(BlueprintCallable,Category = Test)
virtual void OnPostBeginPlay();
接着可以在cpp文件中实现该函数,
其他的继承用法和常规C++实现方式类似,就不记录了。

接口在蓝图中的实现:
主要的声明部分:
UFUNCTION(BlueprintImplementableEvent,BlueprintCallable,Category=AttackAvoider)
void AttackInComing(AActor* AttackActor);

蓝图中覆盖C++中实现的接口函数:
主要的声明部分;
 UFUNCTION(BlueprintNativeEvent,BlueprintCallable,Category=Wearable)
void OnEquip(APawn* Wearer);
函数的主体部分:
void IWearable::OnEquip_Implementation(APawn* Wearer)
{
}

继承子类的写法:
virtual void OnEquip_Implementation(APawn* Wearer) override
{
   IWearable::OnEquip_Implementation(Wearer);
}

C++调用蓝图实现的接口:

基本是通过<IInterface>::Execute_<FunctionName>的方式完成调用的

继承自UObject的对象可以通过声明UCLASS(BlueprintType)的方式来让蓝图识别并作为变量使用
UCLASS(Blueprintable)可以让蓝图继承该类
可以同时用UCLASS(Blueprintable,BlueprintType)的方式让该类即能作为蓝图变量使用又能作为可继承的基类使用

声明方法为UFUNCTION(BlueprintImplementableEvent)可以在蓝图中实现该事件并进行调用

向蓝图中暴露多播委托
首先声明一个多播委托:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnKingDeathSignature,AKing*,DeathKing);

其次在类中声明委托变量:
UPROPERTY(BlueprintAssignable)
FOnKingDeathSignatrue OnKingDeath;

函数中调用:
OnKingDeath.Broadcast(this);


在蓝图可以挂在当前的多播事件,并通过调用OnKingDeath.Broadcast的函数完成调用
解绑绑定的函数,可以通过UnBind系列的函数完成

枚举在蓝图中的公开及使用:
1, UENUM(BlueprintType)
      enum TreeType {Tree_Poplar,Tree_Spruce,Tree_Eucalyptus,Tree_Redwood};
2,在类中的声明:
     UPROPERTY(BlueprintReadWrite)
     TEnumAsByte<TreeType> Type;

属性在细节面板中可见性及修改的控制:
         UPROPERTY (EditDefaultsOnly) //默认蓝图类列表中细节属性可修改
               bool EditDefaultsOnly;
        UPROPERTY (EditInstanceOnly)//实例化的蓝图类的细节列表中可修改
               bool EditInstanceOnly;
        UPROPERTY (EditAnywhere) //以上两者都能进行修改
               bool EditAnywhere;
        UPROPERTY (VisibleDefaultsOnly)//可见性控制,默认蓝图类列表中可见
               bool VisibleDefaultsOnly;
        UPROPERTY (VisibleInstanceOnly)//实例化的细节列表中可见
               bool VisibleInstanceOnly;
        UPROPERTY (VisibleAnywhere)//以上两者皆可见
               bool VisibleAnywhere;
属性在蓝图中调用及修改的基本控制:
     UPROPERTY(BlueprintReadWrite,Category=Cookbook)//读写
     bool ReadWriteProperty;
     UPROPERTY(BlueprintReadOnly,Category=Cookbook)//读
     bool ReadOnlyProperty;

C++中添加蓝图中的Construction事件脚本:
virtual void OnConstruction(const FTransform& Transform) override;
主要在该函数中完成。


创建一个新的编辑器模块:
1,在你的UE4 项目中的uproject文件中找到Module模块配置参数:加上实例类似的内容(一个完整的模块配置参数):
{"Name":"UE4CookBookEditor","Type":"Editor","LoadingPhase":"PostEngineInit","AdditionalDependencies":["Engine","CoreUObject"]}
2,在你的项目源码目录文件夹中创建一个新的文件夹命名为:UE4CookBookEditor,并添加文本配置文件:UE4CookBookEditor.Build.cs
3,在文本配置文件中添加以下代码:
using UnrealBuildTool;
public class UE4CookBookEditor : ModuleRules
{
    public UE4CookBookEditor(TargetInfo Target)
    {
        PublicDependencyModuleNames.AddRange( new string [] { "Core" , "CoreUObject" , "Engine" , "InputCore" , "RHI" , "RenderCore" , "ShaderCore" });
        PublicDependencyModuleNames.Add( "CookBook" );
        PrivateDependencyModuleNames.AddRange( new string [] { "UnrealEd" });
    }
}
4,创建基本组件模块的头文件:UE4CookBookEditor.h和UE4CookBookEditor.cpp实现文件,他们的具体内容如下:
//头文件内容
#pragma once
#include "Engine.h"
#include "ModuleManager.h"
#include "UnrealEd.h"
class UE4CookBookEditorModule:public IModuleInterface
{
};
//实现文件的具体内容
#include "UE4CookBookEditor.h"
IMPLEMENT_GAME_MODULE(FUE4CookBookEditorModule,UE4CookBookEditor)
关闭VS,右键点击你的UE项目,选择Generate Visual Studio Project files文件
新添加的模块是不支持热更新的,就像运行时代码一样, 如果你得到一个 编译错误,其中提到了对生成的头文件的更改, 只需关闭编辑器,然后从IDE中重新构建。

自定义资源类型的写法:
1,首先建立一个资源类,继承自UObject,例如:
#pragma once
#include "Object.h"
#include "MyCustomAsset.generated.h"
UCLASS ()
class COOKBOOK_API UMyCustomAsset : public UObject
{
        GENERATED_BODY ()
public :
        UPROPERTY (EditAnywhere, Category = "Custom Asset" )
               FString Name;
};
2,创建继承自UFactory的自定义资源工厂,并重写创建函数FactoryCreateNew:
#pragma once
#include "Factories/Factory.h"
#include "CustomAssetFactory.generated.h"
UCLASS ()
class COOKBOOK_API UCustomAssetFactory : public UFactory
{
        GENERATED_BODY ()
public :
       UCustomAssetFactory();
        virtual UObject * FactoryCreateNew( UClass * InClass , UObject * InParent , FName InName , EObjectFlags Flags , UObject * Context , FFeedbackContext * Warn , FName CallingContext ) override ;
};
3,实现文件:
#pragma once
#include "CustomAssetFactory.h"
#include "CookBook.h"
#include "MyCustomAsset.h"
UCustomAssetFactory ::UCustomAssetFactory() : Super ()
{
       bCreateNew = true ;
       bEditAfterNew = true ;
       SupportedClass = UMyCustomAsset ::StaticClass();
}
UObject * UCustomAssetFactory ::FactoryCreateNew( UClass * InClass , UObject * InParent , FName InName , EObjectFlags Flags , UObject * Context , FFeedbackContext * Warn , FName CallingContext )
{
        auto NewObjectAsset = NewObject< UMyCustomAsset >( InParent , InClass , InName , Flags );
        return   NewObjectAsset;
}
4,别忘了添加模块引用 “UnrealEd",否则会出现链接错误!

UE4中关于文件读取的一些内容:
判定当前文件是否存在以及文件大小的本地化方式存储在头文件一下头文件中:
Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h
Runtime/Core/Public/HAL/PlatformFilemanager.h
如果你想得到文件的大小,你可以这样做:
FPlatformFileManager::Get().GetPlatformFile().FileSize(*MyFilePath);//当然你也可以直接调取GenericPlathformFile.h头文件来完成,只不过通过FPlatformFileManager可以通过一层单例模式获取
如果你要写文件读取相关的内容,你可以通过以下头文件和模块找到你想要的头文件:
#include "Paths.h" #include "Http.h"  
FPlatformFileManager::Get().GetPlatformFile()下拥有打量的文件操作函数,其中包括,增删文件夹,创建文件,修改内容,移动文件,查询文件大小等
程序中控制鼠标的显示:
GetWorld()->GetFirstPlayerController()->bShowMouseCursor=true;

UE4 Log相关
UE_Log(LogTemp,Warning,TEXT("Message %d"),1);
自定义Log:
首先打开项目头文件:
包含Engine头文件#include“Engine.h”
DECLARE_LOG_CATEGORY_EXTERN(LogCustom,Log,All);
第一个参数:CategoryName:Log的名称
第二个参数:DefaultVerbosity:自定义的Log打印输出信息
第三个参数:CompileTimeVerbosity:这是对编译后的代码进行烘焙后的一段代码(有道翻译,没理解什么意思)

Message Log 相关:
#define LOCTEXT_NAMESPACE "CustomLogMessage"
extern FName LoggerName;
extern FMessageLog Logger;

#define FTEXT(x) LOCTEXT(x,x)
FName LoggerName("CustomLog")
FMessageLog CreateLog( FName name )
{
FMessageLogModule& MessageLogModule =
FModuleManager::LoadModuleChecked<FMessageLogModule>
("MessageLog");
FMessageLogInitializationOptions InitOptions;
InitOptions.bShowPages = true;// Don't forget this!
InitOptions.bShowFilters = true;
FText LogListingName = FTEXT( "Chapter 12's Log Listing"
);
MessageLogModule.RegisterLogListing( LoggerName,
LogListingName, InitOptions );
}
AChapter12GameMode::AChapter12GameMode()
{
//这个没有测试,估计是上面函数的调用,可能要改成CreateLog(LoggerName);
CreateLogger( LoggerName );
// Retrieve the Log by using the LoggerName.
FMessageLog logger( LoggerName );
logger.Warning(
FTEXT( "A warning message from gamemode ctor" ) );
}

调用
Logger.Info(FTEXT("Info Log"));
Logger.Warning(FTEXT("Warning Log"));
Logger.Error(FTEXT("Error Log"));
FMessageLog( LoggerName ).Info( FTEXT( "An info  message" ) );
屏幕输出信息:
#include“Engine.h”
GEngine->AddOnScreenDebugMessage(-1,5.f,FColor::Red,TEXT("Send your Message to Screen!"));

旋转角的知识点:
FRotator(FVector) ;
FQuat(FVector Axis,float AngleRed); //四元数,FVector指的是旋转轴,angleRed指的是旋转的角度

GameplayAbilities插件:
实用的技能插件,可以在相关的博客上具体的学习一下

UE4中嵌入Content内容的方式:
可以通过快捷方式添加命令的形式实现,比如:
mklink /j  F:\UE4Project\CookBook\ShowLink  F:\ShowLink













Guess you like

Origin blog.csdn.net/u011047958/article/details/78738674