为Web导出

HTML5导出允许将在Godot引擎中制作的游戏发布到浏览器。这需要在用户浏览器中支持 WebAssemblyWebGL

重要

使用浏览器集成的开发人员控制台,通常使用 F12 打开,来查看 调试信息,如Javascript、引擎和WebGL错误。

注意

许多浏览器,包括Firefox和基于Chromium的浏览器,在 本地打开 每个 file:// 协议时不,会加载导出的项目。要解决此问题,请使用本地服务器。

小技巧

Python提供了一个简单的方法来启动本地服务器。用Python 3使用 python -m http.server 8000 --bind 127.0.0.1 为当前工作目录 http://localhost:8000 服务。 其他信息请参考MDN

注意

在iOS上运行HTML5项目有严重的bug (与浏览器无关)。推荐使用 iOS' native export functionality,同时它也有更好的性能。

注解

If you use Linux, due to poor Firefox WebGL performance, it's recommended to play the exported project using a Chromium-based browser instead of Firefox.

WebGL 2

OpenGL ES 3 渲染器从 Godot 删除以支持 Vulkan 之前,当选择 GLES3 选项时,HTML5导出将使用 WebGL 2

警告

不推荐使用WebGL 2,因为它预计会从Godot中移除而不需要替换。

并非所有浏览器都支持WebGL 2。FirefoxChromium (Chrome、Opera)是支持WebGL 2的最受欢迎的浏览器,而 SafariEdge 不起作用。在 iOS 系统上,所有浏览器都基于WebKit(即Safari),因此它们也无法正常工作。

Godot 的 WebGL 2 渲染器存在 3D 问题,并且不再维护。

限制

出于安全和隐私的原因,许多在本机平台上轻松工作的功能在Web平台上更加复杂。以下列出了将Godot游戏移植到Web时应注意的限制。

使用cookie进行数据持久化

如果需要持久化 user:// 文件系统,用户必须 允许cookie (特别是IndexedDB)。当玩 iframe 中呈现的游戏时,还必须启用 第三方 cookie。隐身/隐私浏览模式也会防止持久性。

方法 OS.is_userfs_persistent() 可用于检查 user:// 文件系统是否持久,但在某些情况下会误报。

全屏和鼠标捕获

浏览器不允许任意 进入全屏捕获光标 也是如此。相反,这些操作必须作为对JavaScript输入事件的响应而发生。在Godot中,这意味着从按下的输入事件,例如 _input_unhandled_input,回调中进入全屏。查询 Input 单例是不够的,相关的输入事件当前必须是活动的。

出于同样的原因,除非从有效的输入事件处理程序中启动引擎,否则全屏项目设置将不起作用。这需要 定制HTML页面

音频自动播放

Chrome 限制网站播放音频的方式。可能需要玩家单击或轻按或按住一个键来启用音频。

参见

Google提供了有关其 网络音频自动播放政策 的其他信息。

HTTPClientHTTPRequest

HTTP类在HTML5平台上有一些限制:

  • 无法访问或更改 StreamPeer

  • Threaded/Blocking 模式不可用

  • 每帧不能进行多次,因此循环中的轮询将冻结

  • 没有分块响应

  • 无法禁用主机验证

  • 遵循 同源政策

导出的 .html 文件不得重复使用

每个项目必须生成自己的HTML文件。在导出时,在 生成的HTML文件 中,有几个文本占位符会被替换,专门用于给定的导出选项。任何对 生成的HTML文件 的直接修改将在以后的导出中丢失。要自定义生成的文件,请参见 导出自定义HTML页面

启动画面不显示

默认的HTML页面在加载时不显示启动界面。然而,图像导出为一个PNG文件,因此 自定义HTML页面 可以显示它。

着色器语言限制

当导出 GLES2 项目到 HTML5时, WebGL 1.0将被使用。 WebGL 1.0不支持动态循环,所以使用这些的着色器将不会工作。

未实现的功能

HTML5平台上目前无法使用以下功能:

小技巧

