用 Godot 4 + GDScript 开发 3D 游戏的端到端工作流。触发场景:"做一个 3D 游戏"、 "第一人称/第三人称/FPS/TPS/3D 平台跳跃"、"用 Godot 做 3D"、"加个 3D 角色控制器/ 相机/敌人寻路/关卡"、"导入 glb 模型不显示"、"3D 场景太暗/太卡"、"make a 3D game"、 "first-per
3D 游戏开发(Godot 4 + GDScript)是一项面向实际任务的技能,主要用于从零把一个 3D 游戏做到可玩、可验证、可发布;引擎固定 Godot 4.x + GDScript;
每加一个系统就跑一遍验证 (见第。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。
从零把一个 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 -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 的主发布目标
.gltf 静默导入失败 → 换 .glb,或换资产;load() 返回 null 必查此项。relative 符号与灵敏度;忘了 clamp pitch 会翻筋斗。相关专题
热门下载
相关下载
精品课程
共115课时 | 43.5万人学习
共19课时 | 5.6万人学习
共37课时 | 8.8万人学习
最新文章