Godot 4.2 游戏开发实战:从零复刻《Dodge the Creeps!》2D躲避游戏

📅 2026/7/24 3:55:52
Godot 4.2 游戏开发实战:从零复刻《Dodge the Creeps!》2D躲避游戏
1. 项目概述与核心价值如果你对游戏开发感兴趣但又觉得Unity或Unreal Engine的门槛太高或者被它们庞大的体量和复杂的编辑器界面劝退那么Godot引擎绝对值得你花时间了解一下。作为一个开源、免费、轻量级的游戏引擎Godot以其独特的节点Node和场景Scene架构以及内置的GDScript脚本语言为独立开发者和初学者打开了一扇新的大门。这次我们不是泛泛而谈Godot的基础概念而是通过一个具体的、官方的入门示例项目——《Dodge the Creeps!》——来手把手带你走一遍完整的开发流程。《Dodge the Creeps!》是Godot官方文档中经典的2D入门教程项目。它的玩法很简单玩家控制一个角色在一个矩形区域内移动躲避从屏幕四周不断生成的“爬行者”Creeps生存时间越长得分越高。麻雀虽小五脏俱全。这个项目几乎涵盖了2D游戏开发的所有核心环节玩家输入处理、角色移动与碰撞、敌人AI生成与移动、UI分数与生命值显示、游戏状态管理开始、进行中、结束以及音效。通过复刻它你不仅能学会Godot的基本操作更能理解一个完整游戏项目是如何从零搭建起来的。为什么选择Godot 4.24.x版本是Godot的一次重大革新引入了全新的渲染器、改进的GDScript 2.0、更强大的物理系统以及许多工作流优化。4.2作为当前的一个稳定版本修复了大量bug性能表现更佳是新手入坑的理想起点。网上虽然有不少教程但很多是基于旧版本3.x或者步骤跳跃对于真正的“从零开始”并不友好导致新手在配置环境、理解概念、调试bug时频频踩坑。本指南的目的就是充当你的“保姆”不仅告诉你每一步怎么做更会解释为什么这么做并提前预警那些教程里不常提、但实际开发中几乎必遇的“坑”让你能顺畅地完成第一个Godot游戏并建立起扎实的信心。2. 环境准备与项目初始化2.1 Godot 4.2 引擎的下载与安装第一步是获取Godot引擎。前往Godot官网的下载页面你会看到几个版本选项。对于新手我强烈推荐下载“Standard”版本它是一个包含所有功能的独立可执行文件无需安装解压即用。避免使用“.NET”版本除非你确定要使用C#进行开发。下载完成后将压缩包解压到你习惯的目录例如D:\Godot或~/Applications/Godot。双击运行Godot_v4.2-stable_win64.exeWindows或对应的可执行文件引擎就会启动。注意Godot引擎本身不“安装”到系统目录这意味着你可以同时存放多个不同版本如4.1, 4.2, 4.3测试版而互不干扰。这对于项目版本管理或测试新特性非常方便。首次启动会进入项目管理器界面。这里空空如也因为我们还没有创建任何项目。点击右上角的“新建”按钮开始创建我们的《Dodge the Creeps!》项目。2.2 创建新项目的关键配置点击“新建”后会弹出项目创建对话框。这里有几个关键配置项一步错可能导致后续麻烦项目名称输入DodgeTheCreeps或你喜欢的任何名字但建议不要用中文或特殊字符避免路径问题。项目路径选择一个空文件夹作为项目的根目录。Godot会在这个文件夹下创建项目文件和组织资源。绝对不要把项目放在Godot引擎的同一目录或系统盘根目录下。渲染器Godot 4提供了两种渲染器后端Forward和Compatibility。Forward默认选项功能更强大支持所有现代图形特性如SDFGI、SSAO等是未来方向。Compatibility兼容性模式旨在支持较旧的硬件如集成显卡或一些老独显和OpenGL 3.3环境。选择建议作为2D项目两者性能差异不大。如果你的显卡不是特别老旧近5-7年的主流显卡直接选择Forward即可。如果项目创建后运行黑屏或报图形API错误再回来尝试切换到Compatibility模式。版本控制系统元数据这里选择“None”。我们后续会手动初始化Git以便更好地管理版本。配置完成后点击“创建并编辑”Godot就会创建项目并自动打开编辑器。2.3 认识Godot编辑器界面第一次进入编辑器可能会被各种面板和按钮搞得有点晕。别担心我们快速过一下核心区域场景面板左上这是Godot的核心。所有游戏对象都以“节点”Node的形式存在并组织成树状结构称为“场景树”Scene Tree。我们在这里搭建游戏世界。文件系统面板左下类似于资源管理器显示项目文件夹中的所有文件场景、脚本、图片、声音等。我们在这里管理资源。视图面板中间2D/3D视图和脚本编辑器。在2D项目中中间是2D视图你可以在这里直观地布置场景。检查器面板右侧当你选中场景树中的一个节点或文件系统中的一个资源时这里会显示该对象的所有属性和参数你可以在这里进行详细配置。底部面板包含输出、调试、动画等各类工具窗口。最常用的是“输出”窗口它会打印脚本的print信息、警告和错误是调试的利器。现在在文件系统面板中右键点击res://代表项目根目录选择“新建文件夹”创建如下几个文件夹scenes存放场景、scripts存放GDScript脚本、art存放图片、精灵图、audio存放音效。良好的文件夹结构是项目可维护性的第一步。3. 核心场景搭建与玩家角色实现3.1 创建主游戏场景Main Scene在Godot中一切皆场景。我们的游戏主循环本身也是一个场景。在场景面板中点击“其他节点”按钮或按 CtrlA搜索并添加一个Node2D节点。将其重命名为Main。然后在文件系统面板的scenes文件夹上右键选择“另存为场景”将其保存为main.tscn。这样我们就创建了游戏的根场景。接下来我们需要为这个主场景添加一些必要的子节点构成游戏的基本框架选中Main节点添加一个CharacterBody2D节点重命名为Player。这将是我们的玩家角色。选中Main节点添加一个Timer节点重命名为MobTimer。这个计时器将用来控制敌人Creeps的生成间隔。选中Main节点添加一个Timer节点重命名为ScoreTimer。这个计时器将用来定期增加玩家的生存分数。选中Main节点添加一个Marker2D节点重命名为StartPosition。我们将用它来标记玩家初始出现的位置。最后添加一个CanvasLayer节点重命名为UI。CanvasLayer可以确保其子节点如HUD始终绘制在最上层不受游戏世界坐标影响。你的场景树现在应该看起来像这样Main (Node2D) ├── Player (CharacterBody2D) ├── MobTimer (Timer) ├── ScoreTimer (Timer) ├── StartPosition (Marker2D) └── UI (CanvasLayer)3.2 构建玩家角色Player现在我们来让玩家角色变得可见且可操控。首先需要一张角色图片。你可以从Godot官方示例资产中获取或者自己用任何绘图软件画一个简单的正方形/圆形。将图片文件如player.png拖入项目的art文件夹。添加视觉表现选中场景树中的Player节点为其添加一个子节点Sprite2D。在检查器中点击Texture属性旁边的“[空]”选择“快速加载”然后找到你的player.png图片。角色应该现在出现在2D视图中心。添加碰撞形状为了让游戏知道角色的边界以进行碰撞检测我们需要为Player添加一个CollisionShape2D子节点。选中它在检查器的Shape属性中点击“[空]” - “新建 CircleShape2D”。然后在2D视图中你可以拖动圆圈边缘的橙色控制点调整碰撞形状的大小使其大致匹配精灵图的外观。编写玩家移动脚本选中Player节点在检查器右侧点击“添加脚本”按钮。脚本语言选择 GDScript保存路径设为scripts/player.gd。点击“创建”。现在打开player.gd脚本我们将实现基于键盘输入的移动逻辑。extends CharacterBody2D # 定义玩家移动速度单位像素/秒 export var speed: int 400 # 定义一个变量来存储屏幕尺寸用于限制移动范围 var screen_size: Vector2 func _ready(): # 当节点首次进入场景树时调用获取游戏窗口的大小 screen_size get_viewport_rect().size func _physics_process(delta): # 初始化速度向量为 (0, 0) var velocity Vector2.ZERO # 检测键盘输入并更新速度向量 if Input.is_action_pressed(move_right): velocity.x 1 if Input.is_action_pressed(move_left): velocity.x - 1 if Input.is_action_pressed(move_down): velocity.y 1 if Input.is_action_pressed(move_up): velocity.y - 1 # 如果玩家按下了任何方向键速度向量不为零 if velocity.length() 0: # 将速度向量标准化使其长度为1然后乘以速度值 velocity velocity.normalized() * speed # 可选可以在这里播放行走动画 else: # 可选可以在这里播放闲置动画 pass # 调用父类方法移动角色并处理碰撞 move_and_slide() # 限制玩家位置使其不超出屏幕边界 position position.clamp(Vector2.ZERO, screen_size)代码解释与避坑点_physics_process(delta): 这个函数在每个物理帧默认每秒60次被调用delta是上一帧到这一帧的时间间隔。所有与物理和移动相关的逻辑都应该放在这里而不是_process(delta)后者用于图形渲染等非物理逻辑。Input.is_action_pressed(): 检测一个“动作”是否被持续按下。这里的“move_right”等动作我们还没定义。velocity.normalized(): 这是一个非常重要的操作。当同时按下两个方向键如右和下时速度向量会是(1, 1)其长度约为1.414。如果直接乘以speed斜向移动会比单向移动快。normalized()将其长度缩放到1保证了八个方向的移动速度一致。move_and_slide():CharacterBody2D的核心方法。它会根据当前速度移动角色并自动处理与Area2D或RigidBody2D等节点的碰撞。对于简单的移动和碰撞它比手动计算方便得多。position.clamp(): 将玩家的position限制在(0, 0)和screen_size构成的矩形区域内防止角色跑出屏幕。3.3 配置输入映射Input Map脚本里用到了“move_right”等动作我们需要在Godot中定义它们。点击编辑器顶部菜单的“项目” - “项目设置”。在左侧列表中找到“输入映射”标签页。在“动作”输入框中输入move_right点击“添加”按钮。点击新添加的move_right动作旁边的“”号选择“键”。按下键盘上的D键或右方向键然后点击“确定”。你可以为同一个动作添加多个按键如同时绑定D和右箭头。重复上述步骤为move_leftA/左箭头、move_upW/上箭头、move_downS/下箭头添加映射。现在回到编辑器点击顶部中间的“运行”按钮或按 F5。Godot会提示你选择一个主场景选择我们刚才保存的scenes/main.tscn。如果一切正常你将能看到你的角色精灵并且可以通过 WASD 或方向键在屏幕范围内移动它了实操心得在测试移动时你可能会发现角色移动有“粘滞感”或不够跟手。这通常是因为_physics_process的帧率是固定的默认60FPS而你的显示器刷新率可能更高。确保在项目设置“项目”-“项目设置”-“常规”-“应用程序”-“运行”-“帧率”中将“Vsync Mode”设置为“Enabled”或“Adaptive”这可以平滑帧生成减少输入延迟。另外CharacterBody2D的移动在低速或复杂碰撞下可能不如RigidBody2D自然但对于《Dodge the Creeps!》这类游戏完全够用。4. 敌人Creeps的生成与AI逻辑4.1 创建敌人场景Mob Scene敌人和玩家类似也是一个可移动、可碰撞的实体。但敌人会有多个实例因此我们将其创建为一个独立的、可重用的场景。在场景面板点击“新建场景”按钮。添加一个CharacterBody2D根节点重命名为Mob。为Mob添加Sprite2D和CollisionShape2D子节点并配置好敌人的图片如mob.png和碰撞形状建议用RectangleShape2D或CapsuleShape2D。将场景保存为scenes/mob.tscn。接下来为Mob节点添加脚本scripts/mob.gd。extends CharacterBody2D # 定义敌人的移动速度这个值将在生成时由主场景随机设定 export var min_speed: float 150.0 export var max_speed: float 250.0 func _ready(): # 为每个敌人实例随机选择一个速度 var mob_types $AnimatedSprite2D.sprite_frames.get_animation_names() $AnimatedSprite2D.play(mob_types[randi() % mob_types.size()]) func _physics_process(delta): # 敌人只需要朝一个方向直线移动 move_and_slide() # 这个函数由主场景调用用于初始化敌人的方向 func initialize(start_position, target_position): # 让敌人面向玩家目标位置 look_at(target_position) # 随机旋转一个角度让移动方向不那么死板 rotate(randf_range(-PI / 4, PI / 4)) # 计算移动的方向和距离 var direction (target_position - start_position).normalized() # 随机一个速度值 var random_speed randf_range(min_speed, max_speed) # 设置线性速度 velocity direction * random_speed代码解析initialize(start_position, target_position): 这是一个自定义函数。当主场景生成一个敌人实例时会调用这个函数传入生成点屏幕边缘和目标点玩家当前位置附近。敌人会先“看”向目标点然后随机偏转一个角度-45° 到 45°最后计算朝这个方向的速度。这样敌人就是朝着玩家的大致方向移动但带有随机性增加了躲避的难度和趣味性。look_at(): 让节点的正前方X轴正方向指向目标位置。这是2D节点的一个便捷方法。randf_range(): 生成指定范围内的随机浮点数。我们用它来随机化速度和旋转角度。注意我们在_physics_process中只调用了move_and_slide()因为速度velocity已经在initialize函数中设置好了且在整个生命周期中不变直线运动。4.2 在主场景中实现敌人生成逻辑回到我们的main.tscn和main.gd脚本。我们需要编写逻辑定期在屏幕边缘随机位置生成敌人并让它们朝着玩家移动。首先为Main节点添加脚本scripts/main.gd。然后我们需要做以下几件事连接计时器信号。预加载敌人场景。编写生成敌人的函数。extends Node2D # 预加载敌人场景资源 onready var mob_scene preload(res://scenes/mob.tscn) func _ready(): # 连接计时器的 timeout 信号到对应的函数 $MobTimer.timeout.connect(_on_mob_timer_timeout) $ScoreTimer.timeout.connect(_on_score_timer_timeout) # 初始化玩家位置 $Player.position $StartPosition.position # 开始游戏这个函数我们稍后实现 new_game() func _on_mob_timer_timeout(): # 创建一个敌人的实例 var mob mob_scene.instantiate() # 为敌人选择一个随机的生成路径路径节点我们稍后添加 var mob_spawn_location $MobPath/MobSpawnLocation mob_spawn_location.progress_ratio randf() # 设置敌人的初始位置和方向 var direction mob_spawn_location.rotation PI / 2 mob.position mob_spawn_location.position direction randf_range(-PI / 4, PI / 4) mob.rotation direction # 设置敌人的目标位置在玩家附近随机一个点增加不确定性 var target_position $Player.position target_position.x randf_range(-100, 100) target_position.y randf_range(-100, 100) # 调用敌人的初始化函数 mob.initialize(mob_spawn_location.position, target_position) # 将敌人添加到主场景中 add_child(mob) func _on_score_timer_timeout(): # 分数计时器每次触发分数增加 # 这里需要访问UI中的分数标签我们稍后设置 # $UI/ScoreLabel.text str(int($UI/ScoreLabel.text) 1) pass func new_game(): # 重置游戏状态 # 重置分数、生命值等UI # 启动敌人生成计时器和分数计时器 $MobTimer.start() $ScoreTimer.start()这里出现了一个新节点$MobPath/MobSpawnLocation。我们需要创建它在Main场景中添加一个Path2D节点重命名为MobPath。这个节点将定义敌人可能的生成区域一个围绕屏幕的路径。选中MobPath在2D视图中你会看到一条可编辑的曲线。使用工具栏的“钢笔”工具在屏幕外围点击绘制一个大致环绕游戏区域的矩形或椭圆形闭合路径。关键点路径不要离屏幕边界太近以免敌人一出生就在屏幕外也不要太靠内否则生成点会暴露。为MobPath添加一个子节点PathFollow2D重命名为MobSpawnLocation。这个节点可以沿着父路径移动。我们将在代码中随机设置它的progress_ratio在路径上的位置比例从而在路径上随机选一个点作为生成点。避坑指南PathFollow2D的rotation属性默认是沿着路径切线方向的。在代码中mob_spawn_location.rotation PI / 2是为了让敌人的初始朝向通常是精灵图的正面与路径垂直即指向路径内部/屏幕中心因为look_at函数是基于节点X轴正方向的。如果你发现生成的敌人朝向很奇怪可以尝试调整这里的偏移量PI / 2或者在敌人场景的initialize函数中调整look_at后的额外旋转。5. 碰撞检测、游戏逻辑与用户界面5.1 实现碰撞检测与生命值系统游戏的核心玩法是躲避敌人。我们需要检测玩家是否被敌人碰到。在Godot中常用的碰撞检测节点是Area2D。为玩家添加碰撞区域在Player场景中添加一个Area2D子节点重命名为HitBox。为这个Area2D添加一个CollisionShape2D子节点并将其形状设置为与玩家的视觉和物理碰撞形状大致匹配通常可以复用同一个形状资源。连接信号选中HitBox节点在检查器右侧的“节点”标签页中找到“body_entered”信号双击它连接到Player节点。这会在player.gd脚本中自动生成一个回调函数_on_hit_box_body_entered(body)。编写碰撞处理逻辑修改player.gd脚本。# 在 player.gd 顶部添加一个信号定义用于通知主场景玩家被击中 signal hit # ... 之前的代码 ... func _on_hit_box_body_entered(body): # 当有物体body进入碰撞区域时触发 # 我们可以检查进入的物体是否是“敌人”Mob但在这个简单游戏中进入区域的只可能是敌人 # 隐藏玩家表示被击中 hide() # 发出 hit 信号 hit.emit() # 必须禁用碰撞检测否则玩家隐藏后碰撞区域仍在会连续触发信号 $HitBox/CollisionShape2D.set_deferred(disabled, true) func start(pos): # 这个函数由主场景调用用于在游戏开始或重生时重置玩家状态 position pos show() $HitBox/CollisionShape2D.disabled false在主场景中响应玩家被击中回到main.gd脚本我们需要连接玩家的hit信号并处理游戏逻辑如减少生命值、判断游戏结束。# 在 main.gd 中添加一个变量来跟踪生命值 var lives: int 3 func _ready(): # ... 之前的连接代码 ... # 连接玩家的 hit 信号 $Player.hit.connect(_on_player_hit) # ... 其他初始化 ... func _on_player_hit(): lives - 1 # 更新UI中的生命值显示稍后实现 # $UI/LivesLabel.text str(lives) if lives 0: game_over() else: # 玩家还有生命重置玩家位置并给予短暂无敌时间可选 $Player.position $StartPosition.position $Player.start($StartPosition.position) # 可以在这里添加一个短暂的无敌闪烁效果 func game_over(): # 停止所有计时器 $MobTimer.stop() $ScoreTimer.stop() # 可以显示“游戏结束”UI并提供一个重新开始的按钮 # $UI/GameOverScreen.show()5.2 构建游戏用户界面UIUI是玩家与游戏交互的窗口。我们将创建一个简单的HUD来显示分数和生命值。在Main场景的UI(CanvasLayer) 节点下添加一个Control节点重命名为HUD。Control节点是所有UI元素的基类。在HUD下添加两个Label节点分别重命名为ScoreLabel和LivesLabel。在2D视图中使用顶部工具栏的“布局”菜单将ScoreLabel锚点设置为“左上”并调整边距将其放在屏幕左上角。将LivesLabel锚点设置为“右上”放在屏幕右上角。在检查器中为这两个Label设置大一点的字体、颜色使其清晰可见。你还可以添加一个Button节点作为“开始游戏”按钮以及一个包含“游戏结束”文字和“重试”按钮的PanelContainer或VBoxContainer节点作为游戏结束界面。将这些元素组织好并默认隐藏游戏结束界面。编写UI控制脚本为HUD节点创建一个脚本scripts/hud.gd用于更新UI元素和响应按钮点击。extends CanvasLayer # 定义信号用于通知主场景UI上的操作 signal start_game # 引用UI元素 onready var score_label: Label $ScoreLabel onready var lives_label: Label $LivesLabel onready var start_button: Button $StartButton onready var game_over_screen: Control $GameOverScreen onready var final_score_label: Label $GameOverScreen/FinalScoreLabel func update_score(score: int): score_label.text str(score) func update_lives(lives: int): lives_label.text str(lives) func show_game_over(final_score: int): final_score_label.text Score: %s % final_score game_over_screen.show() func _on_start_button_pressed(): # 隐藏开始按钮发出开始游戏信号 start_button.hide() start_game.emit() func _on_retry_button_pressed(): # 隐藏游戏结束界面重新发出开始游戏信号 game_over_screen.hide() start_game.emit()在主场景中集成UI修改main.gd连接UI信号并在游戏状态变化时更新UI。# main.gd var score: int 0 func _ready(): # ... 之前的连接 ... # 连接UI信号 $UI/HUD.start_game.connect(new_game) # 初始化UI $UI/HUD.update_score(score) $UI/HUD.update_lives(lives) # 显示开始按钮 $UI/HUD.start_button.show() func _on_score_timer_timeout(): score 1 $UI/HUD.update_score(score) func _on_player_hit(): lives - 1 $UI/HUD.update_lives(lives) # ... 后续逻辑 ... func game_over(): $MobTimer.stop() $ScoreTimer.stop() $UI/HUD.show_game_over(score) # 清理所有现存敌人可选 get_tree().call_group(mobs, queue_free) func new_game(): # 重置游戏状态 score 0 lives 3 $UI/HUD.update_score(score) $UI/HUD.update_lives(lives) $UI/HUD.start_button.hide() # 重置玩家 $Player.start($StartPosition.position) # 清理旧敌人 get_tree().call_group(mobs, queue_free) # 启动计时器 $MobTimer.start() $ScoreTimer.start()5.3 添加音效与背景音乐声音是游戏体验的重要组成部分。Godot支持.wav和.ogg格式推荐.ogg压缩率高。将背景音乐和碰撞音效文件放入audio文件夹。添加音频播放器节点在Main场景根节点下添加两个AudioStreamPlayer节点分别重命名为BackgroundMusic和HitSound。配置音频流选中BackgroundMusic在检查器的Stream属性中加载你的背景音乐文件如background_music.ogg并勾选Autoplay。对于HitSound加载碰撞音效文件如hit.wav不要勾选Autoplay。在代码中触发音效在main.gd的_on_player_hit()函数中添加播放音效的代码。func _on_player_hit(): lives - 1 $UI/HUD.update_lives(lives) # 播放被击中音效 $HitSound.play() # ... 后续逻辑 ...注意事项音效文件不宜过大。背景音乐可以循环播放在项目设置的音频总线中可以调整主音量、音乐总线和SFX总线的音量实现混音控制。对于短促的音效如击中声确保其音频文件本身没有开头静音否则播放会有延迟感。可以使用$HitSound.finished.connect(some_function)来监听音效播放完毕事件如果需要执行后续操作。6. 项目调试、优化与发布准备6.1 常见问题与调试技巧在开发过程中你几乎一定会遇到各种问题。以下是一些常见坑点及其解决方法角色移动不流畅或抖动检查确保移动逻辑在_physics_process中并且使用了delta参数进行与帧率无关的速度计算本例中我们通过move_and_slide()内部处理速度单位是像素/秒所以直接使用即可。如果手动计算位置position velocity * delta则必须用delta。检查在项目设置中确保物理帧率“项目”-“项目设置”-“物理”-“公共”-“物理FPS”是60默认值且Vsync已开启。检查碰撞形状是否与精灵图匹配不匹配可能导致移动时卡在边缘。碰撞检测不生效检查碰撞双方的CollisionLayer和CollisionMask是否设置正确在检查器中确保玩家的HitBox (Area2D)的Collision Mask包含了敌人所在的层例如第1层而敌人的CollisionBody2D的Collision Layer也在第1层。Godot的碰撞检测基于层和掩码的位运算。检查碰撞形状是否可见在调试时可以点击2D视图左上角的“调试”菜单勾选“可见碰撞形状”这样碰撞区域会以彩色轮廓显示。检查信号连接是否正确确保body_entered信号已连接到正确的函数。敌人生成位置或方向异常检查PathFollow2D的rotation模式。默认是“继承”Inherit会跟随路径旋转。确保在代码中计算方向时考虑了这一点。调试在_on_mob_timer_timeout函数中添加print语句输出生成位置、目标位置和计算出的方向观察数值是否合理。游戏运行后窗口大小/缩放不合适设置进入“项目”-“项目设置”-“窗口”可以设置初始窗口大小如 1024x600以及拉伸模式。对于像素风或固定布局的游戏拉伸模式Stretch Mode选择“canvas_items”拉伸方面Stretch Aspect选择“keep”或“keep_width/height”。使用“输出”面板和“调试器”print()是你最好的朋友。在关键位置打印变量值。当脚本出错时错误信息会显示在“输出”面板点击可以跳转到错误行。使用调试器的断点功能可以暂停游戏检查当前所有变量的状态。6.2 性能优化浅析虽然《Dodge the Creeps!》很简单但养成良好的优化习惯很重要。实例化与队列释放我们使用instantiate()创建敌人实例用queue_free()销毁它们。当敌人移出屏幕后应该销毁以释放资源。可以在mob.gd的_physics_process中添加边界检查。# mob.gd func _physics_process(delta): move_and_slide() # 简单检查如果位置远超出屏幕例如超出1000像素则自我销毁 if position.x -1000 or position.x get_viewport_rect().size.x 1000 or position.y -1000 or position.y get_viewport_rect().size.y 1000: queue_free()使用节点组Groups我们之前用get_tree().call_group(mobs, queue_free)来清理所有敌人。你需要将每个Mob实例添加到“mobs”组。可以在mob.gd的_ready()函数中添加add_to_group(mobs)。资源预加载我们在main.gd中使用preload()预加载了敌人场景。对于频繁使用的资源预加载可以避免运行时卡顿。绘制调用Draw Calls对于2D游戏过多的精灵图尤其是不同纹理会增加绘制调用。如果敌人有多种外观考虑使用AnimatedSprite2D配合精灵表Sprite Frames或者使用TextureRect配合图集AtlasTexture这比多个独立的Sprite2D效率更高。6.3 项目导出与分享完成开发后你可能想分享给朋友或发布到 itch.io 等平台。导出模板首次导出前需要下载导出模板。点击编辑器顶部“项目”-“工具”-“下载导出模板”。选择你的目标平台如 Windows Desktop, macOS, Linux, HTML5Godot会下载对应的模板文件。配置导出预设点击“项目”-“导出...”。在“导出”窗口中点击“添加...”选择目标平台如“Windows Desktop”。关键配置应用程序/名称你的游戏名字。图标为不同尺寸设置应用图标。功能对于桌面端通常保持默认即可。对于WebHTML5需要注意初始画布大小和内存限制。资源确保你的所有场景、脚本、图片、音效都包含在“资源”列表中通常默认包含项目目录下所有文件。你可以通过“过滤器”排除开发用的测试文件。执行导出选择一个输出目录和文件名点击“导出项目”。Godot会打包你的游戏为一个可执行文件如.exe或一个HTML5包包含.html,.pck等文件。测试导出包务必在导出后在目标平台或虚拟机上运行测试确保所有功能正常资源没有丢失特别是音效和字体。最终检查清单在导出前请确认1) 游戏主场景已设置“项目”-“项目设置”-“应用”-“运行”-“主场景”2) 所有资源路径正确没有使用绝对路径3) 移除了所有调试用的print语句和测试代码4) 对最终版本进行了全面的游戏性测试。从零开始我们一步步搭建了《Dodge the Creeps!》的每一个模块场景结构、玩家控制、敌人生成、碰撞逻辑、UI交互和音效。这个过程几乎涵盖了2D游戏开发的所有基础环节。Godot 4.2的节点式架构和GDScript的简洁语法让原型实现变得非常快速。最重要的是通过亲手解决每一个遇到的问题无论是碰撞失效、坐标计算错误还是信号连接不对你对引擎和游戏开发逻辑的理解会远远超过单纯阅读文档。这个项目可以作为你Godot之旅的坚实起点在此基础上你可以尝试添加更多功能比如不同类型的敌人、武器和射击、关卡设计、更复杂的UI、本地化支持等等。Godot社区非常活跃遇到难题时官方文档、QA和论坛是绝佳的资源。