我想让 Godot 在我的 Mac 上像在 Linux 的 CI 里那样,从脚本写出截图和短视频。macOS 26.5.2 上的 Godot 4.7.1 在 --headless 下做不到,但用真正的渲染器、把窗口放到屏幕外就可以。还有一件事我没解决:它运行时,应用仍然会跑到最前面。

下面的一切都在一个 640 × 360、只有一个脚本的测试项目上运行:
extends Node2D
# Saves the 30th frame to the path given after "--" and quits.
var frames := 0
func _process(_delta: float) -> void:
$Box.position.x = 80.0 + frames * 4.0
frames += 1
var args := OS.get_cmdline_user_args()
if frames == 30 and args.size() > 0:
await RenderingServer.frame_post_draw
get_viewport().get_texture().get_image().save_png(args[0])
get_tree().quit()--headless 截图时会怎样
Godot.app/Contents/MacOS/Godot --headless --path . -- "$PWD/out.png"脚本运行到第 30 帧,然后就一直停在 await RenderingServer.frame_post_draw:15 秒后进程还在运行,什么也没保存。去掉 await 直接读纹理,会立刻失败:
ERROR: Parameter "t" is null.
at: texture_2d_get (./servers/rendering/dummy/storage/texture_storage.h:110)在 --headless 下,Godot 用的是一个空壳渲染器,所以视口没有可读的纹理;报错里的路径就是这个空壳渲染器的纹理存储。在 Linux 上,常见的绕法是在真正的渲染器下面放一个虚拟 X 显示。Godot 的 macOS 版本通过 macOS 的窗口服务器和 Metal 绘制,所以这个办法在 Mac 上用不了。
真正渲染,放在屏幕外
保留真正的渲染器,把窗口挪开。窗口设置在窗口创建时生效,早于任何脚本运行,所以在运行期间把它们写进 project.godot 旁边的 override.cfg:
[display]
window/size/no_focus=true
window/size/initial_position_type=0
window/size/initial_position=Vector2i(-6000, -6000)
window/size/always_on_top=false然后通过 open 启动应用:
open -n -W -g -j -a Godot.app --stdout run.log --stderr run.log \
--args --path "$PWD" -- "$PWD/out.png"
rm override.cfg-n 即使 Godot 已经打开也会启动一个新实例,-W 等它退出,-g 让它留在后台,-j 隐藏启动,--stdout 和 --stderr 把它的输出写回文件。没有它们,open 会丢掉输出,因为 Godot 不是你的 shell 的子进程。截到的帧是 640 × 360,颜色就是场景本身的颜色:RGB 平均值为 188, 117, 82,橙色背景上一个蓝色方块。
运行结束后删掉 override.cfg。Godot 每次启动都会读取它,所以在 rm 之前被中断的运行,会让下一次正常启动的窗口一直拿不到键盘焦点。
Movie Maker:先出 PNG 序列,再转 MP4
Movie Maker 以固定的速率渲染每一帧,所以视频的时间不取决于机器渲染得多快:
open -n -W -g -j -a Godot.app --stdout run.log --stderr run.log \
--args --path "$PWD" --write-movie "$PWD/movie/f.png" --fixed-fps 24 --quit-after 4848 frames at 24 FPS (movie length: 00:00:02:00), recorded in 00:00:01 (200% of real-time speed).它写出了 f00000000.png 到 f00000047.png,音频则以 f.wav 放在旁边。ffmpeg 把这些帧合成视频:
ffmpeg -framerate 24 -i movie/f%08d.png -c:v libx264 -pix_fmt yuv420p -crf 18 film.mp4结果是 48 帧、24 fps、长 2.0 秒。
没解决的:焦点
no_focus 能让窗口不抢键盘焦点,但 Godot 打开窗口时仍会把自己变成当前应用。我在两次运行期间反复查询最前面的应用。单帧那次运行中,21 次采样里有 1 次 Godot 在最前面;用了大约一秒的 Movie Maker 运行中,连续 4 次采样都是它;每次 Godot 退出后,我正在用的应用都会回到最前面。9月时,把 LSUIElement 设为 true 的应用包副本也没有用。录制更长时间时 Godot 会在最前面待多久,我没有测。
局限
- macOS 26.5.2 上的 Godot 4.7.1,一台 Mac,Forward+ 渲染器。我没试 Compatibility 渲染器。
- 屏幕外的位置只在一台显示器上试过。