先大量使用蓝图制作项目,后续再用C++把复杂的蓝图重写一遍,用C++代码按照蓝图依葫芦画瓢就可以了,很简单,但需要遵守一些原则:

第一种方法:使用继承

一、创建一个C++类作为蓝图的父类(C++类继承蓝图一样的父类),在UE4中修改蓝图的父类。

二、C++类中的方法、成员变量与蓝图一一对应,并且方法和成员变量名称不能与蓝图的重复。

三、A蓝图不能直接使用B蓝图的变量,A蓝图把要公开的变量封装在函数内返回,并且只返回UE4自带的基础变量类型,不能返回自定义类型,以方便C++重写时返回C++中的成员变量。

四、用C++中实现好的方法逐个替换蓝图中方法,每次替换一个方法就必须要运行游戏进行详细测试,防止修改太多万一出错无法定位问题所在。如下图所示:保留原蓝图的实现,方便C++代码查错。

五、任意一个用C++方法替换蓝图相应的方法 ,都能保证游戏能正常运行,尽量避免出现要同时替换2个以上蓝图方法才能正常运行游戏。这一点非常重要。同样也是防止修改太多万一出错无法定位问题所在。

六、蓝图方法给变量赋值,也可以直接调用C++对应方法赋值,以保证C++其它函数方法能正常运行。

  

第二种使用C++重写蓝图的方法:使用组合

一、创建一个继承自UObject的C++类,一般加后缀Helper,并且加上BlueprintType标签,共蓝图作为变量类型使用。

  头文件:  

// 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);
};

  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(, )); //设置原点不偏移
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 = ; 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*-)); //设置小图标位置 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坐标 + 地图长度 / ) / 地图长度;
float 小地图旋转Y坐标 = (图标Y坐标 + 地图长度 / ) / 地图长度; //设置小地图旋转原点
self->SetRenderTransformPivot(FVector2D(小地图旋转X坐标, 小地图旋转Y坐标));
}

二、在蓝图中添加一个名为MyHelper的变量,类型是第一步C++创建的类型。

  

三、在使用helper对象之前,必须先实例化。“Spawn Object”是自己用C++写的一个蓝图库中的一个方法。

  

四、接着就是要初始化helper的成员变量值。其中当前蓝图对象的引用(也就是self)要传递给me参数,这是关键,用helper的成员对象保存起来。

  

五、最终用C++相同的方法替换原来用蓝图写的功能。

  

使用继承和组合都可以实现C++重写蓝图,但是组合比继承要更好,耦合度更低!

迁移遇到的问题:

1、如果蓝图继承一个C++类,则迁移的时候会出现问题,这个蓝图在新项目里面打不开的。

2、使用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);
};

  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;
}

[UE4]使用C++重写蓝图,SpawnObject根据类型动态创建UObject的更多相关文章

  1. [UE4]认识CanvasPanelSlot,Construct Object From Class动态创建UI控件

    Canvas Panel Slot是UserWidget的Canvas Panel组件容器内的组件特有的属性. 只有放置在Canvas Panel容器内才会有Canvas Panel Slot属性 可 ...

  2. 关于Emit中动态类型TypeBuilder创建类标记的一点思考

      利用TypeBuilder是可以动态创建一个类型,现在有个需求,动态生成一个dll,创建类型EmployeeEx,需要继承原dll里面的Employee类,并包含Employee类上的所有类标记. ...

  3. iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结

    iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结 项目中我们常见的自定义cell主要分为两种 等高cell:如应用列表.功能列表 非等高cell:如微博列表.QQ聊天页面 下面对这 ...

  4. .Net 中的反射(动态创建类型实例) - Part.4

    动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它.可以说,前面三节,我们学习的都是反射是什么,在接下来的章节中,我们将学习反射可以 ...

  5. C# 在运行时动态创建类型

    C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...

  6. [转]js动态创建json类型

    废话少说:json是一个特有的键值对数组类型.既然是数组类型那么我们就可以这样定义 1.先定义数组 var Data = []; 2.理解键值对 对象名:值{ "id": i, & ...

  7. mysql索引总结(1)-mysql 索引类型以及创建

    mysql索引总结(1)-mysql 索引类型以及创建 mysql索引总结(2)-MySQL聚簇索引和非聚簇索引 mysql索引总结(3)-MySQL聚簇索引和非聚簇索引 mysql索引总结(4)-M ...

  8. 封装basedao及动态创建新类型的java数组

    package com.huawei.base; import java.io.Serializable;import java.lang.reflect.Array;import java.lang ...

  9. 静态类型&动态类型

    何时使用:使用存在继承关系的类型时,必须将一个变量或其他表达式的静态类型与该表达式表示对象的动态类型区分开来 静态类型:表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型 动态 ...

随机推荐

  1. mysql插入操作跳过(ignore)、覆盖(replace into)、更新(on duplicate key)

    原帖地址:http:.html .insert ignore into 当插入数据时,如出现错误时,如重复数据,将不返回错误,只以警告形式返回.所以使用ignore请确保语句本身没有问题,否则也会被忽 ...

  2. LA3641 Leonardo's Notebook

    题意 PDF 分析 给出一个26个大写字母的置换B,是否存在A^2 = B 每个置换可以看做若干个循环的乘积.我们可以把这些循环看成中UVa 10294的项链, 循环中的数就相当于项链中的珠子. A^ ...

  3. 安装windows系统时遇到的大坑——鼠标键盘没反应

    进入安装系统界面时,鼠标键盘没反应,换到其他usb接口也不行 解决方法如下,需要进入bios设置两个地方,设置如下 安装好系统(win7)之后,还遇到了两个问题,一个是驱动没安装,插U盘也没反应,一个 ...

  4. mysql自增主键

    MariaDB [test]> create table test1(id int primary key auto_increment,name varchar(20))auto_increm ...

  5. Singer 学习九 运行&&开发taps、targets (四 开发target)

    singer 的target 需要从stdin 的行数据,同时处理schema.record.state 消息 指南 schema 需要进行关联stream records 数据的校验 一旦Targe ...

  6. SAS常用函数

    SAS常用函数 一.数学函数  ABS(x) 求x的绝对值. MAX(x1,x2,…,xn) 求所有自变量中的最大一个. MIN(x1,x2,…,xn) 求所有自变量中的最小一个. MOD(x,y) ...

  7. 免费开源 KiCad EDA 中文资料收集整理(2019-04-30)

    免费开源 KiCad EDA 中文资料收集整理 用 KiCad 也有一段时间了,为了方便自己查找,整理一下 KiCad 的中文资料,会不定期更新. 会收集KiCad 的新闻.元件封装库.应用技巧.开源 ...

  8. 学习笔记:Javascript 变量 包装对象

    学习笔记:Javascript 变量 包装对象 如下代码,可以输出字符的长度. var str = "Tony"; str.length; 这时再试试以下代码,返回是 undefi ...

  9. mysql 的 docker 镜像使用

    mysql 的 docker 镜像使用: 下载镜像: docker pull mysql:8.0.14 运行容器: docker run -it -e MYSQL_ROOT_PASSWORD=mypw ...

  10. windows python监听文件触发脚本

    from watchdog.events import * class FileEventHandler(FileSystemEventHandler): def __init__(self): Fi ...