虚幻4蓝图快速入门(四)

蓝图跟C++交互

概述

蓝图可以继承C++类,从而使得程序员可以在代码中创建新的游戏性类,而关卡设计人员可以使用蓝图来继承该类并对其进行修改。 有很多种修饰符可以改变C++类和蓝图系统间交互方式,其中某些修饰符会在本示例中突出介绍。

可以通过查看以下内容来快速了解:

  • 虚幻引擎快速入门视频教程第五章,见引用[1]
  • 官方文档

类设置

在类设置的第一部分中,使用C++类向导创建一个名称为LightSwitchBoth 的类。

LightSwitchBoth类中的大部分代码设置都和 仅使用C++的LightSwitch示例 类似。尽管您可以让一个蓝图继承LightSwitchCodeOnly类,但蓝图图表并不能访问该类中创建的组件、属性及函数。该示例将使用 UPROPERTY() 和 UFUNCTION() 修饰符,这两个修饰符使得LightSwitchBoth作为继承它的蓝图的模板。

这个头文件是从 仅使用C++的LightSwitch示例 改编而来,添加了以下功能:

  • PointLightComponent和SphereComponent是BlueprintReadOnly(仅蓝图可读的),并且将显示在 我的蓝图 选卡中的 Switch Components(切换组件) 类目中。
  • OnOverlap现在是一个BlueprintNativeEvent,将会显示在 我的蓝图 选卡中的 Switch Functions(切换函数) 类目中。
  • DesiredBrightness是BlueprintReadWrite(蓝图可读写的),将显示在 我的蓝图 选卡中的 Switch Properties(切换属性) 类目中。
  • DesiredBrightness现在是EditAnywhere(随处可编辑的),而不是VisibleAnywhere(随处可见的)。

在LightSwitchBoth的源文件中,构造器仍然是一样的。但是,需要对 OnOverlap 函数做一点修改。这个函数现在是一个BlueprintNativeEvent。这意味着 在继承这个类的蓝图中,可以放置一个覆盖 OnOverlap 的事件,当正常调用该函数时会执行此事件。如果该事件不存在,那么则是执行那个函数的 C++实现。要想使这个设置正常工作,该C++函数需要重命名为 OnOverlap_Implementation 。稍后在本示例中将介绍这个蓝图设置。对 OnOverlap 函数 进行了修改后,LightSwitchBoth 的源文件如下所示:

当创建类时,新的 UCLASS() 、UFUNCTION() 或 UPROPERTY() 宏意味着该代码必须在Visual Studio 或Xcode中进行编译,然后使用虚幻编辑器重新加载它们。 关闭虚幻编辑器,在Visual Studio 或Xcode中编译该项目,然后打开编辑器并重新加载该项目,以确保正确地重新加载该游戏模块。

当重新打开虚幻编辑器并重新打开您的项目后,便可以创建一个新的类蓝图了。 在本示例中,选择LightSwitchBoth作为该蓝图的父类,蓝图名称为 LightSwitchBoth_BP 。

在 C++代码中添加的PointLightComponent和SphereComponent 也会显示在 Blueprint Editor(蓝图编辑器) 的 组件模式中的 Components(组件) 选卡内。 它们的图标是深蓝色,表示它们是从父类LightSwitchBoth类继承而来的原生组件。而刚刚添加到 LightSwitchBoth_BP 蓝图中的新组件的图标 是浅蓝色的

在 Graph Mode(图标模式) 中, My Blueprint(我的蓝图) 选卡显示了在C++中添加到LightSwitchBoth类中的 PointLightComponent 和SphereComponent 。这是因为 BlueprintReadOnly 修饰符存在的缘故。 通过在 我的蓝图 选卡中点击并拖拽这些组件的名称到图表中,可以将这些组件的节点添加到图表中。然后,您可以把这些节点连接到改变像可见性 或光源颜色这样属性的节点上。DesiredBrightness 属性也会出现在 我的蓝图 选卡中。因为它是一个属性,而不是一个组件,所以可以使用 BlueprintReadWrite 修饰符。这意味着在蓝图图表中可以创建节点来获取及设置 DesiredBrightness 的值。

有两个图表用于设置 LightSwitchBoth_BP 类的行为。第一个是构造脚本图表,它包含了一个专用的 Construction Script(构建脚本)事件。如果没有该 Construction Script 设置,那么新的 LightSwitchBoth_BP Actor 将仅使用LightSwitchBoth的构造函数。然而,当Actor在关卡中移动时,及当 Desired Brightness 发生改变时,都会执行 Construction Script 。使用 Construction Script 意味着,可以轻松地改变暴露给蓝图的Actor属性, 并且可以快速地看到这些修改的效果。

