name: 3d-game-dev slug: 3d-game-dev version: 1.0.0 displayName: 3D 遊戲開發(Godot 4) summary: 用 Godot 4 從零到可玩的 3D 遊戲完整工作流:第一/第三人稱控制器、glTF 資產管線、關卡拼搭、燈光氛圍、導航 AI、效能與匯出。 description: >- 用 Godot 4 + GDScript 開發 3D 遊戲的端到端工作流。觸發場景:"做一個 3D 遊戲"、 "第一人稱/第三人稱/FPS/TPS/3D 平臺跳躍"、"用 Godot 做 3D"、"加個 3D 角色控制器/ 相機/敵人尋路/關卡"、"匯入 glb 模型不顯示"、"3D 場景太暗/太卡"、"make a 3D game"、 "first-person controller in Godot"。覆蓋專案腳手架、CharacterBody3D 控制器與相機 (滑鼠視角、SpringArm3D)、glTF 匯入與免費 CC0 資產源(KayKit/Poly Haven)、 StandardMaterial3D 材質貼圖、WorldEnvironment 燈光氛圍、NavigationAgent3D 敵人 尋路、動畫播放、HUD、無頭驗證與截圖驗收、效能最佳化、匯出。只做 3D;2D 遊戲用 2d-game-dev skill。
從零把一個 3D 遊戲做到可玩、可驗證、可釋出。引擎固定 Godot 4.x + GDScript, 資產格式固定 glTF(.glb)。約定 1 unit = 1 米,所有模型按真實尺度擺放。
核心原則:先灰盒後美術——用 CSGBox3D/基本幾何把玩法和手感調對,再替換成正式 模型;每加一個系統就跑一遍驗證(見第 9 節)。
godot --version # 需要 4.x;macOS: brew install godot
project.godot 最小配置(渲染器決定平臺與畫質上限):
[application]
config/name="My3DGame"
run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.4")
[rendering]
renderer/rendering_method="forward_plus" ; 桌面端;匯出網頁/手機改 "mobile" 或 "gl_compatibility"
目錄約定:
scenes/ main.tscn player.tscn enemy.tscn level_1.tscn hud.tscn
scripts/ 同名 .gd
assets/ models/ materials/ textures/ hdris/ audio/
autoload/ game_state.gd
main.tscn 起步三件套:WorldEnvironment + DirectionalLight3D(開 shadow)+
一塊地板(CSGBox3D 或 MeshInstance3D+StaticBody3D)。沒有燈和環境的 3D 場景是
純黑的——"畫面全黑"九成是這裡。
節點:CharacterBody3D > CollisionShape3D(Capsule) + Node3D(Head) > Camera3D
extends CharacterBody3D
const SPEED := 5.0
const JUMP_VELOCITY := 4.5
const MOUSE_SENS := 0.002
@onready var head: Node3D = $Head
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
rotate_y(-event.relative.x * MOUSE_SENS)
head.rotate_x(-event.relative.y * MOUSE_SENS)
head.rotation.x = clampf(head.rotation.x, -PI/2, PI/2)
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
var input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var dir := (transform.basis * Vector3(input.x, 0, input.y)).normalized()
velocity.x = dir.x * SPEED
velocity.z = dir.z * SPEED
move_and_slide()
按 Esc 釋放滑鼠:Input.mouse_mode = Input.MOUSE_MODE_VISIBLE。
相機換成 SpringArm3D > Camera3D(spring_length 3~5,SpringArm 自動防穿牆),
水平旋轉加在 SpringArm 的 yaw 上;移動方向按相機朝向換算,角色模型用
look_at 或對 rotation.y 做 lerp_angle 平滑轉身。
.glb 優先於 .gltf:Godot 4 下部分 .gltf 會靜默匯入失敗
(load() 返回 null 且無報錯)。下載的資產包好檔案常嵌很深,
find <dir> -iname '*.glb' 先定位。.glb 拖進 res:// 自動匯入;程式碼裡
preload("res://assets/models/x.glb").instantiate() 直接例項化。$Mesh.create_trimesh_collision()(僅靜態;
動態剛體用 convex)。AnimationPlayer,
$Model/AnimationPlayer.play("Run");先 get_animation_list() 列印確認動畫名。
狀態多了再上 AnimationTree(locomotion 混合、one-shot 攻擊),兩三個狀態
直接 play 切換即可。game-asset-gen skill 可生成無縫貼圖與圖示;
game-asset-3d skill 可自動搜尋下載上述 CC0 源。沒有則手動下載。MultiMeshInstance3D(一次 draw call)。GridMap + MeshLibrary(把套件場景轉成
MeshLibrary 後像 3D TileMap 一樣刷)。Marker3D / Area3D(拾取、傷害區、關卡切換門,寫法同 2D,
只是節點帶 3D 字尾)。物理層命名規範同樣適用:layer=我是誰,mask=我碰誰。arm 是三合一打包圖,
勾 "ORM" 材質型別或分通道指定)。uv1_scale 控制重複次數;沒有 UV 的程式化幾何體勾 uv1_triplanar。WorldEnvironment > Environment > Sky。快速出效果用
ProceduralSkyMaterial;要真實感用 Poly Haven HDRI + PanoramaSkyMaterial,
並把 ambient light source 設為 Sky,讓環境光來自天空。DirectionalLight3D 當太陽:開 shadow,角度斜 30~45°;室內補
OmniLight3D/SpotLight3D(陰影燈越少越好,每盞陰影燈都有開銷)。Environment 上依次調:Tonemap 設 Filmic/ACES(預設 Linear 是"塑膠感"
主因)、開 Glow(自發光材質會泛光)、加 Volumetric Fog 或普通 Fog 拉出景深
層次、SSAO 增強角落接觸感(Forward+ 專屬)。關卡根掛 NavigationRegion3D,把靜態地面/障礙放進去後 Bake(編輯器按鈕或
bake_navigation_mesh())。敵人:
# CharacterBody3D + NavigationAgent3D
@onready var agent: NavigationAgent3D = $NavigationAgent3D
func _physics_process(delta: float) -> void:
agent.target_position = player.global_position # 加 Timer 每 0.2s 更新更省
if not agent.is_navigation_finished():
var next := agent.get_next_path_position()
var dir := (next - global_position).normalized()
velocity.x = dir.x * SPEED
velocity.z = dir.z * SPEED
if not is_on_floor():
velocity += get_gravity() * delta
move_and_slide()
行為分層:巡邏(導航到路徑點)→ 發現(到玩家距離 + 視線 RayCast3D)→ 追擊 →
攻擊(Area3D hitbox),一個 enum 狀態機足夠。
3D 場景之上疊 CanvasLayer:準星(居中 TextureRect)、血條
(TextureProgressBar)、拾取提示。流程同 2D:
get_tree().change_scene_to_file() 切主選單/關卡/結算;暫停時記得把
Input.mouse_mode 還原成 VISIBLE。
# 1. 匯入 + 解析檢查(改完必跑;新增 glb 後尤其要跑,看有無匯入失敗)
godot --headless --path . --import 2>&1 | grep -iE "error|SCRIPT ERROR" || echo IMPORT_OK
# 2. 無頭跑 120 幀抓執行時報錯
godot --headless --path . --quit-after 120 2>&1 | grep -iE "error" || echo RUN_OK
# 3. 視覺驗收:帶視窗跑幾秒 + 自動截圖(無頭不渲染)
godot --path . --quit-after 240
截圖 autoload 與 2D 相同(get_viewport().get_texture().get_image().save_png(...),
定時存 3 張)。3D 重點檢查:畫面是否全黑(燈/環境)、模型是否顯示(.gltf 靜默
失敗、scale 過大過小)、材質是否發紫(貼圖丟失)、角色是否穿地(碰撞沒生成)。
按收益排序:陰影燈數量與 shadow 解析度 > 重複物件改 MultiMeshInstance3D >
Camera3D.far 別預設 4000 米 > 大關卡加 OccluderInstance3D(遮擋剔除)>
網格 LOD(匯入時自動生成,確認沒關)。目標平臺弱(網頁/手機)就直接換
Mobile / Compatibility 渲染器,比逐項摳更有效。
godot --headless --install-export-templates # 首次
godot --headless --path . --export-release "macOS" build/mac/MyGame.zip
godot --headless --path . --export-release "Windows Desktop" build/win/MyGame.exe
# 網頁匯出需 gl_compatibility 渲染器;3D 網頁包體大,桌面端是 3D 的主釋出目標
7w4.net小蔥技能站收錄全網優質技能,值得收藏。
.gltf 靜默匯入失敗 → 換 .glb,或換資產;load() 返回 null 必查此項。relative 符號與靈敏度;忘了 clamp pitch 會翻筋斗。這個 Skill 質量不錯,涵蓋了 3D 遊戲開發的主要環節,程式碼示例實用,常見問題解答也很貼心。優點是內容全面、步驟清晰,適合入門到中級開發者;不足是缺乏高階技巧和實戰專案參考,深度可以進一步加強。