[UE4]使用C++重寫藍圖,SpawnObject根據類型動態建立UObject

先大量使用藍圖製做項目,後續再用C++把複雜的藍圖重寫一遍,用C++代碼按照藍圖依葫蘆畫瓢就能夠了,很簡單,但須要遵照一些原則:數組

 

第一種方法:使用繼承

1、建立一個C++類做爲藍圖的父類(C++類繼承藍圖同樣的父類),在UE4中修改藍圖的父類。ide

2、C++類中的方法、成員變量與藍圖一一對應,而且方法和成員變量名稱不能與藍圖的重複。函數

3、A藍圖不能直接使用B藍圖的變量,A藍圖把要公開的變量封裝在函數內返回,而且只返回UE4自帶的基礎變量類型,不能返回自定義類型,以方便C++重寫時返回C++中的成員變量。測試

4、用C++中實現好的方法逐個替換藍圖中方法,每次替換一個方法就必需要運行遊戲進行詳細測試,防止修改太多萬一出錯沒法定位問題所在。以下圖所示:保留原藍圖的實現,方便C++代碼查錯。this

5、任意一個用C++方法替換藍圖相應的方法 ,都能保證遊戲能正常運行,儘可能避免出現要同時替換2個以上藍圖方法才能正常運行遊戲。這一點很是重要。一樣也是防止修改太多萬一出錯沒法定位問題所在。spa

6、藍圖方法給變量賦值,也能夠直接調用C++對應方法賦值,以保證C++其它函數方法能正常運行。3d

  

 

第二種使用C++重寫藍圖的方法:使用組合

1、建立一個繼承自UObject的C++類,通常加後綴Helper,而且加上BlueprintType標籤,共藍圖做爲變量類型使用。code

  頭文件:  orm

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Components/CanvasPanel.h"
#include "Blueprint/UserWidget.h"
#include "MiniMap/MiniMapFlagData.h"
#include "Components/CanvasPanelSlot.h"

#include "StaticMiniMapHelper.generated.h"

/**
 * 
 */
UCLASS(BlueprintType)
class PROJ10_0121_API UStaticMiniMapHelper : public UObject
{
    GENERATED_BODY()

private:
    UUserWidget* self;    //自身引用

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = myMethods, meta = (ToolTip = "小圖標容器面板"))
        UCanvasPanel * FlagPanel;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = myMethods, meta = (ToolTip = "存放小圖標數據機構數組"))
        TArray<FUMiniMapFlagDataC> FlagArray;
    //TArray<TSubclassOf<class UMiniMapFlagData>> FlagArray;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = myVariables, meta = (ToolTip = "小地圖比例尺"))
        float MapRatio;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = myVariables, meta = (ToolTip = "小地圖縮放比例"))
        float UIScale;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = myVariables, meta = (ToolTip = "中心對位點"))
        FVector CenterPosition;

public:
    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "初始化"))
        void Ini(UUserWidget* me,UCanvasPanel * Panelflag, FVector PositionCenter, float ScaleUI, float RatioMap);

    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "添加圖標到小地圖"))
        void AddFlag(UUserWidget* flag, AActor* actor);

    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "更新全部圖標在小地圖上的位置"))
        virtual void UpdateFlags();

    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "更新某個圖標在小地圖上的位置"))
        virtual void UpdateFlag(FUMiniMapFlagDataC data);

    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "設置小地圖縮放比例"))
        void SetUIScale(float scale);

    UFUNCTION(BlueprintCallable, Category = myMethods, meta = (ToolTip = "圖標的像素座標轉換成Pivot座標,小地圖是以Pivot爲中心點旋轉的"))
        void SetFlagAsPivot(float x, float y);
};
View Code

   CPP文件:  對象

// Fill out your copyright notice in the Description page of Project Settings.

#include "StaticMiniMapHelper.h"

/**
 *  功能描述:初始化迷你地圖類參數
 *  @self 自身引用
 *  @FlagPanel 小圖標父級容器對象
 *  @CenterPosition 中心對位點
 *  @UIScale 地圖縮放比例
 *  @MapRatio 地圖比例尺
 *
 *  @return
 */
void UStaticMiniMapHelper::Ini(UUserWidget * me, UCanvasPanel * Panelflag, FVector PositionCenter, float ScaleUI, float RatioMap)
{
    this->self = me;
    this->FlagPanel = Panelflag;
    this->CenterPosition = PositionCenter;
    this->UIScale = ScaleUI;
    this->MapRatio = RatioMap;
}

