unreal4 函数 蓝图_unreal 调用蓝图中函数 - CSDN
精华内容
参与话题
  • C++公开给蓝图 UFUNCTION(BlueprintCallable, Category = "MyCppFunc") void MyFunc(); C++调用蓝图(在头文件声明,蓝图内实现即可,无需在cpp文件实现) UFUNCTION(BlueprintImplementableEvent, Category = ...
    • C++公开给蓝图
    UFUNCTION(BlueprintCallable, Category = "MyCppFunc")
    		void MyCppFunc1();
    
    • C++调用蓝图(在头文件声明,蓝图内实现即可,无需在cpp文件实现)
    UFUNCTION(BlueprintImplementableEvent, Category = "MyBPFunc")
    		void MyBPFunc1();
    
    • C++实现、蓝图可覆盖实现
    UFUNCTION(BlueprintNativeEvent, Category = "MyFunc")
    		void MyFunc1();
    
    展开全文
  • 在之前的虚幻版本中,要想实现某个函数在任意蓝图调用,必须通过C++实现,虚幻4.8版本提供了一个蓝图类—BlueprintFunctionLibrary,在这个蓝图类里写的所有函数都可以在任意蓝图里调用。具体步骤如下。首先,创建一...

    在之前的虚幻版本中,要想实现某个函数在任意蓝图调用,必须通过C++实现,虚幻4.8版本提供了一个蓝图类—BlueprintFunctionLibrary,在这个蓝图类里写的所有函数都可以在任意蓝图里调用。具体步骤如下。

    首先,创建一个BlueprintFunctionLibrary类。右键—Blueprints——蓝图函数宏库即可。
    这里写图片描述
    重命名即可。
    这里写图片描述

    打开这个蓝图,正常写函数即可。在这个蓝图里写的函数所有蓝图都可以通过右键得到并调用(节点关系:类—蓝图名字)。
    这里写图片描述

    展开全文
  • UE4蓝图:初体验(5)函数

    千次阅读 2018-03-11 14:15:04
    而在蓝图中,即使它是可视化的编程,但蓝图是由节点构成的,每一个节点只是单一的功能,由这样的节点去连接成一些逻辑链,这样的是相当复杂的,因为节点非常的多,所以蓝图中也有函数这样的模块,用函数去包装一些单一的功能...

    在编程中使用函数,可以让代码的结构更加模块化,减少代码的复用程度,基本上一个函数就是一个单一的功能.这样看上去更直观.

    而在蓝图中,即使它是可视化的编程,但蓝图是由节点构成的,每一个节点只是单一的功能,由这样的节点去连接成一些逻辑链,这样的是相当复杂的,因为节点非常的多,所以蓝图中也有函数这样的模块,用函数去包装一些单一的功能,让蓝图更加的简洁,易读.

    首先进入到关卡蓝图中,点击Functions后面的添加按钮,添加一个函数,用来判断是否是偶数.我们可以看到Detail面板中,最后有两个很关键的项,Inputs和Outputs.分别为输入和输出.Inputs下的变量实际上就是函数的形参,而Outputs下的变量 则是这个函数节点可以返回的一些值.也就是返回值.这里就比较出C++和蓝图之间的一些区别了.C++中函数的返回值最多只有一个,而蓝图中的函数节点的返回值,只要你愿意,你可以返回n个.

    由于我们这里的函数只是对一个值是否是偶数的判断,所以只需要返回一个bool值即可.

    这里写图片描述

    首先我们很容易的添加了一些节点来完成,对是否为偶数做出了判断.我们可以看到圈起来的地方多了个局部变量的顶点,然后我们点击Event Graph标签,可以发现并没有局部变量,所以说只有在函数中才能使用局部变量.那到底局部变量和其他的变量有什么区别呢?Variables可以看作是全局变量,在任何节点内都可以使用,而Local Variables局部变量只能在函数体中去实现,只能在函数中使用.

    这里写图片描述

    接下来让我们实现一个函数,用来求一个整型数组的平均值,其中就用到了局部变量.

    首先我们先创建一个函数,然后设置函数的参数和返回值.参数为数组,返回值为float类型.

    这里写图片描述

    然后创建一个局部变量,用来保存整个数组之和.
    这里写图片描述

    然后在使用数组的遍历节点,让Sum保存数组之和.求出数组平均数.这里要注意:int/int的值还是int.所以注意在做’/’运算的时候,最好使用float类型.

    这里写图片描述

    然后在关卡蓝图中创建一个数组变量,设置好初始值,右键输入你刚刚写好的函数节点的名字,然后输出答案.

    这里写图片描述

    这里写图片描述

    函数可以说是程序中非常非常重要的一个模块了,只要函数用的好,条例就会非常的清晰.

    展开全文
  • 使用UFunction CustomThunk函数方式,实现蓝图模板功能节点,用来处理任意类型的数组,并探索实现细节背后的蓝图机制。

    Unreal的蓝图和C++一样,也是一种静态类型的编程语言,它又不像其他静态类型语言那样支持模板,有些时候就觉得很不方便。思考了一下这个问题。想要蓝图节点支持任意类型的参数,主要分为两种情况:

    • UObject派生类对象:那很简单了,使用基类指针作为参数就好,在C++里面可以Cast,或者取得对象的UClass,就可以根据反射信息做很多事了;
    • Struct类型,或者TArray<MyStruct>类型:这个是本文的重点。

    其实说蓝图完全不支持“模板”也是不对的,引擎中其实已经有很多能够处理任意Struct或者TArray<MyStruct>类型的节点了!官方文档中把这种情况叫做参数“Wildcard”(通配符)。感谢Unreal开源,通过阅读源代码,加上一点实验,就能够搞清楚具体实现方法和背后的细节。

    下面主要探讨使用UFUNCTION的CustomThunk描述符,实现自定义的Thunk函数;然后通过指定meta的CustomStructureParamArrayParm参数,来实现参数类型“通配符”!这中间的难点是:需要明确蓝图Stack的处理方式。Demo如下图所示:
    在这里插入图片描述

    在上图的Demo中:

    1. 自定义了一个蓝图Struct:MyStruct
    2. 使用C++实现了一个蓝图节点“Show Struct Fields”:可以接受任意UStruct的引用,具体类型可以由C++或者蓝图定义;
    3. 蓝图节点“Array Numeric Field Average”:可以接受任意类型的TArray<MyStruct>,并对数组中指定的数值型字段求平均;

    完整的Demo工程可以从我的GitHub下载:https://github.com/neil3d/UnrealCookBook/tree/master/MyBlueprintNode

    实现蓝图功能节点的几种方式

    在Unreal开发中可以使用C++对蓝图进行扩展,生成Unreal蓝图节点最方便的方法就是写一个UFUNCTION,无论是定义在UBlueprintFunctionLibrary派生类里面的static函数,还是定义在UObject、AActor派生类里面的类成员函数,只要加上UFUNCTION宏修饰,并在宏里面添加BlueprintCallable标识符,就可以自动完成蓝图编辑节点、蓝图节点执行调用的整个过程。不过,由于C++和蓝图都属于“静态类型”编程语言,这种形式编写的蓝图节点,所有的输入、输出参数的类型都必须是固定的,这样引擎才能自动处理蓝图虚拟机的栈。

    先来总结一下C++实现蓝图节点的几种方式:

    1. UFUNCTION,上面已经说过了;
    2. 实现class UK2Node的派生类,这是最强大的方式,是对蓝图节点最深入的定制开发,如果你需要动态的添加、删除蓝图节点的针脚,就只能用这种方式了。例如我们常用的“Format Text”节点,可以根据输入字符串中的“{index}”来动态增加输入节点,输入节点的类型也是动态的,这个就是通过class UK2Node_FormatText这个类来实现的;
    3. 还有介于上面两者之间的一种方式,就是在UFUNCTION中使用“CustomThunk”标识,告诉UHT(Unreal Header Tool)不要生成默认的蓝图包装函数,而是由我们手工实现。这种方式,需要手工控制蓝图虚拟机的“栈”,但是不用处理蓝图编辑器UI部分,相对第2种来说代码量要少很多,相对第1种来说,又多了很多控制力;
    4. 另外,蓝图的“宏”–Macros,也可以实现自己的节点。

    使用第3种方式,结合UFUNCTION的其它meta标识符,可以实现参数类型的“通配符”,就可以实现模板函数,也就是输入、输出参数可以处理多种数据类型,类似C++的泛型。这些meta标识符主要有:

    1. ArrayParm="Parameter1, Parameter2, ..":说明 BlueprintCallable 函数应使用一个Call Array Function节点,且列出的参数应被视为通配符数组属性;
    2. ArrayTypeDependentParams="Parameter":使用 ArrayParm 时,此说明符将指定一个参数,其将确定 ArrayParm 列表中所有参数的类型;
    3. CustomStructureParam="Parameter1, Parameter2, ..":列出的参数都会被视为通配符。

    引擎源代码中,这种编程方式的典型的例子有:

    • 蓝图编辑器中的“Utilities”->“Array”菜单中的所有节点,他们可以处理任意的UStruct类型的数组。这些节点对应的源代码是:class UKismetArrayLibrary
    • class UDataTableFunctionLibrary::GetDataTableRowFromName(UDataTable* Table, FName RowName, FTableRowBase& OutRow)

    详见官方文档:UFunctions

    CustomThunk函数

    如果在UFUNCTION宏里面指定了CustomThunk,那么UHT就不会自动生成这个函数的“thunk”,而需要开发者自己实现。这里的“thunk”是什么呢?我们看个例子。

    我们来做个最简单的小试验,在工程中建立一个Blueprint Function Library,添加一个简单的UFUNCTION:

    #pragma once
    
    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "MyBlueprintFunctionLibrary.generated.h"
    
    UCLASS()
    class MYBLUEPRINTNODES_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
    {
    	GENERATED_BODY()
    public:
    	UFUNCTION(BlueprintCallable)
    	static int Sum(int a, int b);
    };
    

    然后在对应的cpp文件中,使用C++实现这个函数:

    #include "MyBlueprintFunctionLibrary.h"
    
    int UMyBlueprintFunctionLibrary::Sum(int a, int b) {
    	return a + b;
    }
    

    项目build一下,然后你就可以在“Intermediate”目录找到这个"MyBlueprintFunctionLibrary.generated.h"文件。在这个文件里面,你可以找到这样一段代码:

        DECLARE_FUNCTION(execSum) \
    	{ \
    		P_GET_PROPERTY(UIntProperty,Z_Param_a); \
    		P_GET_PROPERTY(UIntProperty,Z_Param_b); \
    		P_FINISH; \
    		P_NATIVE_BEGIN; \
    		*(int32*)Z_Param__Result=UMyBlueprintFunctionLibrary::Sum(Z_Param_a,Z_Param_b); \
    		P_NATIVE_END; \
    	}
    

    这段代码就是蓝图函数节点的thunk了!这段代码做了这样几件事:

    1. 声明了一个名为“execSum”的函数,函数的签名为:void func( UObject* Context, FFrame& Stack, RESULT_DECL )
    2. 使用P_GET_PROPERTY宏,从“FFrame& Stack”(也就是蓝图虚拟机的栈)中取出函数参数;
    3. 调用P_FINISH宏;
    4. 使用取出的这些参数调用我们实现的UMyBlueprintFunctionLibrary::Sum()函数;

    “thunk”函数是一个包装,它完成的核心任务就是处理蓝图虚拟机的Stack,然后调用我们使用C++实现的函数。

    我们还可以看一下UHT帮我们生成的另外一个文件:MyBlueprintFunctionLibrary.gen.cpp,在其中有这样一段代码:

    void UMyBlueprintFunctionLibrary::StaticRegisterNativesUMyBlueprintFunctionLibrary()
    	{
    		UClass* Class = UMyBlueprintFunctionLibrary::StaticClass();
    		static const FNameNativePtrPair Funcs[] = {
    			{ "Sum", &UMyBlueprintFunctionLibrary::execSum },
    		};
    		FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, ARRAY_COUNT(Funcs));
    	}
    

    这段代码把刚才"MyBlueprintFunctionLibrary.generated.h"中声明的excSum函数注册到了UMyBlueprintFunctionLibrary::StaticClass()这个UClass对象之中,并指定它的名字为“Sum”,也就是我们原始C++代码中声明的函数名,也是在蓝图编辑器中显示的名字。

    看清楚了什么是“thunk函数”,“CustomThunk函数”也就不言自明了。在UFUNCTION中指定“CustomThunk”标识符,就是告诉UHT,不要在.generated.h中生成DECLARE_FUNCTION那部分代码,这部分代码改由手写。为啥要抛弃自动生成,而手写呢?回到本文主题:要实现“参数类型通配符”(或者叫做“蓝图模板节点”),就必须手写thunk!

    蓝图Stack探索

    要实现自己的thunk函数,核心任务就是“准确的处理蓝图虚拟机的栈”,可惜的是官方并没有这方面的文档!下面我就把自己的一些探索记录下来,请大家指正。

    以上面的int Sum(int a, int b)函数为例,thunk函数使用P_GET_PROPERTY宏从Stack取值,这个宏P_GET_PROPERTY(UIntProperty,Z_Param_a)展开之后的代码如下所示:

    	UIntProperty::TCppType Z_Param_a = UIntProperty::GetDefaultPropertyValue();
    	Stack.StepCompiledIn<UIntProperty>(&Z_Param_a);
    

    其中UIntProperty派生自TProperty_Numeric<int32>UIntProperty::TCppType就是“int32”无疑!

    我们还需要处理TArray<MyStruct>这样的数据,所以我们重点要看一下这种参数类型的栈处理。
    假设我们有一个C++的UStruct:

    USTRUCT(Blueprintable)
    struct FMyStruct {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY(EditAnywhere, BlueprintReadWrite)
    	FString Name;
    
    	UPROPERTY(EditAnywhere, BlueprintReadWrite)
    	int Value;
    };
    

    类似这样一个UFUNCTION:

    UFUNCTION(BlueprintCallable)
    static void PrintMyStructArray(const TArray<FMyStruct>& MyStructArray);
    

    则在.h中的thunk函数为:

    DECLARE_FUNCTION(execPrintMyStructArray) \
    	{ \
    		P_GET_TARRAY_REF(FMyStruct,Z_Param_Out_MyStructArray); \
    		P_FINISH; \
    		P_NATIVE_BEGIN; \
    		UMyBlueprintFunctionLibrary::PrintMyStructArray(Z_Param_Out_MyStructArray); \
    		P_NATIVE_END; \
    	} \
    

    其中P_GET_TARRAY_REF(FMyStruct,Z_Param_Out_MyStructArray);这个宏展开之后的代码为:

    PARAM_PASSED_BY_REF(Z_Param_Out_MyStructArray, UArrayProperty, TArray<FMyStruct>)
    

    最终展开为:

    TArray<FMyStruct> Z_Param_Out_MyStructArrayTemp;
    TArray<FMyStruct>& Z_Param_Out_MyStructArray = Stack.StepCompiledInRef<UArrayProperty, TArray<FMyStruct> >(&Z_Param_Out_MyStructArrayTemp);
    

    综合上面两个例子,我们发现核心操作都是调用template<class TProperty> void FFrame::StepCompiledIn(void*const Result)这个模板函数。通过跟踪这个函数的执行,发现它实际调用了UObject::execInstanceVariable()函数。

    1. 更新"FFrame::PropertyChainForCompiledIn"这个成员变量;
    2. 使用更新后的“FFrame::PropertyChainForCompiledIn”值,更新了"FFrame::MostRecentPropertyAddress"成员变量。

    再结合引擎中CustomThunk函数的实现源码,可以得出这样的结论:

    1. 通过调用Stack.StepCompiledIn()函数,就可以更新蓝图虚拟机的栈顶指针;

    2. Stack.MostRecentPropertyAddressStack.MostRecentProperty这两个变量,就是当前参数值的内存地址和反射信息。

    有了具体变量的内存地址和类型的反射信息,就足够做很多事了。下面我们就开始实践。

    实践1:接受任意UStruct类型参数

    下面我们就看一下文章开头的这张图里面的蓝图节点“Show Struct Fields”是如何接受任意类型UStruct参数的。

    先上代码, BlueprintWildcardLibrary.h

    USTRUCT(BlueprintInternalUseOnly)
    struct FDummyStruct {
    	GENERATED_USTRUCT_BODY()
    
    };
    
    UCLASS()
    class UNREALCOOKBOOK_API UBlueprintWildcardLibrary : public UBlueprintFunctionLibrary {
    	GENERATED_BODY()
    
    public:
    	UFUNCTION(BlueprintCallable, CustomThunk, Category = "MyDemo", meta = (CustomStructureParam = "CustomStruct"))
    		static void ShowStructFields(const FDummyStruct& CustomStruct);
    	static void Generic_ShowStructFields(const void* StructAddr, const UStructProperty* StructProperty);
    
    	DECLARE_FUNCTION(execShowStructFields) {
    
    		Stack.MostRecentPropertyAddress = nullptr;
    		Stack.MostRecentProperty = nullptr;
    
    		Stack.StepCompiledIn<UStructProperty>(NULL);
    		void* StructAddr = Stack.MostRecentPropertyAddress;
    		UStructProperty* StructProperty = Cast<UStructProperty>(Stack.MostRecentProperty);
    
    
    		P_FINISH;
    
    		P_NATIVE_BEGIN;
    		Generic_ShowStructFields(StructAddr, StructProperty);
    		P_NATIVE_END;
    	}
    };
    

    BlueprintWildcardLibrary.cpp

    #include "BlueprintWildcardLibrary.h"
    #include "Engine/Engine.h"
    
    void UBlueprintWildcardLibrary::Generic_ShowStructFields(const void* StructAddr, const UStructProperty* StructProperty) {
    	UScriptStruct* Struct = StructProperty->Struct;
    	for (TFieldIterator<UProperty> iter(Struct); iter; ++iter) {
    
    		FScreenMessageString NewMessage;
    		NewMessage.CurrentTimeDisplayed = 0.0f;
    		NewMessage.Key = INDEX_NONE;
    		NewMessage.DisplayColor = FColor::Blue;
    		NewMessage.TimeToDisplay = 5;
    		NewMessage.ScreenMessage = FString::Printf(TEXT("Property: [%s].[%s]"),
    			*(Struct->GetName()),
    			*(iter->GetName())
    		);
    		NewMessage.TextScale = FVector2D::UnitVector;
    		GEngine->PriorityScreenMessages.Insert(NewMessage, 0);
    	}
    }
    

    解释一下这段代码:

    1. 首先声明了一个UFunction:static void ShowStructFields(const FDummyStruct& CustomStruct);,其参数类型是“FDummyStruct”,这只是一个占位符;
    2. 在UFUNCTION宏里面指定“CustomThunk”和“CustomStructureParam”;
    3. 实现一个execShowStructFields函数。这个函数很简单,主要是处理蓝图的Stack,从中取出需要的参数,然后对用C++的实现;
    4. 具体功能实现在:static void Generic_ShowStructFields(const void* StructAddr, const UStructProperty* StructProperty)这个函数中。

    实践2:对数组中的Struct的数值型求平均

    下面我们再来一下文章开头的这张图里面的“Array Numeric Field Average”蓝图节点是如何通过“CustomThunk”函数来实现的。

    参照引擎源代码,我定义了这样一个宏,用来从栈上取出泛型数组参数,并正确的移动栈指针:

    #define P_GET_GENERIC_ARRAY(ArrayAddr, ArrayProperty) Stack.MostRecentProperty = nullptr;\
    		Stack.StepCompiledIn<UArrayProperty>(NULL);\
    		void* ArrayAddr = Stack.MostRecentPropertyAddress;\
    		UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Stack.MostRecentProperty);\
    		if (!ArrayProperty) {	Stack.bArrayContextFailed = true;	return; }
    

    通过这个宏,可以得到两个局部变量:

    • void* ArrayAddr: 数组的起始内存地址;
    • UArrayProperty* ArrayProperty: 数组的反射信息,ArrayProperty->Inner就是数组成员对应的类型了;

    有了这个宏,我们就可以很方便的写出thunk函数了:

    DECLARE_FUNCTION(execArray_NumericPropertyAverage) {
    
    		// get TargetArray
    		P_GET_GENERIC_ARRAY(ArrayAddr, ArrayProperty);
    
    		// get PropertyName
    		P_GET_PROPERTY(UNameProperty, PropertyName);
    
    		P_FINISH;
    
    		P_NATIVE_BEGIN;
    		*(float*)RESULT_PARAM = GenericArray_NumericPropertyAverage(ArrayAddr, ArrayProperty, PropertyName);
    		P_NATIVE_END;
    	}
    

    经过以上的准备,我们就已经可以正确的处理“泛型数组”了。下一步就是对这个数组中指定的数“值类型成员变量”求均值了,这主要依靠Unreal的反射信息,一步步抽丝剥茧,找到数组中的每个变量即可。反射系统的使用不是本文的重点,先看完整代码吧。

    BlueprintWildcardLibrary.h

    #pragma once
    
    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "BlueprintWildcardLibrary.generated.h"
    
    #define P_GET_GENERIC_ARRAY(ArrayAddr, ArrayProperty) Stack.MostRecentProperty = nullptr;\
    		Stack.StepCompiledIn<UArrayProperty>(NULL);\
    		void* ArrayAddr = Stack.MostRecentPropertyAddress;\
    		UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Stack.MostRecentProperty);\
    		if (!ArrayProperty) {	Stack.bArrayContextFailed = true;	return; }
    
    UCLASS()
    class UNREALCOOKBOOK_API UBlueprintWildcardLibrary : public UBlueprintFunctionLibrary {
    	GENERATED_BODY()
    
    public:
    
    	UFUNCTION(BlueprintPure, CustomThunk, meta = (DisplayName = "Array Numeric Property Average", ArrayParm = "TargetArray", ArrayTypeDependentParams = "TargetArray"), Category = "MyDemo")
    		static float Array_NumericPropertyAverage(const TArray<int32>& TargetArray, FName PropertyName);
    	static float GenericArray_NumericPropertyAverage(const void* TargetArray, const UArrayProperty* ArrayProperty, FName ArrayPropertyName);
    
    public:
    	DECLARE_FUNCTION(execArray_NumericPropertyAverage) {
    
    		// get TargetArray
    		P_GET_GENERIC_ARRAY(ArrayAddr, ArrayProperty);
    
    		// get PropertyName
    		P_GET_PROPERTY(UNameProperty, PropertyName);
    
    		P_FINISH;
    
    		P_NATIVE_BEGIN;
    		*(float*)RESULT_PARAM = GenericArray_NumericPropertyAverage(ArrayAddr, ArrayProperty, PropertyName);
    		P_NATIVE_END;
    	}
    };
    
    

    BlueprintWildcardLibrary.cpp

    
    #include "BlueprintWildcardLibrary.h"
    #include "Engine/Engine.h"
    
    float UBlueprintWildcardLibrary::Array_NumericPropertyAverage(const TArray<int32>& TargetArray, FName PropertyName) {
    	// We should never hit these!  They're stubs to avoid NoExport on the class.  Call the Generic* equivalent instead
    	check(0);
    	return 0.f;
    }
    
    float UBlueprintWildcardLibrary::GenericArray_NumericPropertyAverage(const void* TargetArray, const UArrayProperty* ArrayProperty, FName PropertyName) {
    
    	UStructProperty* InnerProperty = Cast<UStructProperty>(ArrayProperty->Inner);
    	if (!InnerProperty) {
    		UE_LOG(LogTemp, Error, TEXT("Array inner property is NOT a UStruct!"));
    		return 0.f;
    	}
    
    	UScriptStruct* Struct = InnerProperty->Struct;
    	FString PropertyNameStr = PropertyName.ToString();
    	UNumericProperty* NumProperty = nullptr;
    	for (TFieldIterator<UNumericProperty> iter(Struct); iter; ++iter) {
    		if (Struct->PropertyNameToDisplayName(iter->GetFName()) == PropertyNameStr) {
    			NumProperty = *iter;
    			break;
    		}
    	}
    	if (!NumProperty) {
    		UE_LOG(LogTemp, Log, TEXT("Struct property NOT numeric = [%s]"),
    			*(PropertyName.ToString())
    		);
    	}
    
    
    	FScriptArrayHelper ArrayHelper(ArrayProperty, TargetArray);
    	int Count = ArrayHelper.Num();
    	float Sum = 0.f;
    
    	if(Count <= 0)
    		return 0.f;
    
    	if (NumProperty->IsFloatingPoint())
    		for (int i = 0; i < Count; i++) {
    			void* ElemPtr = ArrayHelper.GetRawPtr(i);
    			const uint8* ValuePtr = NumProperty->ContainerPtrToValuePtr<uint8>(ElemPtr);
    			Sum += NumProperty->GetFloatingPointPropertyValue(ValuePtr);
    
    		}
    	else if (NumProperty->IsInteger()) {
    		for (int i = 0; i < Count; i++) {
    			void* ElemPtr = ArrayHelper.GetRawPtr(i);
    			const uint8* ValuePtr = NumProperty->ContainerPtrToValuePtr<uint8>(ElemPtr);
    			Sum += NumProperty->GetSignedIntPropertyValue(ValuePtr);
    		}
    	}
    	// TODO: else if(enum类型)
    
    	return Sum / Count;
    }
    
    展开全文
  • Unreal 4 抛物线 蓝图完整实现 可用于HTC Vive 传送时,曲线的实现
  • 通过派生class UK2Node和class SGraphNodeK2Base,为蓝图添加自定义节点,实现一个“动态添加输入Pin”的蓝图节点。
  • 通过派生class UK2Node,为蓝图添加自定义节点;这篇博客我们先实现一个最简单的自定义节点,下篇文章将完成“动态添加输入Pin”的蓝图节点。
  • 这篇博客主要是深入理解蓝图整个流程的的底层机制,包括节点编辑、编译、字节码解释执行。理解了这些,对前面几篇所讲的蓝图扩展,可以有一个更清晰的认识。
  • UE4之C++调用蓝图函数

    千次阅读 2018-09-10 08:14:52
    我们都知道蓝图调用C++的函数或者变量都很简单, 直接在C++的.h文件中所要暴露的变量或者函数头上 加上宏就可以了 然而,在C++中调用蓝图写好的函数就不是很简单了 1,首先我们创建一个C++类,我用的是Pawn、...
  • Unreal Engine 4 蓝图之自定义事件

    千次阅读 2015-01-11 01:15:00
    UE4蓝图就跟C++等编程语言在概念上是非常类似的。在蓝图中你可以定义变量、函数、宏等等,高级点的,它还可以被继承。这还不算,我们还可以定义蓝图接口,规范子类的行为。基本上C++中可以做的,蓝图也可以做到,...
  • Unreal Engine 4 蓝图脚本学习,根据《Blueprints Visual Scripting for Unreal Engine》学习整理
  • 文章目录概述蓝图函数蓝图宏库 概述 蓝图函数库(Blueprint Function Library)和蓝图宏库(Blueprint Macro Library)的意义和C/C++中函数以及宏大致相同。它们都是用于代码复用,并且如果合理使用可以让蓝图变得...
  • UE4 C++ 蓝图函数模板 自定义解析

    千次阅读 2018-12-12 19:21:08
    UE4 C++ 蓝图函数模板 自定义解析版本:4.20泛型编程蓝图函数模板 版本:4.20 泛型编程 模板是泛型编程的基础,即以一种独立于任何类型的方式编写代码。模板是创建一系列类(Class)或函数(Function)的通用标准或...
  • 蓝图构造函数ConstructionScript

    千次阅读 2017-07-26 09:58:03
    本篇介绍蓝图构造函数Construction ScriptCSDN的博客添加图片太麻烦了,而且链接网页图片会出现错误,如果需要看详细文章,请访问我的微信公众号《猎梦虚幻研究社》先来看一下这个函数长什么样子: 很尴尬的发现这...
  • 本节书摘来异步社区《Unreal Engine 4蓝图可视化编程》一书中的第2章,第2.1节,作者: Brenden Sewell 译者: 陈东林 责编: 胡俊英,更多章节内容可以访问云栖社区“异步社区”公众号查看。 2.1 通过扩展蓝图添加...
  • UE4蓝图调用C++函数

    2016-03-17 23:33:27
      调用UFUNCTION(UE4模版函数): https://wiki.unrealengine.com/Blueprints,_Creating_C%2B%2B_Functions_as_new_Blueprint_Nodes    
  • 命令格式 ce +函数名+参数 举例这是写在关卡蓝图的一个函数控制台输入ce结果除了ce以外,还有ke,这个是调用actor中函数的命令。具体用法是“ ke 类名 函数名 参数 ”如果你不知道actor的名字,那么可以直接使用ke ...
  • 最近要写一个插件,希望尽量傻瓜化不需要用户操作任何,但是在蓝图构造函数下要执行某些函数 想在C++中把这一步做了 找了半天没找到地方 最终发现了OnConstruction这个函数,重写就行了 太蠢了,记下来- - ...
  • 前面两篇博客我们都是通过ExpandNode来实现蓝图节点的功能,这一篇来介绍另外一种重要的蓝图扩展方式,就是Node Handler。
  • 虚幻4蓝图快速入门(一)

    万次阅读 2018-06-02 19:48:12
    蓝图快速入门序言本文依据官方教程总结而来,只是带你对蓝图有一个快速的认识,如果想对蓝图有一个比较深入的了解,那么可以看官方的视频或者是做一些小项目练手,如果你有编程经验的话,上手还是很容易的。蓝图快速...
1 2 3 4 5 ... 20
收藏数 1,027
精华内容 410
关键字:

unreal4 函数 蓝图