[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
相关文章
相关标签/搜索