A、普通的C++類型 F Class
B、智能指針
C、UObject類型的UClass
我們逐一說明他們的使用方法和注意事項
1、針對普通的C++的class照普通的使用方式即可;UED中或者UE4的底層很多使用這種Class的例子;但UE4會統一的在前加F 比如:上次我們說的負責座標軸繪製和處理的FWidget類(在UnrealWidget.h中)
聲明:
class FWidget
: public FGCObject
{
FWidget();
};
使用:
FEditorViewportClient::FEditorViewportClient(FEditorModeTools* InModeTools, FPreviewScene* InPreviewScene, const TWeakPtr<SEditorViewport>& InEditorViewportWidget)
: bAllowCinematicPreview(false)
...
, Widget(new FWidget)
銷燬:
FEditorViewportClient::~FEditorViewportClient()
{
...
delete Widget;
}
目前大部分的F Class都在UED的框架中使用。在game的框架中相同功能的Class都改成了UClass
2、UE4的智能指針SmartPointer體系在引擎初期項目中用處主要在UI上;SlateUI是主要使用智能指針的地方。但隨着後期UMG的出現SlateUI的部分被完全封裝在UMG內部,現在研發人員一般不會接觸到這一塊。但對於研究引擎的人來說熟悉智能指針相當重要。以SWidget爲例說明
聲明方式():
class SLATECORE_API SWidget
: public FSlateControlledConstruction,
public TSharedFromThis<SWidget> // Enables 'this->AsShared()'
{
friend struct FCurveSequence;
//dubeibei XMod
friend class UXScriptWidget;
public:
};
重點是類模版TSharedFromThis<SWidget>;TSharedPtr<>;TSharedRef<>
template< class ObjectType, ESPMode Mode >
class TSharedFromThis
{};
template< class ObjectType, ESPMode Mode >
class TSharedPtr
{};
template< class ObjectType, ESPMode Mode >
class TSharedRef
{};
template< class ObjectType, ESPMode Mode >
class TWeakPtr
{
public:
};
詳情見:SharedPointer.h 其中指針會有SharedReferenceCount保存計數;計數爲0時自動清理。TWeakPtr中有WeakReferenceCount保存計數,但TWeakPtr的引用計數不作爲是否清理的標記,即TweakPtr中的Object可能已經被清理;但TweakPtr還在;可使用TWeakPtr的Isvalid來校驗Object是否已被清理。
使用方式:
TSharedPtr<SWidget> RetWidget = SNew(SInvalidationPanel)
或者:
SAssignNew(MyTextBlock, STextBlock)
或者:
MakeShareable(new FUIController()); 返回的也是一個TSharedPtr
關於TSharedPtr TSharedRef TWeakPtr之間相互轉換的使用:
TSharedPtr ToSharedRef()-> TSharedRef
TWeakPtr Pin()-> TSharedPtr
TSharedRef
轉換使用StaticCastSharedPtr:
TSharedPtr<SChannelListPageWidget> MyWidget = StaticCastSharedPtr<SChannelListPageWidget>(GetWidget());
3、關於 UObject的Class使用
UObject是上層或者Game框架裏面最經常用到的Class。把遊戲框架中出現的各種東西抽象出一個UObject十分必要;通用的屬性和接口;統一的GC;方便數據統計;等等
聲明示例如下:
UCLASS(config = Game, meta = (ChildCanTick))
class PROJECTZ_API AMaterialParamaterObject : public AActor
{
GENERATED_UCLASS_BODY()
/** The CapsuleComponent being used for movement collision (by CharacterMovement). Always treated as being vertically aligned in simple collision check functions. */
UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly)
class USceneComponent* RootSceneCom;
/** The main skeletal mesh associated with this Character (optional sub-object). */
UPROPERTY(Category = MapEditor, VisibleAnywhere, BlueprintReadOnly)
class UStaticMeshComponent* Mesh;
static FName MeshComponentName;
static FName RootComponentName;
UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
void ChangeFloatParamater(int32 ParaIndex, int32 NameIndex, float InValue);
UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
void ChangeIntParamater(int32 ParaIndex, int32 NameIndex, int32 InValue);
UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
void ChangeVectorParamater(int32 ParaIndex, int32 NameIndex, FVector InValue);
UFUNCTION(BlueprintCallable, Category = "MapEditor|Objects")
void ChangeTextureParamater(int32 ParaIndex, int32 NameIndex, UTexture2D* InValue);
UPROPERTY(Category = "MapEditor|Objects", EditAnywhere, BlueprintReadWrite)
TArray<FEditorMaterialParamater> Paramaters;
};
關於UHT:UnrealHeaderTool,UHT會根據UClass的頭文件.h生成.generated.h文件把其中擁有UPROPERTY UFUNCTION的標籤的重新定義例如ChangeFloatParamater接口:
DECLARE_FUNCTION(execChangeFloatParamater) \
{ \
P_GET_PROPERTY(UIntProperty,Z_Param_ParaIndex); \
P_GET_PROPERTY(UIntProperty,Z_Param_NameIndex); \
P_GET_PROPERTY(UFloatProperty,Z_Param_InValue); \
P_FINISH; \
P_NATIVE_BEGIN; \
this->ChangeFloatParamater(Z_Param_ParaIndex,Z_Param_NameIndex,Z_Param_InValue); \
P_NATIVE_END; \
}
新生成的.genreated.h文件會加入編譯所有的UPROPERTY和UFUNCTION都會是繼承自UObject的Class使用 ;然後再由GC統一的管理UObject;
不加UPROPETY標籤的屬性不在UObject 此過程GC的範圍之內;需要另外的控制,不然很容易內存泄漏。見下章詳細說明。
使用:
MyGCProtectedObj = NewObject<UMyObjectClass>(this);
如果不想讓UObject強制回收可設置:
YourObjectInstance->AddToRoot();
銷燬:
if(!MyObject) return;
if(!MyObject->IsValidLowLevel()) return;
MyObject->ConditionalBeginDestroy(); //instantly clears UObject out of memory
MyObject = nullptr;
銷燬Actor:
if(!TheCharacter) return;
if(!TheCharacter->IsValidLowLevel()) return;
TheCharacter->Destroy();
TheCharacter->ConditionalBeginDestroy(); //essential extra step, in all my testing