前言

  并不是所有人都喜欢写代码的,有些时候可能蓝图操作起来更加简单。
  尽管蓝图无法进行 git 的合并还是很不方便的。

  通过 Unreal 封装蓝图可以反向让蓝图有了 Python 的功能。
  一些逻辑比较复杂的操作用蓝图链接会非常晦涩和复杂,可以将其封装成一个蓝图节点,方便不懂代码人进行使用。

  最初我是完全没有想到还有这种用法的,是偶然间一个师弟问我问题,提供了一个蓝图封装好的脚本。
  这才让我大开眼界,这篇文章才有机会面世~
  后来我问了师弟的写法是从哪里来,可以参考这篇文章 链接

  由于是 Python 进行封装的,所以这些蓝图节点不推荐在运行时的游戏逻辑上使用。
  推荐在 editor utility 相关的节点来使用。

蓝图库封装

  虚幻引擎本身可以通过创建蓝图库资源来扩展蓝图。

alt

  在这里面进行扩展的蓝图,也可以在别的蓝图调用到。
  但是本质上还是 蓝图 分装自己 而已。

  用 Python 封装不需要生成这个资源,只需要继承 unreal.BlueprintFunctionLibrary 文档链接

  废话不多说,直接上代码。

1
2
3
4
5
6
7
8
9
import unreal

# NOTE 生成一个 Unreal Class 对象
@unreal.uclass()
class PyBPFunctionLibrary(unreal.BlueprintFunctionLibrary):
# NOTE 蓝图库分类设置为 Python Blueprint
@unreal.ufunction(static=True,meta=dict(Category="Python Blueprint"))
def TestFunction():
unreal.SystemLibrary.print_string(None,'Python Test Function Run',text_color=[255,255,255,255])

  打开一个蓝图,右键输入 Test 就可以找到上面 Python 生成的蓝图了。

alt
alt

  点击按钮触发的蓝图就是 执行上面封装的 Python 代码
  通过这个方法可以利用 Python 的 API 实现蓝图不好做甚至是不能做的操作。

  比如可以通过 Python 的 json 库输出 json 数据,借助 socket 库进行远程通信,也可以借助一些第三方库实现更多骚操作。
  比如通过蓝图调用 Python 图像库处理图片。

  蓝图其实也可以通过 Execute Python Command 节点来执行 Python 字符串。
  但是用 Python 封装的 蓝图 节点还可以返回出内部的数据,一些复杂的运算可以用 Python 封装。
  因为蓝图每个运算符都是单独的节点,连接复杂的运算会变得很混乱,另外 for 循环也可以通过 Python 进行封装简化。
  当然这些操作其实都可以通过 BlueprintFunctionLibrary 资源 连接蓝图 来实现。

  蓝图最弱的地方是读取外部的文件数据,通过 Python 可以完全弥补这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
import unreal
# NOTE 生成一个 Unreal Class 对象
@unreal.uclass()
class PyBPFunctionLibrary(unreal.BlueprintFunctionLibrary):
# NOTE 蓝图库分类设置为 Python Blueprint
@unreal.ufunction(static=True,meta=dict(Category="Python Blueprint"))
def TestFunction():
unreal.SystemLibrary.print_string(None,'Python Test Function Run',text_color=[255,255,255,255])

@unreal.ufunction(params=[str],ret=str,static=True,meta=dict(Category="Python Blueprint"))
def TestReadFile(filepath):
if not os.path.exists(filepath):
return ''
with open(filepath,'r') as f:
data = f.read()
return data

alt

  我在 C 盘建了 txt ,写入了 read from text file 的数据
  通过 Python 封装就可以读取到里面的数据了,省得用 C++ 去写。


  ufunction 的参数可以参考文档, 链接
  不过文档也是简单得等同于没有说。
  其中比较值得让人注意的地方是,如果参数使用 数组 需要用 unreal.Array 来封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import os
import unreal
# NOTE 生成一个 Unreal Class 对象
@unreal.uclass()
class PyBPFunctionLibrary(unreal.BlueprintFunctionLibrary):
# NOTE 蓝图库分类设置为 Python Blueprint
@unreal.ufunction(static=True,meta=dict(Category="Python Blueprint"))
def TestFunction():
unreal.SystemLibrary.print_string(None,'Python Test Function Run',text_color=[255,255,255,255])

@unreal.ufunction(params=[str],ret=str,static=True,meta=dict(Category="Python Blueprint"))
def TestReadFile(filepath):
if not os.path.exists(filepath):
return ''
with open(filepath,'r') as f:
data = f.read()
return data

@unreal.ufunction(params=[unreal.Array(str)],ret=str,static=True,meta=dict(Category="Python Blueprint"))
def TestReadArrayFile(file_list):
data = ""
for filepath in file_list:
if not os.path.exists(filepath):
continue
with open(filepath,'r') as f:
data += f.read()
return data

alt

注意事项

  如果对已经使用的节点进行修改需要谨慎,目前 python 还不是很稳定,可能会导致很多报错。
  另外 Python 的蓝图封装是动态生成的,重开引擎之后,相关的节点需要重新执行一遍 Python 脚本来生成。
  否则蓝图就是红色显示,不起作用。

  Python 封装的节点如果使用 Python 的库就无法在运行时使用了,编译就会提示报错。

alt

  不过如果是使用 unreal 模块的封装还是可以运行部分的,就是限制太大了,而且这样和纯蓝图没有什么区别。

1
2
3
4
5
6
7
import unreal
@unreal.uclass()
class PyRuntimeBPFunctionLibrary(unreal.BlueprintFunctionLibrary):
@unreal.ufunction(static=True,meta=dict(Category="Python Runtime"))
def TestRuntime():
frame = unreal.SystemLibrary.get_frame_count()
unreal.SystemLibrary.print_string(None,str(frame),text_color=[255,255,255,255])

总结

  以上就是 Python 反向封装蓝图的效果。
  我个人还是不太习惯用蓝图,可能主要还是对 虚幻 不太熟悉吧。
  而且 Python 的文档比较全面,参考 Python 文档补全了 蓝图 文档过于简略的问题。