Godot 4 GDScript 教程 / 28 - 导出与发布
28 - 导出与发布
开发完成后,需要将游戏导出为各平台的可执行文件并发布。本文覆盖 Godot 4 的导出配置、平台发布流程和 CI/CD 自动构建。
导出模板管理
导出模板是各平台的 Godot 运行时二进制文件,导出时需要使用。
| 模板类型 | 说明 |
|---|
| Debug | 调试版,包含调试符号和控制台输出 |
| Release | 发布版,优化过,体积更小 |
| Export Template | 官方提供的各平台模板 |
# 下载导出模板(通过编辑器)
# 编辑器 → 编辑器设置 → 导出 → 模板管理器 → 下载
# 或手动下载安装
# https://godotengine.org/download
# 模板安装路径: ~/.local/share/godot/export_templates/4.2.stable/
导出预设配置
# export_presets.cfg 说明
# 通过编辑器 GUI 配置更方便
# 编辑器 → 项目 → 导出 → 添加预设
PC 平台导出
Windows
| 配置项 | 推荐值 | 说明 |
|---|
custom_template/debug | 自定义模板路径 | 可选 |
custom_template/release | 自定义模板路径 | 可选 |
binary_format/64_bits | true | 64 位可执行文件 |
texture_format/s3tc_bptc | true | DXT 纹理压缩 |
application/icon | .ico 文件路径 | 应用图标 |
application/console_wrapper_enabled | false (发布版) | 隐藏控制台 |
codesign/enable | true (如有证书) | 代码签名 |
codesign/identity | 签名证书名称 | 企业签名 |
Linux
| 配置项 | 推荐值 | 说明 |
|---|
texture_format/etc2_astc | true | ETC2 纹理压缩 |
binary_format/embed_pck | true | PCK 嵌入可执行文件 |
ssh_remote_deploy/enabled | false | 远程部署(调试用) |
macOS
| 配置项 | 推荐值 | 说明 |
|---|
application/icon | .icns 文件路径 | 应用图标 |
codesign/enable | true | 必须签名 |
codesign/identity | 开发者证书 | Apple 开发者证书 |
notarization/enable | true | Apple 公证(macOS 10.15+) |
texture_format/s3tc_bptc | true | DXT 纹理压缩 |
导出命令行
# 使用命令行导出(适合 CI/CD)
# 需要先在编辑器中配置好导出预设
# 导出 Windows 版本
godot --headless --export-release "Windows Desktop" build/windows/my_game.exe
# 导出 Linux 版本
godot --headless --export-release "Linux/X11" build/linux/my_game.x86_64
# 导出 macOS 版本
godot --headless --export-release "macOS" build/mac/my_game.zip
移动端导出
Android
# 前置条件:
# 1. 安装 Android SDK
# 2. 安装 JDK 17
# 3. 在 Godot 中配置 Android SDK 路径
# 编辑器 → 编辑器设置 → 导出 → Android
# 关键配置:
# gradle_build/export_format = 1 (AAB for Play Store)
# gradle_build/min_sdk = "24"
# gradle_build/target_sdk = "34"
# package/unique_name = "com.yourcompany.yourgame"
# package/name = "Your Game Name"
# package/version = "1.0.0"
# package/version_code = 1
# launcher_icons/xxxhdpi_192x192 = "res://icons/icon_192.png"
| 导出格式 | 用途 |
|---|
| APK | 直接安装、第三方市场 |
| AAB | Google Play Store(推荐) |
iOS
| 配置项 | 说明 |
|---|
application/app_store_team_id | Apple 开发者团队 ID |
application/bundle_identifier | 应用 Bundle ID |
codesign/certificate_file | P12 证书 |
codesign/provisioning_profile | 描述文件 |
xcode/platform_build | Xcode 版本 |
⚠️ 注意:iOS 导出必须在 macOS 上进行,且需要 Apple 开发者账号($99/年)。
Web 导出(HTML5)
# web_export_settings.gd
# 项目设置推荐配置:
#
# html/export/icon_144x144 = "res://icons/icon_144.png"
# html/export/icon_180x180 = "res://icons/icon_180.png"
# html/export/icon_512x512 = "res://icons/icon_512.png"
# html/custom_html/release = "res://web/index.html"
# html/head_include = "<meta name='viewport' content='width=device-width'>"
# vram_texture_compression/for_desktop = true
# vram_texture_compression/for_mobile = true
自定义 HTML 模板
<!-- web/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的游戏</title>
<style>
body { margin: 0; background: #000; overflow: hidden; }
canvas { display: block; width: 100vw; height: 100vh; }
#loading {
position: absolute; top: 50%; left: 50%;
transform: translate(-50%, -50%);
color: white; font-family: sans-serif;
}
</style>
</head>
<body>
<div id="loading">加载中...</div>
<canvas id="canvas"></canvas>
<script src="$GODOT_URL"></script>
<script>
var engine = new Engine($GODOT_CONFIG);
engine.startGame().then(() => {
document.getElementById('loading').remove();
});
</script>
</body>
</html>
PCK 文件
PCK(Pack)是 Godot 的资源打包格式,所有导出的游戏数据都打包在 PCK 文件中。
# PCK 文件包含:
# - 所有项目资源(纹理、音频、场景等)
# - GDScript 编译后的字节码
# - 项目设置
# - 导入的资源(转换后的格式)
# 手动创建 PCK
godot --headless --export-pack "Windows Desktop" build/game.pck
# PCK 可以嵌入可执行文件,也可以独立分发
# 独立 PCK 可用于 MOD 系统或热更新
从 PCK 加载资源
# 在运行时加载额外的 PCK 文件(DLC/Mod)
func load_dlc(pck_path: String) -> bool:
var success = ProjectSettings.load_resource_pack(pck_path)
if success:
print("DLC 加载成功: ", pck_path)
# 现在可以访问 DLC 中的资源
var dlc_scene = load("res://dlc/new_level.tscn")
return success
加密签名
# 加密导出配置
# 在导出预设中配置:
#
# encryption/encrypt_source = true
# encryption/include_filters = "*.gd,*.tres,*.tscn"
# encryption/exclude_filters = "*.png,*.jpg,*.wav"
# encryption/key = "your_256_bit_encryption_key_here_32b"
# 生成加密密钥
# godot --headless --generate-encryption-key my_key.key
# 导出时加密
# 1. 将密钥文件放在项目根目录
# 2. 在导出预设中配置加密选项
# 3. 正常导出,GDScript 和敏感资源会被加密
⚠️ 注意:加密可以防止普通用户查看源码,但不能防止专业破解。核心验证逻辑应该在服务端。
自动更新
# auto_updater.gd
extends Node
signal update_available(version: String, size: int)
signal update_progress(progress: float)
signal update_completed()
var current_version: String = "1.0.0"
var update_server: String = "https://updates.example.com"
func check_for_update():
var http = HTTPRequest.new()
add_child(http)
http.request_completed.connect(_on_check_completed)
http.request(update_server + "/check?version=" + current_version)
func _on_check_completed(result, code, _headers, body):
if code != 200:
return
var json = JSON.new()
json.parse(body.get_string_from_utf8())
var data = json.data
if data.has("new_version"):
update_available.emit(data.new_version, data.get("size", 0))
if data.get("auto_download", false):
download_update(data.download_url)
func download_update(url: String):
var http = HTTPRequest.new()
add_child(http)
http.download_file = "user://update.pck"
http.request_completed.connect(_on_download_completed)
# 监听下载进度
http.set_use_threads(true)
http.request(url)
func _on_download_completed(result, code, _headers, _body):
if code == 200:
# 验证更新文件
if _verify_update("user://update.pck"):
# 应用更新
ProjectSettings.load_resource_pack("user://update.pck")
update_completed.emit()
# 提示重启
get_tree().quit()
func _verify_update(path: String) -> bool:
# 验证签名或哈希
return true
Steam / itch.io 发布
Steam 发布
# Steam 发布流程:
# 1. 注册 Steamworks 开发者账号 ($100)
# 2. 创建 Steam App
# 3. 配置 steam_appid.txt (包含你的 App ID)
# 4. 使用 SteamCMD 上传构建
# steam_appid.txt
# 你的AppID
# 使用 GodotSteam 插件
# https://godotsteam.com/
# 上传构建脚本 (app_build.vdf)
# "AppBuild"
# {
# "AppID" "你的AppID"
# "Desc" "v1.0.0"
# "ContentRoot" "./build/"
# "BuildOutput" "./output/"
# "SetLive" ""
# "Depots"
# {
# "你的DepotID"
# {
# "FileMapping"
# {
# "LocalPath" "./build/*"
# "DepotPath" "."
# "Recursive" "1"
# }
# }
# }
# }
# 上传命令
# steamcmd +login your_username +run_app_build app_build.vdf +quit
itch.io 发布
# itch.io 发布流程:
# 1. 注册 itch.io 账号
# 2. 创建项目页面
# 3. 使用 butler 上传构建
# 安装 butler
# https://itch.io/docs/butler/
# 上传构建
butler push build/windows myuser/mygame:windows --userversion 1.0.0
butler push build/linux myuser/mygame:linux --userversion 1.0.0
butler push build/mac myuser/mygame:mac --userversion 1.0.0
butler push build/web myuser/mygame:web --userversion 1.0.0
CI/CD 自动构建
GitHub Actions 示例
# .github/workflows/build.yml
name: Build and Release
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [windows, linux, macos, web]
steps:
- uses: actions/checkout@v4
- name: Setup Godot
uses: chickensoft-games/setup-godot@v1
with:
version: 4.2.1
export-templates: true
- name: Build
run: |
mkdir -p build/${{ matrix.platform }}
godot --headless --export-release "${{ matrix.platform }}" build/${{ matrix.platform }}/game
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}
path: build/${{ matrix.platform }}
release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
windows/*
linux/*
macos/*
web/*
generate_release_notes: true
发布检查清单
发布前检查项
| 检查项 | 说明 | 状态 |
|---|
| 功能测试 | 所有核心功能正常 | ☐ |
| 性能测试 | 目标平台帧率达标 | ☐ |
| 内存测试 | 无内存泄漏 | ☐ |
| 存档测试 | 存档/读档正常 | ☐ |
| 崩溃测试 | 极端情况不崩溃 | ☐ |
| UI 适配 | 不同分辨率正常显示 | ☐ |
| 音效检查 | 音量平衡,无爆音 | ☐ |
| 本地化 | 所有文本已翻译 | ☐ |
| 版权检查 | 所有素材有合法授权 | ☐ |
| 隐私政策 | 收集用户数据需声明 | ☐ |
| 版本号 | 版本号正确更新 | ☐ |
| 图标 | 各平台图标已配置 | ☐ |
| 加密密钥 | 生产环境密钥已更换 | ☐ |
| 测试账号 | 移除所有测试账号 | ☐ |
| 日志清理 | 移除调试日志输出 | ☐ |
# release_checklist.gd
# 在 CI 中自动检查部分项目
static func validate_export(export_path: String) -> Array[String]:
var issues: Array[String] = []
# 检查导出文件是否存在
if not FileAccess.file_exists(export_path):
issues.append("导出文件不存在: " + export_path)
return issues
# 检查文件大小(过小可能导出失败)
var file = FileAccess.open(export_path, FileAccess.READ)
if file and file.get_length() < 1024:
issues.append("导出文件过小,可能导出失败")
# 检查是否包含调试代码
# ... 更多检查
return issues
💡 扩展阅读