void UStaticMiniMapHelper::AddFlag(UUserWidget* flag, AActor* actor)
{
    UCanvasPanelSlot* slot = FlagPanel->AddChildToCanvas(flag);
    FAnchors InAnchors(0.5f, 0.5f);
    slot->SetAnchors(InAnchors);                //設置錨點:中心對齊
    slot->SetAlignment(FVector2D(0.5f, 0.5f));    //設置對齊:中心對齊
    slot->SetPosition(FVector2D(0, 0));            //設置原點不偏移
    slot->SetAutoSize(true);                    //設置自動尺寸:爲圖片原始尺寸

    //FUMiniMapFlagDataC data;
    //data.flag = flag;
    //data.Actor = actor;
    //data.Slot = slot;
    //FUMiniMapFlagDataC(flag,actor,slot)
    FUMiniMapFlagDataC data(flag, actor, slot);
    FlagArray.Add(data);

}

void UStaticMiniMapHelper::UpdateFlags()
{
    for (int i = 0; i < FlagArray.Num(); i++)
    {
        UpdateFlag(FlagArray[i]);
    }
}

void UStaticMiniMapHelper::UpdateFlag(FUMiniMapFlagDataC data)
{
    FVector ActorLocation = data.Actor->GetActorLocation();
    FVector temp = (ActorLocation - CenterPosition)*(MapRatio*UIScale);
    data.Slot->SetPosition(FVector2D(temp.Y, temp.X*-1));        //設置小圖標位置

    data.flag->SetRenderAngle(data.Actor->GetActorRotation().Yaw);    //旋轉小圖標
}

void UStaticMiniMapHelper::SetUIScale(float scale)
{
    UIScale = scale;
}

//更新全部圖標在小地圖上的位置
void UStaticMiniMapHelper::SetFlagAsPivot(float x, float y)
{
    FVector2D 地圖實際尺寸 = self->GetCachedGeometry().GetLocalSize();        //得到地圖實際尺寸
    float 地圖長度 = 地圖實際尺寸.X;
    float 地圖寬度 = 地圖實際尺寸.Y;

    float 圖標X座標 = x;
    float 圖標Y座標 = y;

    //小地圖旋轉X座標 = (圖標X座標 + 地圖長度/2)/地圖長度
    float 小地圖旋轉X座標 = (圖標X座標 + 地圖長度 / 2) / 地圖長度;
    float 小地圖旋轉Y座標 = (圖標Y座標 + 地圖長度 / 2) / 地圖長度;

    //設置小地圖旋轉原點
    self->SetRenderTransformPivot(FVector2D(小地圖旋轉X座標, 小地圖旋轉Y座標));
}
View Code

 2、在藍圖中添加一個名爲MyHelper的變量,類型是第一步C++建立的類型。

  

3、在使用helper對象以前,必須先實例化。「Spawn Object」是本身用C++寫的一個藍圖庫中的一個方法。

  

4、接着就是要初始化helper的成員變量值。其中當前藍圖對象的引用(也就是self)要傳遞給me參數,這是關鍵,用helper的成員對象保存起來。

  

5、最終用C++相同的方法替換原來用藍圖寫的功能。

  

 

使用繼承和組合均可以實現C++重寫藍圖,可是組合比繼承要更好,耦合度更低! 

遷移遇到的問題:

一、若是藍圖繼承一個C++類,則遷移的時候會出現問題,這個藍圖在新項目裏面打不開的。

二、使用C++組合時能夠遷移到其餘項目,能夠打開藍圖,可是helper全部的相關方法調用變成無效,須要手動從新照着作一次。

 

附註用C++ 實現藍圖函數庫,根據類型動態建立UObject,並返回引用給藍圖使用:

  頭文件

#include "Kismet/BlueprintFunctionLibrary.h"
#include "TimyLibrary.generated.h"

/**
 * 
 */
UCLASS()
class PROJ10_0121_API UTimyLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable, Category = "TimyLibrary|Object", meta = (ToolTip = "建立UObject實例"))
    static UObject* SpawnObject(UObject* owner, UClass* ObjClass);
};
View Code

  CPP文件

// Fill out your copyright notice in the Description page of Project Settings.

#include "TimyLibrary.h"
#include "Runtime/Engine/Classes/Engine/Engine.h"

//建立根據類型建立UObject
UObject* UTimyLibrary::SpawnObject(UObject* owner, UClass* ObjClass)
{
    UWorld* World = GEngine->GetWorldFromContextObject(owner);
    UObject* tempObject = NewObject<UObject>(World, ObjClass);
    //UObject* tempObject = NewObject<UObject>(ObjClass);        //建立對象會失敗
    return tempObject;
}
View Code
相關文章
相關標籤/搜索