查看GitHub上的 `HTML5公开议题列表<https://github.com/godotengine/godot/issues?q=is:open+is:issue+label:platform:html5>`__ ,看看你关注的功能是否有议题。如果没有,请打开一个议题来表达你的兴趣。

提供文件

导出为Web生成多个要从Web服务器提供的文件,包括用于演示的默认HTML页面。可以使用自定义HTML文件,请参阅 导出自定义HTML页面

生成的 .html 文件可以在Apache服务器中用作 DirectoryIndex,并且可以在任何时候重命名为例如 index.html,默认情况下永远不会依赖它的名称。

HTML页面在浏览器窗口内以最大尺寸绘制游戏。这样,就可以将其插入游戏大小的 <iframe> 中,这在大多数网络游戏托管站点中很常见。

其他导出的文件在 .html 文件旁边,按原样提供,名称不变。.wasm 文件是实现引擎的二进制WebAssembly模块。.pck 文件是包含您的游戏的Godot主包。.js 文件包含启动代码, .html 文件使用它来访问引擎。.png 文件包含启动画面图像。默认HTML页面中未使用它,但 自定义HTML页面 中包含了它。

.pck 文件是二进制文件,通常与MIME类型 application/octet-stream 一起分发。.wasm 文件以 application/wasm 分发。

警告

分发WebAssembly模块(.wasm)时,使用一个 application/wasm 以外的MIME类型,可能会阻止某些启动优化。

建议使用服务器端压缩来分发文件,尤其是对通常很大的 .pck.wasm 文件。WebAssembly模块压缩特别好,通过gzip压缩缩小到原始大小的四分之一。

导出选项

如果可以使用可运行的Web导出模板,则编辑器中的 停止场景播放编辑的场景 按钮之间会出现一个按钮,可以在默认浏览器中快速打开游戏进行测试。

如果给出了 自定义HTML Shell 文件的路径,则将使用它来代替默认的HTML页面。请参阅 导出自定义HTML页面

Head Include 被附加到生成的HTML页面的 <head> 元素中。例如,这允许加载webfonts和第三方JavaScript APIs,包括CSS或运行JavaScript代码。

从脚本调用JavaScript

在Web构建中,实现了 JavaScript 单例。它提供一个名为 eval 的方法,其工作方式与同名的JavaScript函数类似。它将字符串作为参数,并将其作为JavaScript代码执行。这允许以与集成到Godot中的脚本语言不可能的方式与浏览器交互。

func my_func():
    JavaScript.eval("alert('Calling JavaScript per GDScript!');")

最后一个JavaScript语句的值转换为GDScript值,并在某些情况下由 eval() 返回:

  • JavaScript number 作为GDScript的 float 返回

  • JavaScript boolean 作为GDScript的 bool 返回

  • JavaScript string 作为GDScript的 String 返回

  • JavaScript RellBufferTypedArrayDataView 作为GDScript的 PoolByteArray 返回

func my_func2():
    var js_return = JavaScript.eval("var myNumber = 1; myNumber + 2;")
    print(js_return) # prints '3.0'

任何其他JavaScript值都返回为 null

HTML5导出模板可能会 built 不支持单例以提高安全性。对于这样的模板,在HTML5以外的平台上,调用 JavaScript.eval 也会返回 null 。 可以通过 JavaScript feature标签 来检查单例的可用性:

func my_func3():
    if OS.has_feature('JavaScript'):
        JavaScript.eval("""
            console.log('The JavaScript singleton is available')
        """)
    else:
        print("The JavaScript singleton is NOT available")

小技巧

GDScript中的多行字符串由3双引号 """ 包围,如同上文中的 my_func3() 那样,有助于保证JavaScript代码的可读性。

eval 方法也接受第二个可选的布尔参数,它指定是否在全局执行上下文中执行代码,默认为 false 以防止污染全局命名空间:

func my_func4():
    # execute in global execution context,
    # thus adding a new JavaScript global variable `SomeGlobal`
    JavaScript.eval("var SomeGlobal = {};", true)