IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 【游戏开发】踩坑UE4的Python脚本插件 -> 正文阅读

[游戏开发]【游戏开发】踩坑UE4的Python脚本插件

UE4以C++为基础,在游戏开发需求当中,官方推崇的是Blueprint可视化编程,而除此之外像UnLua、puerts等解决方案也提供了lua、ts等其它脚本语言的支持。至于python,UE4本身就有插件支持,叫做PythonScriptPlugin,启用插件后,在编辑器里,可以输入python代码执行一系列命令。在最新的4.27版本中,python的版本是3.7.7。

回到正题,之所以这篇文章标题叫踩坑,是因为真的踩坑了——尝试用PythonScriptPlugin来编写UE4的游戏逻辑,最终放弃。PythonScriptPlugin适合做一些驱动编辑器的操作,或者是做一些静态资源检查相关的工作(其实这个插件真名就叫Python Editor Script Plugin),如果用它来写游戏逻辑的话,很多必须的内容都难以支持。但不管怎么说,既然踩坑了还是要分享点东西出来,因此这篇文章先粗浅谈一下PythonScriptPlugin的工作流。

PythonScriptPlugin的使用方法,基本可以参考官方文档:Scripting the Editor using Python

一些必须的步骤有:

  • 插件中,启用Python Editor Script Plugin
  • 项目设置的Python插件设置里面,sys.path增加自己脚本的目录
  • 项目设置的Python插件设置里面,启用开发者模式,重启后在Intermediate/PythonStubs能够看到导出的unreal.py
    • unreal.py放到自己脚本目录下,其它.py脚本就可以通过import unreal来调用UE相关的库了
    • unreal.py内容非常大,ide需要配置intellisense相关设置

如果要在游戏逻辑里执行python命令,尤其是在C++里的话(蓝图已经有支持了),需要在Build.csPublicDependencyModuleNames加上PythonScriptPlugin

在C++执行python代码的话,可以这样子做:

// 这里笔者单独写了个GameInstanceSubsystem封装了相关方法

#include "IPythonScriptPlugin.h"


bool UPyEnvGameInstanceSubsystem::ExecPyCmd(const FString& Cmd)
{
    IPythonScriptPlugin* ScriptPlugin = GetScriptPlugin();
    if (!_IsScriptPluginAvailable(ScriptPlugin))
    {
        return false;
    }
    return ScriptPlugin->ExecPythonCommand(*Cmd);
}

IPythonScriptPlugin* UPyEnvGameInstanceSubsystem::GetScriptPlugin()
{
    return IPythonScriptPlugin::Get();
}

bool UPyEnvGameInstanceSubsystem::_IsScriptPluginAvailable(IPythonScriptPlugin* ScriptPlugin)
{
    return ScriptPlugin != nullptr && ScriptPlugin->IsPythonAvailable();
}

简单的代码执行可以通过IPythonScriptPluginExecPyCmd实现。如果说要获取执行结果,可以调用IPythonScriptPluginExecPythonCommandEx方法:

// Engine\Plugins\Experimental\PythonScriptPlugin\Source\PythonScriptPlugin\Private\PythonScriptPlugin.cpp

bool FPythonScriptPlugin::ExecPythonCommandEx(FPythonCommandEx& InOutPythonCommand)
{
#if WITH_PYTHON
    if (!IsPythonAvailable())
#endif
    {
        InOutPythonCommand.CommandResult = TEXT("Python is not available!");
        ensureAlwaysMsgf(false, TEXT("%s"), *InOutPythonCommand.CommandResult);
        return false;
    }

#if WITH_PYTHON
    if (InOutPythonCommand.ExecutionMode == EPythonCommandExecutionMode::ExecuteFile)
    {
        // We may have been passed literal code or a file
        // To work out which, extract the first token and see if it's a .py file
        // If it is, treat the remaining text as arguments to the file
        // Otherwise, treat it as literal code
        FString ExtractedFilename;
        {
            const TCHAR* Tmp = *InOutPythonCommand.Command;
            ExtractedFilename = FParse::Token(Tmp, false);
        }
        if (FPaths::GetExtension(ExtractedFilename) == TEXT("py"))
        {
            return RunFile(*ExtractedFilename, *InOutPythonCommand.Command, InOutPythonCommand);
        }
        else
        {
            return RunString(InOutPythonCommand);
        }
    }
    else
    {
        return RunString(InOutPythonCommand);
    }
#endif // WITH_PYTHON
}

bool FPythonScriptPlugin::RunString(FPythonCommandEx& InOutPythonCommand)
{
    // Execute Python code within this block
    {
        FPyScopedGIL GIL;
        TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, GIsRunningUnattendedScript || EnumHasAnyFlags(InOutPythonCommand.Flags, EPythonCommandFlags::Unattended));

        int PyExecMode = 0;
        switch (InOutPythonCommand.ExecutionMode)
        {
        case EPythonCommandExecutionMode::ExecuteFile:
            PyExecMode = Py_file_input;
            break;
        case EPythonCommandExecutionMode::ExecuteStatement:
            PyExecMode = Py_single_input;
            break;
        case EPythonCommandExecutionMode::EvaluateStatement:
            PyExecMode = Py_eval_input;
            break;
        default:
            checkf(false, TEXT("Invalid EPythonCommandExecutionMode!"));
            break;
        }

        FDelegateHandle LogCaptureHandle = PyCore::GetPythonLogCapture().AddLambda([&InOutPythonCommand](EPythonLogOutputType InLogType, const TCHAR* InLogString) { InOutPythonCommand.LogOutput.Add(FPythonLogOutputEntry{ InLogType, InLogString }); });
        FPyObjectPtr PyResult = FPyObjectPtr::StealReference(EvalString(*InOutPythonCommand.Command, TEXT("<string>"), PyExecMode));
        PyCore::GetPythonLogCapture().Remove(LogCaptureHandle);
        
        if (PyResult)
        {
            InOutPythonCommand.CommandResult = PyUtil::PyObjectToUEStringRepr(PyResult);
        }
        else if (PyUtil::LogPythonError(&InOutPythonCommand.CommandResult))
        {
            return false;
        }
    }

    FPyWrapperTypeReinstancer::Get().ProcessPending();
    return true;
}

执行时候传入FPythonCommandEx结构体,其CommandResult属性会存储执行的结果。如果要传入结果的话,得选择EPythonCommandExecutionMode::EvaluateStatement执行模式。而最终传入的结果,是python数据的repr,并非兼容成UE4的数据结构。

总结起来可以看到,直接用PythonScriptPlugin写游戏是不大现实,有几个点还要解决:

  • python与C++之间的相互通信,数据结构兼容。只有string repr是肯定不行的= =
  • 游戏最终呈现的性能
  • 多平台发布
  • 开发效率(至少自己16G烂本本干不动,还不如纯C++)
  • etc

不过原生作为面向UE4编辑器工作的脚本插件,PythonScriptPlugin应当有其用武之地。后面有空再慢慢探索。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:40:53  更:2021-11-22 12:41:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 23:42:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码