在 LightSwitchBoth_BP 类中, Construction Script 事件连接到了 Set Brightness 节点上,以便当在关卡中添加或移动Actor时或者 Desired Brightness 发生改变时,将 Point Light 1 (PointLightComponent) 的亮度设置为 Desired Brightness 的值。

在 LightSwitchBoth_BP 类中, Construction Script 事件连接到了 Set Brightness 节点上,以便当在关卡中添加或移动Actor时或者 Desired Brightness 发生改变时,将 Point Light 1 (PointLightComponent) 的亮度设置为 Desired Brightness 的值。

LightSwitch_BPOnly 类中设置的另一个图表是 事件图表 。EventGraph的执行是由事件触发的。在这个示例中, 任何时候当调用C++函数 OnOverlap 时, OnOverlap 就会执行。在LightSwitchBoth的源文件中,设置了代理,以便当一个Actor进入或离开SphereComponent时会执行 OnOverlap 。

在变量的设置中, DesiredBrightness 变量设置为 EditAnywhere (随处可编辑) ,所以在 蓝图编辑器 的默认模式中它是可见的,并且可以进行编辑。 这意味着对于类的每个实例,这个变量是可以变化的,所以每个Actor可以有其自己的 DesiredBrightness 。因为 DesiredBrightness 也是 BlueprintReadWrite(蓝图可读写) 的,且 Construction Script 中使用了它,所以更新它还会导致再次执行 Construction Script 。

其他Class Blueprints(类蓝图)可以继承由蓝图创建的类,通过以下两种方式实现:使用 Class Viewer(类别查看器) 中的类附近的下拉列表按钮来创建一个新蓝图, 或者通过右击该蓝图并选择 Create New Blueprint Based on This(基于此蓝图创建一个新蓝图) 。

蓝图函数库

有时候有一些帮助函数,我们需要在蓝图中使用,这时候我们可以创建一个蓝图函数库。它是一些静态函数的集合。

创建蓝图库跟使用UFUNCITON()暴露一些函数给蓝图很相似。只需要继承UBlueprintFunctionLibrary即可。它们也应该包含静态函数。

下面是StartSession的实现

编译后,就可以在蓝图内里面调用这些方法了。

属性修饰符

此处只列举了一些常用的属性,具体参照官方文档

  • AdvancedDisplay
  • AssetRegistrySearchable
  • BlueprintAssignable仅能用于Multicast代理。应显示该属性,以供在蓝图中分配。
  • BlueprintCallable仅能用于Multicast代理。应显示该属性,以在蓝图代码中调用。
  • BlueprintReadOnly 只读
  • BlueprintReadWrite 读写
  • Category定义属性的分类

  • Config
  • Const
  • DuplicateTransient
  • EditAnywhere表示该属性可从编辑器内的属性窗口编辑。
  • EditDefaultsOnly表示该属性可通过属性窗口来编辑,但仅能对原型编辑。
  • EditFixedSize
  • EditInline
  • EditInstanceOnly

函数修饰符

函数声明

UFUNCTION([specifier, specifier, ...], [meta(key=value, key=value, ...)])

ReturnType FunctionName([Parameter, Parameter, ...])

函数修饰符

在声明函数时,声明上可添加修饰符以控制引擎和编辑器的不同方面的属性表现。

  • BlueprintAuthorityOnly
  • BlueprintCallable 该函数可在蓝图或关卡蓝图图表内执行。
  • BlueprintCosmetic 此函数为修饰函数而且无法运行在专属服务器上
  • BlueprintImplementableEvent此函数可以在蓝图或关卡蓝图图表内进行重载。
  • BlueprintNativeEvent 此函数将由蓝图进行重载,但同时也包含native类的执行。提供一个名称为[FunctionName]_Implementation的函数本体而非[FunctionName];自动生成的代码将包含转换程序,此程序在需要时会调用实施方式。
  • BlueprintPure 此函数不会以任何方式影响其从属对象,并且可在蓝图或关卡蓝图图表中执行。
  • Category 当在蓝图编辑工具中显示时,定义函数的分类。

  • Client此函数仅在该函数从属对象所从属的客户端上执行。提供一个名称为[FunctionName]_Implementation的函数主体,而不是[FunctionName]; 自动生成的代码将包含一个转换程序来在需要时调用实现方法。
  • CustomThunk UnrealHeaderTool(虚幻头文件工具)的代码生成器将不会为此函数生成execFoo转换程序; 可由用户来提供
  • Exec此函数可从游戏中的控制台中执行。Exec命令仅在特定类中声明时才产生作用。
  • NetMulticast无论Actor的NetOwner为何值,此函数都会在服务器上被本地执行且将被复制到所有的客户端
  • Reliable此函数在网络间进行复制,并会忽略带宽或网络错误而被确保送达。仅在与客户端或服务器共同使用时可用
  • Server此函数仅在服务器上执行。提供一个名称为[FunctionName]_Implementation的函数主体,而不是[FunctionName]; 自动生成的代码将包含一个转换程序来在需要时调用实现方法。
  • Unreliable此函数在网络间复制,但可能会由于带宽限制或网络错误而传送失败。仅在与客户端或服务器一起使用时有效。

