我的第一个开源项目:
用Godot 4.3从零开发2D游戏《丛林探险》
从安装引擎到发布网页版,一名开发者的完整创作手记
引言:为什么选择Godot?
作为一名对游戏开发充满兴趣的程序员,我一直在寻找一个轻量、开源、功能完备的游戏引擎。在尝试了Unity、Unreal等主流引擎后,我最终选择了Godot。它不仅完全开源,还拥有极其清晰的节点化场景结构和友好的脚本语言GDScript,特别适合独立开发者和小团队快速原型开发。
在这篇文章中,我将分享我使用Godot 4.3开发的第一个完整2D游戏项目------《丛林探险》的完整开发历程。从环境搭建、场景构建、代码编写,到最终发布为可执行文件和网页版,希望我的经验能帮助更多初学者迈出游戏开发的第一步。
一、项目架构与场景设计
1.1 场景树的组织
Godot的核心设计理念是"一切皆节点"。在《丛林探险》中,我构建了如下主要场景:
-
主场景(Game):包含背景、玩家、敌人、空气墙等
-
玩家场景(Player):独立封装玩家逻辑与动画
-
敌人场景(Slime):史莱姆敌人行为与受击逻辑
-
子弹场景(Bullet):发射物行为与生命周期管理
-
UI场景(CanvasLayer):得分与游戏结束界面
这种模块化设计使得每个部分都可以独立测试和复用。
1.2 节点的选择与用途
我使用了多种类型的节点来构建游戏逻辑:
-
CharacterBody2D
:用于玩家,支持物理移动与碰撞 -
Area2D
:用于敌人和子弹,用于检测区域重叠 -
Sprite2D
/AnimatedSprite2D
:静态与动态图像渲染 -
Camera2D
:控制视角与渲染范围 -
Timer
:循环任务与延时触发 -
AudioStreamPlayer
:音效与背景音乐播放
二、GDScript:Godot的灵魂语言
Godot支持多种脚本语言,但我选择了原生支持的GDScript。其语法类似Python,简洁易懂,特别适合快速开发。
2.1 玩家移动与控制
以下是玩家移动的核心代码片段:
gdscript
@export var move_speed: float = 100
var velocity: Vector2 = Vector2.ZERO
func _physics_process(delta):
if not is_game_over:
velocity = Input.get_vector("left", "right", "up", "down") * move_speed
move_and_slide()
通过Input.get_vector
获取键盘输入,并结合move_and_slide()
实现平滑移动。
2.2 动画状态机
我使用AnimatedSprite2D
配合代码实现了玩家的动画切换:
gdscript
func _physics_process(delta):
if velocity == Vector2.ZERO:
$AnimatedSprite2D.play("idle")
else:
$AnimatedSprite2D.play("run")
2.3 信号系统:Godot的事件驱动机制
Godot的信号(Signal) 机制非常强大。例如,我在史莱姆中使用了body_entered
信号来检测玩家碰撞:
gdscript
func _on_body_entered(body):
if body is CharacterBody2D and not is_dead:
body.game_over()
三、游戏机制实现详解
3.1 敌人生成与难度递增
我使用GameManager
脚本控制敌人的生成与难度曲线:
gdscript
@export var slime_scene: PackedScene
@onready var spawn_timer: Timer = $Timer
func _on_timer_timeout():
var slime = slime_scene.instantiate()
slime.position = Vector2(265, randf_range(52, 116))
get_tree().current_scene.add_child(slime)
func _process(delta):
spawn_timer.wait_time = clamp(spawn_timer.wait_time - 0.2 * delta, 1.0, 3.0)
随着游戏进行,生成间隔从3秒逐渐缩短至1秒,提升游戏挑战性。
3.2 子弹发射与对象池优化
子弹发射使用了PackedScene.instantiate()
动态生成,并通过Timer控制发射频率。为了避免内存泄漏,每个子弹在3秒后自动销毁:
gdscript
func _on_fire():
if velocity != Vector2.ZERO or is_game_over:
return
var bullet = bullet_scene.instantiate()
bullet.position = position + Vector2(6, 6)
get_tree().current_scene.add_child(bullet)
四、UI系统与全局状态管理
4.1 得分系统
得分逻辑通过GameManager
统一管理,并在UI中实时更新:
gdscript
@export var score: int = 0
@export var score_label: Label
func _process(delta):
score_label.text = "Score: " + str(score)
4.2 游戏结束画面
当玩家失败时,通过信号通知GameManager
显示游戏结束UI:
gdscript
func show_game_over():
game_over_label.visible = true
五、音效与背景音乐
Godot的AudioStreamPlayer
节点让音效集成变得非常简单。我分别为开枪、跑步、死亡等动作配置了音效,并通过代码控制播放时机:
gdscript
func _on_fire():
$FireSound.play()
背景音乐使用AutoLoad功能实现跨场景持续播放,避免重启时音乐中断。
六、导出与发布
6.1 多平台导出设置
Godot支持一键导出到Windows、Linux、macOS、HTML5等平台。我在项目中配置了两种导出预设:
-
Windows(.exe):适合本地分发
-
Web(HTML5):适合在线游玩
6.2 上传至itch.io
我将Web版本打包为ZIP文件,上传到itch.io,并设置为"HTML5项目"。任何人都可以在浏览器中直接体验我的游戏。
七、总结与展望
通过这个项目,我不仅掌握了Godot引擎的基本用法,还深入理解了2D游戏开发的核心流程。Godot的节点化设计、GDScript的简洁性、信号系统的高效性,都让我对开源游戏引擎的未来充满信心。
如果你也想尝试游戏开发,我强烈推荐从Godot开始。它不仅是免费的,更是强大的、开放的、充满可能性的。
项目源码已开源,欢迎Star & Fork:
https://gitcode.com/Brianna_Home/my-frist-game
附录:技术栈总结
-
引擎:Godot 4.3 Stable
-
语言:GDScript
-
素材:自制像素图 + 免费音效
-
导出平台:Windows, Web (HTML5)
-
发布平台:itch.io
希望这篇文章能为你打开Godot游戏开发的大门。如果你有任何问题,欢迎在评论区留言交流!