Godot4实战:从零构建2D像素风平台跳跃游戏全流程指南
1. 项目概述为什么选择Godot4构建2D像素风平台跳跃游戏如果你对游戏开发感兴趣尤其是想亲手创造一个属于自己的、充满复古魅力的平台跳跃游戏那么Godot4引擎绝对是一个值得你投入时间学习的绝佳工具。我最初接触Godot也是被它轻量、开源和极其友好的2D开发体验所吸引。与一些商业引擎相比Godot没有复杂的许可费用其节点Node和场景Scene的架构理念让游戏逻辑的组织变得直观就像在搭积木。特别是对于2D游戏Godot内置的渲染和物理系统经过了深度优化处理精灵Sprite、瓦片地图TileMap和刚体碰撞时非常高效。这次我们要构建的是一个经典的2D像素风平台跳跃游戏。这不仅仅是复刻《超级马里奥》或《蔚蓝》的玩法更是一个完整的、从零开始的实践项目。通过它你将系统性地掌握Godot4的核心工作流从创建第一个场景、绘制或导入像素美术资源到编写玩家控制器、设计关卡、实现敌人AI和交互逻辑最后打包发布。像素风不仅是一种美术风格更是一种技术选择——它意味着对动画帧、碰撞体精度和关卡设计有着更具体的要求。Godot4对2D像素游戏的友好支持比如像素对齐Snap、子像素移动的处理以及强大的动画状态机都能让我们事半功倍。无论你是编程新手还是有一定基础想转战游戏开发的爱好者这个项目都将带你走完一个游戏从无到有的全过程。我们会避开华而不实的理论直接上手敲代码、摆节点在解决一个个具体问题的过程中把知识牢牢掌握。准备好了吗让我们打开Godot4开始构建你的第一个游戏世界。2. 核心工作流与项目结构设计在动手写第一行代码之前花点时间规划一下项目结构至关重要。一个清晰的结构不仅能让你在开发后期保持头脑清醒也便于团队协作和未来的功能扩展。在Godot中一切皆节点Node我们的游戏世界就是由一个个节点树组成的。2.1 项目文件夹与资源管理启动Godot4创建一个新项目。我建议你为项目建立一个清晰的文件夹结构这会在资源越来越多时帮你大忙。通常我会在项目根目录下创建如下文件夹scenes/: 存放所有.tscn场景文件。这是Godot场景树的序列化文件是我们游戏的主要构件。scripts/: 存放所有.gd脚本文件。Godot使用GDScript作为主要脚本语言它语法类似Python非常易学。assets/: 存放所有美术和音频资源。可以再细分为sprites/精灵图、tilesets/瓦片集、backgrounds/背景、audio/音效和音乐等。autoload/: 存放自动加载的全局脚本比如游戏管理器GameManager、音效管理器AudioManager。在Godot编辑器的“文件系统”停靠面板中创建这些文件夹。管理资源时Godot的“导入”停靠面板是关键。对于像素美术一个重要的设置是“导入”选项中的“纹理”设置。确保将“过滤”模式设置为“最近邻”Nearest这样才能保持像素边缘锐利避免模糊。对于音频可以根据需要设置循环或压缩格式。2.2 场景树Scene Tree架构设计Godot的游戏运行基于场景树。我们的主游戏流程可能会由以下几个核心场景构成Main主场景: 作为游戏的入口点通常是一个简单的场景用于加载其他场景或显示主菜单。Player玩家场景: 一个独立的场景包含玩家角色精灵、碰撞形状、摄像机以及控制脚本。这样设计便于在任何关卡中复用玩家。Level_01, Level_02...关卡场景: 每个关卡都是一个独立的场景里面包含地形瓦片地图TileMap、敌人、机关、收集品等。UI用户界面场景: 处理生命值、分数、暂停菜单等UI元素的场景。它们之间的关系是Main场景加载并实例化Level_01场景Level_01场景中又实例化了Player场景。这种模块化设计让调试和替换变得非常容易。例如你想测试一个新的玩家动作只需修改Player场景所有关卡都会自动更新。注意在Godot中将一个场景实例化到另一个场景中通常使用“实例化子场景”功能将.tscn文件拖入场景中。确保玩家场景的根节点是CharacterBody2D用于平台跳跃物理而关卡场景的根节点通常是Node2D。3. 构建游戏世界玩家角色与物理运动游戏的核心是交互而交互的核心是玩家角色。在2D平台跳跃游戏中一个响应灵敏、手感扎实的玩家控制器是成功的一半。3.1 创建玩家场景与物理体首先创建一个新场景。根节点选择CharacterBody2D。为什么是CharacterBody2D而不是RigidBody2D因为CharacterBody2D是专门为受代码控制的角色如平台游戏主角、第一人称角色设计的物理体。它允许我们通过代码精确控制移动、跳跃并处理与环境的碰撞而不是完全交由物理引擎模拟这给了我们更大的操控权。为这个CharacterBody2D节点添加子节点一个CollisionShape2D并为其分配一个RectangleShape2D。这个形状就是玩家的物理碰撞边界。对于像素角色这个矩形应该紧密贴合精灵的视觉轮廓。一个Sprite2D节点用于显示玩家形象。暂时可以先使用一个简单的彩色矩形作为占位符等美术资源到位后再替换。一个Camera2D节点作为跟随玩家的摄像机。将其设为当前Make Current并调整其缩放和拖拽边缘等属性实现平滑跟随。3.2 编写玩家移动与跳跃脚本为CharacterBody2D根节点附加一个新脚本命名为player.gd。下面是一个基础但功能完整的平台跳跃控制器代码框架extends CharacterBody2D # 导出变量方便在编辑器中实时调整 export var speed: float 300.0 export var jump_velocity: float -400.0 export var double_jump_velocity: float -350.0 # 二段跳速度 # 获取重力设置 var gravity ProjectSettings.get_setting(physics/2d/default_gravity) var has_double_jumped false var is_jumping false func _physics_process(delta): # 1. 应用重力如果不在平台上 if not is_on_floor(): velocity.y gravity * delta has_double_jumped false # 重置二段跳状态可选逻辑 else: has_double_jumped false is_jumping false # 2. 处理跳跃输入 if Input.is_action_just_pressed(ui_accept) or Input.is_action_just_pressed(jump): if is_on_floor(): # 在地面上执行普通跳 velocity.y jump_velocity is_jumping true elif not has_double_jumped: # 在空中且未二段跳执行二段跳 velocity.y double_jump_velocity has_double_jumped true is_jumping true # 3. 获取水平方向输入左/右/A/D var direction Input.get_axis(ui_left, ui_right) if direction: velocity.x direction * speed else: # 没有输入时逐渐减速可选增加手感 velocity.x move_toward(velocity.x, 0, speed) # 4. 执行移动并处理碰撞 move_and_slide() # 5. 可选根据方向翻转精灵 if direction ! 0: $Sprite2D.flip_h direction 0这段代码实现了几个核心功能重力模拟、地面跳跃、空中二段跳、水平移动与减速。move_and_slide()方法是CharacterBody2D的灵魂它根据我们设置的velocity速度矢量移动角色并自动处理与环境中其他CollisionObject2D如地面、墙壁的碰撞。实操心得跳跃手感是平台游戏的核心。jump_velocity的负值越大跳得越高。你可以尝试在玩家按住跳跃键时让重力略微减小实现“长按跳得更高”的效果这能极大提升操作手感。另外move_and_slide()之后is_on_floor()、is_on_wall()、is_on_ceiling()等方法会更新用于判断碰撞状态非常实用。3.3 动画状态机与精灵动画静态的精灵很无趣我们需要让角色动起来。Godot的AnimationPlayer节点和AnimationTree状态机是制作复杂角色动画的利器。首先为玩家场景添加一个AnimationPlayer节点。假设我们有一张包含走、跑、跳、 idle待机等动作的精灵图集Sprite Sheet。我们需要为每个动作创建动画在AnimationPlayer中新建动画命名为idle。选中Sprite2D节点在动画轨道上为其animation属性如果你使用AnimatedSprite2D或frame属性如果手动控制帧添加关键帧。类似地创建run、jump、fall等动画。然后添加一个AnimationTree节点并将其Tree Root设置为AnimationNodeStateMachine。在状态机中创建与动画同名的状态如Idle, Run, Jump并将AnimationPlayer中的动画分配给它们。最后通过编写代码根据玩家的状态速度、是否在地面等来切换状态机中的状态。# 在_physics_process函数末尾添加动画逻辑 func _physics_process(delta): # ... 之前的物理和移动代码 ... # 动画控制 if is_on_floor(): if abs(velocity.x) 1.0: $AnimationTree.set(parameters/conditions/is_running, true) $AnimationTree.set(parameters/conditions/is_idle, false) else: $AnimationTree.set(parameters/conditions/is_running, false) $AnimationTree.set(parameters/conditions/is_idle, true) else: $AnimationTree.set(parameters/conditions/is_jumping, velocity.y 0) $AnimationTree.set(parameters/conditions/is_falling, velocity.y 0)通过状态机管理动画逻辑清晰且易于扩展比如未来添加“受伤”、“攻击”等状态会非常方便。4. 绘制关卡TileMap与关卡设计实战有了会动的主角我们需要一个舞台。Godot的TileMap节点是构建2D关卡尤其是平台跳跃关卡的神器。它允许你使用预先绘制好的瓦片Tile来“绘制”关卡高效且易于修改。4.1 创建与配置TileSetTileMap依赖于TileSet资源。TileSet就是一个图集包含了所有用于拼接地图的小块图片。创建TileSet的步骤如下在场景中添加一个TileMap节点。在检查器面板中点击TileSet属性旁边的[empty]选择New TileSet。点击TileSet属性旁边的资源图标进入TileSet编辑面板。在“图块”模式下点击“添加图块集”导入你的瓦片图集一张包含多个瓦片的图片。Godot4的TileSet系统非常强大支持自动切割瓦片。你可以设置瓦片尺寸如16x16像素然后点击“在图像中自动创建瓦片”它会自动识别并切割。为切割好的瓦片配置属性。最重要的是物理层和导航层。物理层为那些玩家和敌人应该与之发生碰撞的瓦片如地面、墙壁添加碰撞形状。通常使用矩形碰撞即可。你可以为每个瓦片或一组瓦片绘制碰撞体。导航层如果你希望敌人能在平台上自动寻路需要为可行走的表面设置导航多边形。4.2 使用TileMap绘制关卡配置好TileSet后回到场景中的TileMap节点。在编辑器顶部你会看到TileMap的绘制工具。选择你想要放置的瓦片然后在2D视口中点击或拖拽绘制。你可以绘制多个图层例如一个背景装饰层和一个前景碰撞层。绘制技巧使用图章工具可以预先组合好一小片地形如一个平台加两边的斜坡保存为图章然后快速重复放置大大提高效率。利用网格对齐确保开启“吸附”功能快捷键S并设置为“网格吸附”步长设为瓦片大小如16像素这样能保证瓦片完美对齐避免出现像素缝隙。分层管理创建多个TileMap节点或使用单个TileMap的多个图层来分别管理地面、背景装饰、前景遮挡物等。这有助于后期调整和添加视差滚动等效果。4.3 关卡设计原则与技巧绘制关卡不仅仅是铺瓦片更是设计玩家的体验旅程。对于平台跳跃游戏循序渐进第一个关卡只引入基本移动和跳跃。后续关卡再逐步加入二段跳、冲刺、蹬墙跳等能力以及相应的新障碍。引导与暗示利用金币、发光的物体或地形的走向自然地引导玩家前进的方向。避免让玩家在空旷的场景中不知所措。节奏感设计关卡时要有张有弛。一段紧张的跳跃序列后可以安排一个安全的区域让玩家喘息或者放置一个存档点。难度曲线通过调整跳跃间距、敌人密度、机关复杂度来平滑地提升难度。最忌讳的是难度陡增。踩坑记录早期我经常把跳跃关卡设计得过难。后来发现一个黄金法则是为玩家设计“安全网”。例如一个需要精确跳跃的深渊下方可以设置一些会掉血的尖刺作为惩罚而不是直接死亡重来。这降低了挫败感也让关卡更有层次。5. 注入灵魂敌人、机关与交互逻辑一个只有平台和跳跃的世界是单调的。我们需要加入敌人增加挑战加入机关丰富玩法加入收集品提供正反馈。5.1 创建基础敌人AI敌人也是一个场景。常见的平台游戏敌人类型有巡逻型、追逐型、发射型。我们以最简单的左右巡逻型敌人为例。新建场景根节点为CharacterBody2D或Area2D如果不需要复杂物理。添加Sprite2D和CollisionShape2D。编写脚本使其在两个点之间来回移动。extends CharacterBody2D export var move_speed: float 50.0 export var patrol_distance: float 100.0 # 巡逻距离 var start_position: Vector2 var target_position: Vector2 var moving_right: bool true func _ready(): start_position global_position target_position start_position Vector2.RIGHT * patrol_distance func _physics_process(delta): # 计算移动方向 var direction: Vector2 if moving_right: direction (target_position - global_position).normalized() else: direction (start_position - global_position).normalized() velocity direction * move_speed move_and_slide() # 判断是否到达转折点 if moving_right and global_position.distance_to(start_position) patrol_distance: moving_right false elif not moving_right and global_position.distance_to(start_position) 1.0: moving_right true # 翻转精灵朝向 if velocity.x ! 0: $Sprite2D.flip_h velocity.x 0当玩家碰到敌人时需要处理伤害。这通常通过信号或区域检测来实现。在敌人身上添加一个Area2D作为其“伤害区域”当玩家的碰撞体进入该区域时触发伤害逻辑。5.2 实现可交互机关机关是关卡设计的调味剂。例如移动平台使用Path2D和PathFollow2D节点让平台沿预定路径循环移动。玩家站上去后需要成为平台的子节点或同步其速度。尖刺/伤害区域创建一个Area2D当玩家进入时调用玩家的受伤或重置函数。开关与门使用两个场景一个StaticBody2D作为门一个Area2D作为开关。当玩家触碰或攻击开关时通过信号或全局变量通知门“打开”可以播放动画并禁用碰撞。# 开关脚本示例 (switch.gd) extends Area2D signal switch_activated func _on_body_entered(body): if body.is_in_group(player): # 确保只有玩家能触发 emit_signal(switch_activated) $AnimationPlayer.play(press) # 播放按下动画 # 禁用后续碰撞避免重复触发 set_deferred(monitoring, false) # 门脚本示例 (door.gd) extends StaticBody2D func _on_switch_activated(): $AnimationPlayer.play(open) set_deferred(collision_layer, 0) # 打开后移除碰撞层玩家可通过5.3 收集品与游戏状态管理金币、宝石等收集品是直接的奖励。它们通常是一个Area2D带有旋转或上下浮动的动画。当玩家碰撞时播放收集音效、增加分数、然后销毁自身。游戏状态如分数、生命值、当前关卡需要全局管理。这时就该使用自动加载单例。创建一个名为GameManager.gd的脚本。进入“项目设置” - “自动加载”将该脚本添加进去并给它起个名字如GameManager。在这个脚本中定义全局变量和函数。# GameManager.gd extends Node var score: int 0 var player_lives: int 3 var current_level: String func add_score(points: int): score points # 可以在这里发出信号通知UI更新 print(Score: , score) func player_died(): player_lives - 1 if player_lives 0: game_over() else: respawn_player() func respawn_player(): # 重新加载当前关卡或传送到检查点 get_tree().reload_current_scene()这样在任何脚本中都可以通过GameManager.add_score(100)来修改分数实现了逻辑解耦。6. 打磨体验摄像机、UI与音效游戏的“手感”和“观感”很大程度上由细节决定。平滑的摄像机、清晰的UI和恰当的音效能让游戏品质提升一个档次。6.1 高级摄像机控制之前我们简单地将Camera2D附加到玩家身上。但直接跟随会导致画面剧烈抖动尤其是在高速移动或跳跃时。Godot的Camera2D提供了强大的平滑和限制功能。平滑在Camera2D属性中启用“位置平滑”和“旋转平滑”并调整平滑速度。这会让摄像机延迟一点跟随玩家运动更柔和。拖拽边缘可以设置当玩家移动到屏幕边缘一定距离时摄像机才开始移动。这给了玩家一些前瞻空间。限制将摄像机的“限制”属性与当前关卡的边界绑定防止摄像机移出地图外。你可以创建一个不可见的Node2D作为关卡边界然后在代码中设置$Camera2D.limit_left等属性。更高级的做法是使用RemoteTransform2D节点。将RemoteTransform2D作为玩家的子节点而Camera2D放在场景根部。RemoteTransform2D会控制Camera2D的位置这样你可以独立设计摄像机的行为逻辑而不受玩家节点变换的直接影响。6.2 创建游戏UIUI是玩家与游戏信息交互的窗口。Godot的UI系统基于控件Control节点。创建一个新的场景根节点为CanvasLayer。CanvasLayer的渲染顺序独立于主世界适合做UI。在CanvasLayer下添加MarginContainer、HBoxContainer、VBoxContainer等布局容器以及Label、TextureRect等控件来显示生命值、分数。为UI编写脚本定义更新函数并连接到GameManager发出的信号上。# UI.gd extends CanvasLayer onready var score_label: Label $MarginContainer/HBoxContainer/ScoreLabel onready var lives_label: Label $MarginContainer/HBoxContainer/LivesLabel func _ready(): # 连接到全局管理器的信号 GameManager.score_changed.connect(_on_score_changed) GameManager.lives_changed.connect(_on_lives_changed) update_display() func _on_score_changed(): score_label.text Score: %d % GameManager.score func _on_lives_changed(): lives_label.text Lives: %d % GameManager.player_lives6.3 集成音效与背景音乐声音是氛围营造的关键。Godot使用AudioStreamPlayer一次性音效和AudioStreamPlayer2D具有2D空间感的音效来播放声音。音效对于跳跃、收集、受伤等音效使用AudioStreamPlayer。将其作为玩家或收集品节点的子节点在代码中需要时调用$JumpSound.play()。背景音乐对于循环播放的背景音乐通常使用一个全局的AudioStreamPlayer节点可以放在自动加载的AudioManager中并设置其Stream为导入的音乐文件如.ogg、.wav将播放模式设为循环。注意事项音效文件不宜过大注意压缩格式。背景音乐音量应低于音效避免喧宾夺主。Godot还支持总线Audio Bus和效果器你可以为音乐和音效创建不同的总线并统一调整音量或添加混响等效果。7. 调试、优化与发布游戏基本完成后还有大量“打磨”工作要做以确保它稳定、流畅且易于分享。7.1 常用调试技巧与工具Godot内置了强大的调试工具调试器在编辑器底部“调试器”面板可以查看变量值、调用堆栈。善用print()函数输出关键信息。远程场景树运行游戏后在“场景”停靠面板顶部切换到“远程”可以实时查看运行中游戏的节点树对于查找节点路径错误或动态生成的节点非常有用。性能分析器通过“调试器” - “分析器”选项卡可以监控帧时间_process/_physics_process、物理步骤、内存使用等。如果某帧时间突然飙升这里能找到元凶。可视碰撞调试在运行游戏时按下键盘上的F3键或通过“调试”菜单可以显示所有碰撞形状和射线投射对于调试物理问题至关重要。7.2 性能优化要点对于2D像素游戏性能压力通常不大但好习惯要养成绘制调用Draw Calls这是2D性能的关键。尽量减少屏幕上不同材质/纹理的数量。使用TileMap本身就是一种批处理优化。对于大量相同的精灵如子弹、粒子考虑使用MultiMeshInstance2D或GPUParticles2D。物理优化避免使用过多、过复杂的碰撞形状。对于静态地形TileMap的碰撞效率很高。对于移动的敌人或物体确保其碰撞形状尽可能简单矩形、胶囊形优于多边形。脚本效率在_process中避免进行昂贵的计算或频繁的节点查找get_node()。可以将结果缓存起来。对于不活跃的敌人或物体可以设置其process_mode为PROCESS_MODE_DISABLED或直接移出场景树。资源管理及时释放不再需要的资源。对于动态加载的场景或资源使用queue_free()销毁节点或调用ResourceLoader.unload()释放资源。7.3 打包与发布你的游戏当游戏调试完毕就可以打包分享了。Godot支持一键导出到数十个平台。准备导出模板首次导出前需要下载对应平台如Windows、macOS、Linux、HTML5的导出模板。在编辑器“编辑器设置” - “导出”中下载。配置导出预设进入“项目” - “导出”菜单。添加一个导出预设如“Windows Desktop”。在“资源”选项卡中通常选择“导出所有资源”。在“功能”选项卡可以为不同平台配置图标、文件关联等。处理特定平台问题HTML5注意文件大小过大的游戏加载慢。可能需要将音频转换为合适的格式如.ogg。移动端需要配置触摸屏控制并考虑性能适配。执行导出选择预设点击“导出项目...”选择一个输出文件夹和可执行文件名。Godot会生成一个包含所有游戏数据的独立可执行文件或对于HTML5是一个.html文件和.pck数据包。发布前务必在目标平台上进行测试确保所有功能正常UI缩放合适没有平台特有的Bug。8. 常见问题与排查技巧实录在开发过程中你一定会遇到各种奇怪的问题。这里记录了一些我踩过的坑和解决方案希望能帮你节省时间。8.1 物理与碰撞问题问题1玩家卡在TileMap边缘或穿透薄墙。原因CharacterBody2D的move_and_slide()默认使用floor_stop_on_slope等参数可能与斜坡或边缘处理有关。另外碰撞形状可能比视觉精灵大导致“蹭”到障碍物。排查按F3开启碰撞可视化检查玩家和地面的碰撞形状是否准确对齐。确保TileMap中瓦片的碰撞形状没有意外的凸起。解决调整玩家CollisionShape2D的大小使其略小于视觉精灵。对于斜坡可以尝试在move_and_slide()调用时传入false给floor_stop_on_slope参数或使用move_and_slide_with_snapGodot 3风格Godot 4中已整合优化。问题2跳跃手感“粘滞”有时按了跳不起来。原因is_on_floor()的判断可能有一帧延迟或者输入检测时机与物理帧不同步。解决实现“跳跃缓存”和“土狼时间”。跳跃缓存允许玩家在落地前几帧按下跳跃键系统会记住这个输入并在落地时自动执行跳跃。土狼时间则允许玩家在离开平台后极短时间内仍能起跳。var jump_buffer_time 0.1 # 100毫秒缓存 var jump_buffer_counter 0.0 var coyote_time 0.1 # 土狼时间 var coyote_counter 0.0 func _physics_process(delta): # 更新计数器 if Input.is_action_just_pressed(jump): jump_buffer_counter jump_buffer_time jump_buffer_counter - delta if is_on_floor(): coyote_counter coyote_time else: coyote_counter - delta # 跳跃判断逻辑 var can_jump is_on_floor() or coyote_counter 0 if jump_buffer_counter 0 and can_jump: velocity.y jump_velocity jump_buffer_counter 0.0 coyote_counter 0.08.2 渲染与视觉问题问题像素游戏画面模糊或闪烁。原因默认的纹理过滤模式是线性插值会平滑像素边缘。视图拉伸模式也可能导致非整数倍缩放。解决项目设置进入“项目设置” - “渲染” - “纹理”将“默认纹理过滤”设置为“最近邻”。导入设置对每个像素美术资源在“导入”停靠面板中将其“过滤”模式设置为“最近邻”。视图拉伸进入“项目设置” - “显示” - “窗口”将“拉伸模式”设置为“canvas_items”或“viewport”并将“缩放模式”设置为“整数倍”。这样可以确保游戏画面以整数倍像素缩放保持清晰。问题TileMap瓦片之间有缝隙。原因瓦片图集Texture Atlas的边缘像素可能被采样。或者绘制时没有严格对齐网格。解决在图像编辑器中确保每个瓦片周围有至少1像素的透明边框或扩展边缘颜色。在Godot的TileSet资源中找到“图块集”的“纹理区域”尝试勾选“使用纹理区域”并微调区域或调整“图块偏移”。绘制时务必开启网格吸附。8.3 脚本与逻辑错误问题信号Signal连接了但没有触发。排查检查信号是否确实发射了。在发射信号的代码行后加一个print(“信号发射”)。检查接收信号的节点路径是否正确。使用print(self.get_path())和print(接收节点.get_path())对比。检查连接时机。确保在_ready()中连接信号时对方节点已经存在于场景树中。对于动态生成的节点需要在生成后立即连接。一个常见陷阱通过编辑器界面连接的信号如果节点名称或路径改变了连接会断开。通过代码连接更可靠。问题游戏打包后某些资源如图片、声音丢失。原因Godot默认只导出在项目中实际被引用的资源。如果资源是通过字符串路径动态加载的如load(“res://assets/level_” str(num) “.tscn”)导出器可能无法识别。解决在“项目” - “导出” - “资源”选项卡中不要选择“导出所有资源”这会让包体巨大而是将那些动态加载的资源所在的文件夹如res://assets/levels/添加到“资源导出包含过滤器”中。或者更规范的做法是将所有需要动态加载的资源注册到某个自动加载脚本的数组中确保它们被引用。开发游戏是一个不断迭代和解决问题的过程。遇到问题时不要慌张善用Godot的调试工具、查阅官方文档和活跃的社区论坛。从零构建一个完整的游戏是一次极具成就感的旅程你学到的不仅仅是Godot引擎的使用更是游戏设计、编程思维和解决问题能力的综合锻炼。我个人的体会是每解决一个棘手的Bug每实现一个酷炫的功能那种快乐是无可替代的。现在你的游戏世界已经初具雏形继续打磨它加入更多奇思妙想然后分享给朋友们玩吧