资讯动态

Godot 演示项目:Runtime Save/Load —— 绕过资源导入系统的运行时文件加载与保存实战

发布时间:2026/10/3 13:35:35 来源:尧图企业网站定制
示例工程【免费下载链接】godot-demo-projectsDemonstration and Template Projects项目地址https://gitcode.com/GitHub_Trending/go/godot-demo-projects点击查看免费下载本指南围绕 godot-demo-projects 仓库中的 runtime_save_load 演示项目系统讲解如何在不经过 Godot 资源导入系统Import System的前提下于运行时直接加载与保存图片、音频、3D 场景glTF、ZIP 压缩包、字体与纯文本等各类文件。读完本文你将掌握Image、AudioStreamOggVorbis/MP3/WAV、GLTFDocument/FBXDocument、FontFile、ZIPReader/ZIPPacker与FileAccess等核心类的运行时读写用法并理解其与 PCK 打包、资源导入、游戏存档序列化之间的边界可直接应用到用户生成内容UGC、DLC 扩展包等真实场景。项目概览为什么需要绕过资源导入系统在 Godot 中常规的资源使用方式是把图片、音频、场景等资源导入Import进项目最终随导出打包进 PCK 文件。这种方式适合「开发者预先准备、内容固定」的资源。但当内容来自用户运行时产生如玩家上传的头像、自制的模型、自定义关卡包时不可能在每次导出前重新导入因此需要一套「运行时直接从磁盘读写文件」的方案。runtime_save_load 演示项目 正是展示这一能力的官方示例。它的核心主张体现在项目自述中本项目展示如何在不经过 Godot 资源导入系统的情况下加载和保存各种文件类型。这对于在运行时加载/保存图片、声音、3D 场景和 ZIP 压缩包等用户生成内容非常有用且无需用户通过 Godot 生成 PCK 文件。项目基于 GDScript 编写渲染后端为 CompatibilityOpenGL对应配置可在 project.godot 中看到renderer/rendering_methodgl_compatibility主场景为res://runtime_save_load.tscn并开启了run/low_processor_modetrue以降低闲置时的 CPU 占用。支持的文件类型清单能力文件类型可运行时加载并保存图片JPEG、PNG、WebP、3D 场景glTF 2.0、ZIP 压缩包、纯文本文件可运行时加载仅加载图片TGA、BMP、SVG、3D 场景FBX、音频Ogg Vorbis、MP3、WAV、字体TTF、OTF、WOFF、WOFF2、PFB、PFM、BMFont演示目录下 examples 为每种类型都准备了可直接试用的样例images/下同源的godot_icon共 6 种格式png、jpg、webp、tga、bmp、svgaudio/下的item_spawn有 ogg、mp3、wav 三种编码fonts/提供 TTF/OTF/WOFF2 三种字体3d_scenes/gltf/提供带纹理贴图的塑料椅 glTF 场景misc/下则是example.zip与file.txt。快速上手运行演示项目用 Godot 4.x 打开 loading/runtime_save_load/project.godot项目配置config/featuresPackedStringArray(4.7)需 Godot 4.7 或兼容版本。点击运行主场景 runtime_save_load.tscn 会加载一个文件浏览器 UI。在顶部的FilePath输入框中直接输入文件路径或点击Browse按钮通过文件对话框选择examples/目录中的任一文件。程序会根据文件扩展名自动识别类型并在下方的Result区域显示对应预览图片纹理、音频播放按钮、3D 场景视图、字体字形预览、ZIP 文件列表或纯文本内容。预览成功后点击Export按钮可将当前内容保存为指定格式的新文件。界面结构一个场景承载六种查看器runtime_save_load.tscn 将全部 UI 组织在一个Control根节点下并通过visible切换不同查看器其结构对理解脚本逻辑很有帮助输入区FilePathLineEdit、Browse按钮与FileDialogfile_mode0即打开文件模式。结果区Result/CenterContainerPlainTextViewer滚动容器 Label用于显示纯文本。TextureViewerTextureRect显示图片。AudioPlayer按钮内含AudioStreamPlayervolume_db-10.0与时长信息 Label。SceneViewerSubViewportContainer SubViewport开启 MSAA、scaling_3d_scale2.0 Camera3D 三盏方向光KeyLight/FillLight/BackLight Zoom 滑块HSlidermin_value-100.0、max_value-0.1。FontViewerLabel用预览字体渲染字母、数字与符号表。ZIPViewerHSplitContainer左侧FileListItemList列出压缩包内文件右侧FilePreviewLabel显示选中文件的 UTF-8 文本内容。ErrorLabel加载失败时的错误提示。导出区Export按钮与独立FileDialogaccess2即文件系统访问。场景中所有信号均在 tscn 末尾通过[connection]声明绑定例如text_submitted、file_selected、item_selected、value_changed分别对应脚本中的_on_file_path_text_submitted、_on_file_dialog_file_selected、_on_zip_viewer_item_selected、_on_scene_viewer_zoom_value_changed等回调。核心实现open_file 的分发逻辑整个加载流程集中在 runtime_save_load.gd 的open_file(path)方法中。它将路径转为小写后按扩展名依次匹配图片、音频、3D 场景、字体、ZIP最后以纯文本作为兜底func open_file(path: String) - void: var path_lower : path.to_lower() # 图片分支 if path_lower.ends_with(.jpg) or path_lower.ends_with(.jpeg) \ or path_lower.ends_with(.png) or path_lower.ends_with(.webp) \ or path_lower.ends_with(.svg) or path_lower.ends_with(.tga) \ or path_lower.ends_with(.bmp): # ... # 音频分支 elif path_lower.ends_with(.ogg) or path_lower.ends_with(.mp3) \ or path_lower.ends_with(.wav): # ... # 3D 场景分支 elif path_lower.ends_with(.gltf) or path_lower.ends_with(.glb) \ or path_lower.ends_with(.fbx): # ... # 字体分支 elif path_lower.ends_with(.ttf) or path_lower.ends_with(.otf) \ or path_lower.ends_with(.woff) or path_lower.ends_with(.woff2) \ or path_lower.ends_with(.pfb) or path_lower.ends_with(.pfm) \ or path_lower.ends_with(.fnt) or path_lower.ends_with(.font): # ... # ZIP 分支 elif path_lower.ends_with(.zip): # ... # 兜底按纯文本打开 else: var file_contents : FileAccess.get_file_as_string(path) # ...图片一行代码完成格式探测与加载图片分支是整个演示中代码最简洁的因为它直接调用Image.load_from_file(path)—— 该方法会根据文件扩展名自动探测格式并完成读取同时覆盖 JPEG/PNG/WebP/SVG/TGA/BMP 七种格式var image : Image.load_from_file(path) reset_visibility() export_file_dialog.filters [*.png ; PNG Image, *.jpg, *.jpeg ; JPEG Image, *.webp ; WebP Image] texture_viewer.visible true texture_viewer.texture ImageTexture.create_from_image(image)脚本注释明确指出如果需要错误处理或更细粒度的控制例如控制 SVG 的加载缩放比例应改用Image类的load_*_from_buffer()系列方法与load_svg_from_string()。音频按格式选择对应的 AudioStream 类音频分支依据扩展名分别使用三个静态工厂方法将文件直接构造成可播放的AudioStream资源if path_lower.ends_with(.ogg): audio_stream_player.stream AudioStreamOggVorbis.load_from_file(path) elif path_lower.ends_with(.mp3): audio_stream_player.stream AudioStreamMP3.load_from_file(path) elif path_lower.ends_with(.wav): audio_stream_player.stream AudioStreamWAV.load_from_file(path)加载成功后脚本会显示播放按钮并计算音频时长roundi(stream.get_length())后格式化为MM:SS。需要注意如果数据已在内存中PackedByteArray可改用AudioStreamOggVorbis.load_from_buffer()这类缓冲区方法。3D 场景GLTFDocument 与 FBXDocument 的运行时装配glTF 分支使用GLTFDocumentGLTFState完成「文件 → 节点树」的转换前者负责加载数据后者保存加载状态。成功加载后调用generate_scene(gltf_state)生成根节点并挂到 SubViewport 下的场景查看器中var gltf_document : GLTFDocument.new() var gltf_state : GLTFState.new() var error : gltf_document.append_from_file(path, gltf_state) if error OK: scene_viewer_root_node gltf_document.generate_scene(gltf_state) reset_visibility() scene_viewer.add_child(scene_viewer_root_node) export_file_dialog.filters [*.gltf ; glTF Text Scene, *.glb ; glTF Binary Scene] scene_viewer.visible true else: show_error(Couldn\t load %s as a glTF scene (error code: %s). % [path.get_file(), error_string(error)])FBX 分支的结构与之完全对称只是换用FBXDocument与FBXState。场景查看器中的Zoom滑块通过_on_scene_viewer_zoom_value_changed控制正交相机projection1的size滑块取值范围为负值-100.0 ~ -0.1scene_viewer_camera.size abs(value)数值越小绝对值越大表示放大倍率越高。字体动态字体与位图字体的区分加载字体分支创建FontFile根据扩展名区分两类加载方式.fnt/.fontBMFont 位图字体走load_bitmap_font()其余 TTF/OTF/WOFF/WOFF2/PFB/PFM 走load_dynamic_font()var font_file : FontFile.new() if path_lower.ends_with(.fnt) or path_lower.ends_with(.font): font_file.load_bitmap_font(path) else: font_file.load_dynamic_font(path) if not font_file.data.is_empty(): font_viewer.add_theme_font_override(font, font_file) reset_visibility() font_viewer.visible true export_button.disabled true成功加载后通过add_theme_font_override把字体应用到一个 48 号字号的 Label 上直接预览字形。脚本用font_file.data.is_empty()判断加载是否成功失败则进入show_error流程。ZIP 压缩包ZIPReader 的只读浏览ZIP 分支创建ZIPReader打开压缩包后列出内部全部文件并禁用列表中以/结尾的目录项zip_reader.open(path) var files : zip_reader.get_files() files.sort() export_file_dialog.filters [*.zip ; ZIP Archive] reset_visibility() for file in files: zip_viewer_file_list.add_item(file, null) zip_viewer_file_list.set_item_disabled(-1, file.ends_with(/)) zip_viewer.visible true当用户选中列表项时_on_zip_viewer_item_selected用zip_reader.read_file(文件名)取出原始字节再get_string_from_utf8()转为文本预览。值得一提的扩展场景Godot 的「Export PCK/ZIP」功能生成的 ZIP 文件同样可以被读取其中包含的是导入后的 Godot 资源而非原始工程文件而若要作为 DLC 追加数据包无缝集成到虚拟文件系统演示注释推荐改用ProjectSettings.load_resource_pack()。运行时保存Export 按钮背后的写入逻辑_on_export_file_dialog_file_selected(path)根据当前可见的查看器类型决定写入方式纯文本用FileAccess.open(path, FileAccess.WRITE)store_string()写回最后close()。图片从texture_viewer.texture.get_image()取回Image再按目标扩展名调用save_png()、save_jpg()质量常量为JPG_QUALITY 0.9或save_webp()。注释特别说明 WebP 默认无损保存需要有损时可通过Image.save_webp()的可选参数调整。3D 场景用GLTFDocument.append_from_scene(scene_viewer_root_node, gltf_state)把预览中的节点树转回 glTF 状态再write_to_filesystem(gltf_state, path)落盘。输出是文本.gltf还是二进制.glb由目标路径扩展名决定二进制写盘更快、体积更小、更适合内嵌纹理但文本格式更易于调试。ZIP创建ZIPPackeropen(path)后遍历zip_reader.get_files()对每个文件依次start_file()→write_file()→close_file()最后close()。若打开失败会push_error并中止。两处「无法导出」的限制也在代码中明确标注音频中的 Ogg Vorbis 与 MP3 无法在运行时导出为标准格式只有 WAV 源可通过AudioStreamWAV.save_to_wav()保存为 WAV字体同样只能通过ResourceSaver保存为 Godot 专属的.res格式。因此这两个分支下export_button.disabled true。边界与注意事项原文档的脚注部分给出了三条关键边界项目中均有对应实现佐证自定义二进制格式操作自定义二进制格式可以通过FileAccess与PackedByteArray类实现但演示未展示。这意味着文本/压缩包之外的结构化数据读写需要自行封装字节流逻辑。SVG 程序化生成可以先用文本方式程序化生成 SVG 内容再用FileAccess写入带.svg扩展名的文件。仓库中 examples/images/godot_icon.svg 正是可被Image.load_from_file()直接加载的 SVG 样例。FBX 运行时加载的已知问题文档明确提到 Godot 的 issue #96043即运行时 FBX 加载存在已知缺陷。FBX 分支在append_from_file返回非OK时同样会通过show_error展示error_string(error)错误码实际项目中建议优先使用 glTF 作为跨引擎交换格式。与 Serialization 演示的互补关系本演示关注「文件级 I/O」而仓库中的 loading/serialization 演示Saving and Loading / Serialization关注「游戏进度级 I/O」展示如何使用ConfigFile与JSON保存游戏状态。原文档明确给出分工建议前者解决「导出的游戏如何在运行时读取未导入的文件」后者解决「游戏进度如何持久化」两者配合即可覆盖从存档数据到 UGC 资源的完整读写需求。示例资产与许可examples/3d_scenes/gltf/ 下的plastic_monobloc_chair_01_1k.gltf及配套纹理diff/nor/arm 三张 JPG 与一个.bin缓冲文件来自 Poly Haven采用 CC0 1.0 通用许可examples/audio/ 下的音频文件来自 Red Eclipse 项目采用 CC BY-SA 4.0 国际许可examples/fonts/ 内的 Inter 字体遵循 SIL Open Font License 1.1。在自有项目中使用或二次分发这些示例资产时需保留对应的许可声明。赞分享示例工程【免费下载链接】godot-demo-projectsDemonstration and Template Projects项目地址https://gitcode.com/GitHub_Trending/go/godot-demo-projects点击查看免费下载相关推荐Godot 音频输出设备运行时切换实战Audio Device Changer 演示项目源码解析godot-demo-projectsGodot 音频输出设备运行时切换实战Audio Device Changer 演示项目源码解析godot demo projects 本文基于 godo示例工程komorebi 快速保存与加载窗口 Resize 布局尺寸quick-save-resize 与 quick-load-resize 实战指南komorebi 快速保存与加载窗口 Resize 布局尺寸quick save resize 与 quick load resize 实战指南 导读 qui桌面应用CANN Runtime 运行时配置接口实战系统参数与 Device/Stream 资源限制管理CANN Runtime 运行时配置接口实战系统参数与 Device/Stream 资源限制管理 本篇技术指南聚焦 CANN Runtime 的运行时配置接口CANNAscend人工智能性能剖析系统编程上一篇金融数据输入输出Python处理CSV、Excel和数据库的完整教程下一篇如何为深蓝词库转换添加新的输入法格式Source Generator 自动注册的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