类修饰符

在声明类时,声明上可添加修饰符以控制引擎和编辑器的不同方面的类表现。

有太多修饰符,此处仅列举一些常用的,其它请参考官方文档。

  • Blueprintable指定该类为创建蓝图的可接受基类。除非被继承,否则默认值为NotBlueprintable。它由子类继承。
  • BlueprintType此类可作为蓝图中的一种变量类型使用
  • Abstract Abstract 类修饰符将类声明为"抽象基类",这样会阻止用户在虚幻编辑器中向这个世界中添加这个类的Actor,或者在游戏过程中创建这个类的实例。
  • Deprecated该类已被废弃,并且该类的对象在序列化时将不会被保存。该标识由子类继承。

元数据修饰符

在声明类、函数和接口时,声明上可添加元数据修饰符以控制其在引擎和编辑器的不同方面的表现。

对元数据修饰符的使用按常规类、函数和接口修饰符而不同。

类元数据修饰符

  • BlueprintSpawnableComponent

函数元数据修饰符

  • BlueprintInternalUseOnly
  • BlueprintProtected
  • DeprecatedFunction
  • DeprecationMessage
  • UnsafeDuringActorConstruction

接口元数据修饰符

  • CannotImplementInterfaceInBlueprint

蓝图技术指南

蓝图编程指南

当决定使用C++或者蓝图时,有两个主要考虑的因素

  • 速度
  • 表达式复杂度

除了这两个因素外,其它的来自游戏的复杂程序以及团队的组成。如果你有比程序员更多的设计师,那么蓝图代码将会比C++代码多很多。相反,如果你有更多的程序员,那么他们可能更倾向于使用C++。我们(Epic)期望在这中间有一个平衡点。在Epic,大多工作流程是这样的,内容创建者会做一个非常复杂的蓝图,程序员通过C++编写一个新的蓝图节点来把前面所创建的蓝图的大部分转成C++代码,他把那部分功能转成了C++函数。一个好的经验是大量使用蓝图,然后把它转换成C++代码,当它们达到一定复杂度的时候,它需要一个关于该功能一个更精确的表达式(或者对于一个非程序员太复杂时),或者执行速度过慢需要转换成C++时。

速度

就速度来说,蓝图肯定会比C++慢(8~10倍见上方引用部分),并不是说性能就非常差,但是如果你做的事情需要很多的计算,或者执行频率非常高,那么最多是使用C++而不是蓝图。然而,很好地结合两者来为你们团队很好的工作和取得一个不错的性能是很有可能的。如果一个蓝图类有很多功能,那么你可以把一些功能转换成C++代码来加速,但是保留其它的部分来保证灵活性。如果你的性能分析发现蓝图中的某个操作很耗时,那么可以把那部分转移到C++,其它的保留在蓝图中。

假如要使用蓝图来控制几千个Actor,那么这种情况下就最好用C++来处理决策、寻路等,然后把一个可调节的属性和控制函数暴露给蓝图。

复杂度

就表达式复杂来说,有些东西用C++来做确实比蓝图容易。蓝图在很多方面做的很好,但是有些东西在蓝图结点内却并不好表达。比如操作大量数据,字符串操作,大量数据的数学操作等都很复杂,且在一个可视化系统里面并不容易云做。这些东西最好用C++来实现,因为它们容易看出来到底在做什么。

参考

  1. https://docs.unrealengine.com/latest/CHN/Gameplay/ClassCreation/CodeAndBlueprints/index.html
  2. https://docs.unrealengine.com/latest/CHN/Programming/UnrealArchitecture/Reference/Classes/Specifiers/index.html
  3. https://docs.unrealengine.com/latest/INT/Engine/Blueprints/TechnicalGuide/Guidelines/index.html
时间: 2024-12-18 16:23:18

虚幻4蓝图快速入门(四)的相关文章

虚幻4蓝图快速入门(一)

