一天零基础用Godot做了个游戏,随便写点
前言
五一期间花了一天时间用Godot做了个游戏,想记录点什么。本来五一期间就该写这篇博客的,奈何本人有些拖延,拖着拖着就拖了半个月才想着写。再回看自己的博客,发现已有接近有一年没有写了,不知不觉时间过得真快,稍不留神竟然已经过了这么久了,想想真是有些惭愧。
其实我之前是从没听过Godot的,游戏引擎我之前只知道Unity、UE、Cocos、Pygame这些,不知什么时候横空出世的Godot。五一期间在刷B站时,我无意间刷到Unity又变更条款的消息,Unity6不让中国用了,中国只能用特供版,也就是团结引擎,特供版和国际版未来会独立发展。然后就了解到了开 源游戏引擎Godot的存在,于是就想挑战自己一下,一天时间零基础用Godot做一个简单的游戏,结果基本上做到了。
游戏下载链接 ,提取码: teiv
代码已开源:https://github.com/straicat/demo-projects/tree/master/color-square
玩法
游戏玩法我是参考《鸣潮》中的小游戏“溢彩画”,但是由于是零基础一天时间,所以界面做得很简陋,而且我是后端开发并不会美术。游戏界面如图:
点击右侧的颜色块拾取颜色,然后点击中间的颜色块,将该颜色块和与之连接的颜色块都染成拾取的颜色,要求在规定的步数内完成相应的染色要求。
怎么做到的
我是先在Youtube上看了一个快速入门教程,对Godot有了一个简单的整体印象,了解了Godot中的场景、节点等概念。然后就开始做了,做的过程中也并没有使用Cursor这种工具,而只是依赖DeepSeek-v3。不过,因为Godot使用gdscript语言,这门语言挺冷门的,网上资料很少,API还有变化,故而在做的过程中不仅需要反复问AI进行纠错,还需要有自己的一些判断。
与后端开发不同的是,使用游戏引擎做游戏不只是写代码,还涉及一些引擎的图形化界面操作。对于Godot,需要创建节点、为节点创建脚本、在检查器面板设置节点属性等。但是,DeepSeek又只会输出一些文字,这些界面操作一般需要自行完成,不过好在这些比较简单。
遇到的问题
遇到的第一个问题就是点击不同颜色色块没反应,并不会进行染色。经过反复地询问DeepSeek才知道,色块需要设置mouse_filter
以允许接收鼠标事件,然后还需要将GUI输入信号连接到色块的事件处理函数。
func _ready():
mouse_filter = Control.MOUSE_FILTER_STOP
gui_input.connect(_on_gui_input)
然后就是节点的引用了,Godot里对于节点的引用有好几种方式,本项目里使用了如下方式:
# 使用导出变量,在编辑器中拖拽赋值
@export var target_node: Node2D
# 直接路径引用,有两种写法。路径引用有相对路径也有绝对路径。
var b= $ColorBoard/Board
var b = get_node("ColorBoard/Board")
然后就是对于信号的处理了,感觉和Qt的信号槽机制很像,不过我也不熟悉Qt。基本用法就是定义一个信号,然后一边emit
,另一边connect
到信号处理函数。例如项目中对于剩余步数的传递:
# board.gd
signal step_update(step: int)
func _on_block_clicked(pos):
# ...
step_update.emit(remain_step)
# main.gd
@onready var step_label = $Step
@onready var board = $ColorBoard/Board
func _ready():
board.connect("step_update", _on_step_updated)
func _on_step_updated(step):
step_label.text = "[font_size=24]还剩 [color=red][b]%d[/b][/color] 步[/font_size]" % step
Godot中的富文本Node使用的是BBCode来实现富文本。
除了通过代码的方式显式连接信号,Godot还可以在图形化界面上配置信号的连接。在节点面板的信号选项卡,选择一个信号,右键选择“连接...”,Godot会自动生成一个信号处理函数名,点击连接后即完成了信号的连接。
由于各Node需要初始化,然后Node之间可能有引用关系,如果引用的Node尚未初始化,就会出现空指针。Godot的_ready()
调用顺序是从场景树的叶子节点到根节点。如果想延迟执行可以使用call_deferred
:
# board.gd
func _ready():
call_deferred("init_config_show")
func init_config_show():
# ...
做完了游戏主界面后,我还想做一个选关界面,故而又涉及场景的切换,或者说场景的管理。项目中用到了两种方式:
- 第1种是初始化节点、添加节点,然后释放当前节点。这种方式可以进行参数的传递
- 第2种是使用
change_scene_to_file
# 第1种
var main_scene = preload("res://scenes/Main.tscn").instantiate()
# 传递参数
main_scene.selected_level = selected_level
get_tree().root.add_child(main_scene)
queue_free()
# 第2种
get_tree().change_scene_to_file("res://scenes/LevelSelect.tscn")
queue_free()
对于第2种,一些文档说旧场景默认会被自动释放,但我实测又没有释放,因此还是加上了queue_free
才正常,可能旧场景的释放是惰性的,并不会立即释放。
最后就是布局与样式了,不过本项目并不在意外观,所以这一部分涉及的比较少。
总结
总的来说,Godot游戏引擎还是比较好上手的。但是,Godot的资料偏少,教程与文档质量一般,gdscript语言也不主流。在国内,Godot似乎用的公司很少很少,几乎没有。所以,如果是感兴趣自己做游戏的话,倒是可以用一下Godot的,感觉类似于Qt,但是找工作的话还是Unity、UE吧,不过我是后端开发并不是游戏客户端~
而且,一款好的游戏还是离不开优秀的美术的,而美术一般是程序员的短板,用素材或AI不太能满足需求。而游戏客户端开发感觉和Windows客户端开发类似,和前端更为接近,和后端技术栈相去甚远。