蓝图快速入门 序言 本文依据官方教程总结而来,只是带你对蓝图有一个快速的认识,如果想对蓝图有一个比较深入的了解,那么可以看官方的视频或者是做一些小项目练手,如果你有编程经验的话,上手还是很容易的. 蓝图快速入门 什么是蓝图 虚幻引擎中的蓝图可视化系统是一个完整的游戏脚本系统,其理念是使用基于节点的界面从虚幻编辑器中创建游戏可玩性元素,该系统非常灵活且非常强大,因为它为设计人员提供了一般仅供程序员使用的所有概念及工具.它是一种特殊类型的资源,为关卡设计师和游戏开发人员提供了一种在编辑器中快速创建及

虚幻4蓝图快速入门(三)

数学表达式节点 概述 要想创建一个数学表达式节点,请右击图表并从关联菜单中选择 Add Math Expression(添加数学表达式)... . 数学表达式节点就像一个合并的图表.它是一个独立的节点,您可以双击它来打开构成其功能的子图表. 最初,该名称/表达式是空的.任何时候,当您重命名该节点时,都将会解析新表达式并生成新的子图表. 变量 变量命名非常灵活,但是记住以下几点非常重要: 变量名称本身可以包含数字,但是不能以数字开头. 变量名称不能和隐藏的蓝图变量名称一样. 确保您正在使用正确的变

虚幻4蓝图快速入门(二)

蓝图用户指南 由于蓝图就是个可视化的脚本系统,那么一个程序语言中的基本概念也就都存在.下面我们简单来介绍下蓝图中的一些基本概念. 变量 概述 Variables(变量) 是存放一个值或引用世界中的一个Object或Actor的属性.这些用户界面 内部访问,或者通过设置使得可以在外部进行访问, 以便应用放置在关卡中的蓝图实例的设计人员可以修改它们的 值. 变量显示为圆角方框,方框内包含了变量的名称: 变量类型 您可以创建各种类型的变量,包括数据类型的变量(比如布尔型.整型及浮点型)及用于存放类似于

AndroidStudio快速入门四:打造你的开发工具,settings必备

http://blog.csdn.net/jf_1994/article/details/50085825 前言:这里是使用AS的基本设置,适合新入手的朋友阅读,将这里介绍的设置完基本使用无忧啦. 1.setting介绍 点击菜单栏:File | settings 快捷方式:ctrl+art+s 注意:我们可以在基本设置头部的搜索框直接输入你要设置的关键字直接进入 2.设置主题样式.字体大小 File | settings |Appearance&Behavior|Appearance 如上图中

MySQL快速入门(四)

1 事务处理  接下来我会带大家一起来熟悉mysql中的事务处理机制 1.1  事务概述 l 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务. l 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行. l 事务用来管理DDL.DML.DCL操作,比如 insert,update,delete 语句 一般来说,事务必须满足四个条件 1. Atomicity(原子性)                                

mybatis快速入门(四)

mybatis动态标签<where><if><foreach>以及sql片段 1.创建一个包装类UserQueryVo.java package cn.my.mybatis.entity; public class UserQueryVo { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } } 2.

程序员带你学习安卓开发,十天快速入门-基础知识(四)

关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到熟悉的效果. 本系列课程是.Net程序员学习安卓开发系列课程. 下面是前三次课程列表: 程序员带你学习安卓开发,十天快速入门-安卓学习必要性 程序员带你学习安卓开发,十天快速入门-开发工具配置学习 程序员带你学习安卓开发,十天快速入-对比C#学习java语法 为了大家系统有效的快速入门安卓开发,推荐

快速入门git第四步

一.获得git仓库有两个来源:1.在现有的目录下,通过git add 导入文件创建新的git仓库 2.从以后的git仓库下克隆下代码 1.在工作目录下新建git仓库,使项目进行了git的管理,只需要进行下列的命令: cd 文件名(进入目录)或者直接建立一个文件夹(mkdir zhen/cd zhen/) git init git init 做了写什么? 该命令的叫做初始化,初始化目录里面的文件和结构,在该目录下胡出现一个.git的文件,该文件含有git所需要的 资源和数据 2.克隆代码: git

C语言快速入门系列(四)

C语言快速入门系列(四) C语言数组 ---------转载请注明出处:coder-pig 贴心小提示:如果图看不清晰可右键另存为,应该就很清晰了; 注意上面的代码都要自己过一遍哦! 本节引言: 经过我们前面三个系列的学习,我们对C语言有了一定的了解; 现在要你写这样一个代码应该不难吧: 输入五个学生的成绩,然后求出总和与平均值,打印出结果! 相信大家都会先定义五个变量,用来存储五个学生的成绩,然后再进行计算吧! 但是,假如要求的学生不是5个而是20个,50个或者更多,难道你又定义一堆变量么?