Godot学习笔记
记录Godot游戏引擎的学习
本文章长期更新(最后更新于2026.4.28)
前言
古人有云,温故而知新,学习做笔记
考虑到应该学习一点其他东西了,所以打算学习Godot引擎做出全宇宙爆款的胎死腹中音乐游戏,这个是古话了
其实在选择学什么之前,也在考虑是选择Godot还是市场占有率更高的Unity. 但是Godot有以下吸引我的点
- 看着性能占用不高
Unity给我的感觉是很重型。假设我要做一个项目,我要启动Unity Hub,再启动Unity,然后启动Visual Studio. 要打开的东西很多,无法保证我的便携电脑能带的动。而Godot是一个绿色软件,看着很轻量化。
- GDScript看着更容易上手
因为目前所规划的想做的游戏基本都是2D游戏,虽然说还有像Cocos2D这样的专业选手,但是我的C++水平基本等于没有,Java目前是起步阶段,C#的学习看着也比较曲折。
Godot的原生编程语言GDScript以近似Python一样的简便而闻名。实际体验也确实容易理解。没准GDScript学会了还能点下Python技能树。
- Unity经常做妖
我懒得对这一条进行解释。
其他的暂时没想出来,我还没有达到从技术方面对他们进行剖析的水平。如果未来水平足够或者需求提高,再考虑学习其他引擎
本文基于Clear Code的《Godot4终极入门教程》,在这里附上B站链接。
关键概念
节点
节点 (Node) 是Godot的一个重要的概念。场景是一个节点,玩家是一个节点,很多东西都是节点。整个Godot就是一个节点大世界。
在Godot中基本要做的就是制作各种节点然后将他们联系在一块,个人感觉可以将它们视作多个对象。
图为Godot的主界面,按下Ctrl + A来增加新的节点。
节点使用帕斯卡命名法,即每个单词首字母大写。而其他内容使用蛇形命名,即所有字母小写,用下划线链接。Godot会自动帮你做好这些内容。
节点具有图层优先级,类似于Ps,越往下面图层就会越优先。
父节点与子节点
节点具有包含关系。可以将一个节点B归属到另一个节点A. 此时A为B的父节点,反之为子节点。
父节点中对属性的改变都会对子节点造成影响,而反之不然。
可以右键选择父节点增加子节点。如果要把已有的节点作为子节点,按下Ctrl + Shift + A或者点击“实例化子节点”选项,将会列出所有可以作为子节点的其他节点
语言
Godot的原生语言为GDScript,虽然宣传说的是类似Python,但准确来讲,他就是Python. 除了部分关键词有区别外,其他的基本如出一辙。
游戏中的所有属性都可以在属性面板中找到,将鼠标选在其上方将会自动显示对应的变量名称。
由于Markdown没有原生GDScript支持,所以代码块将会使用Python.
语言特点
数据类型:常见的数据类型都有覆盖,数组覆盖了元组和列表。
两种变量:普通变量和常量
普通变量格式:
1
2var name = 200 #直接赋值的一般格式
var names: int = 114 #指定数据类型的格式常量格式:
1
const value = 200 #直接赋值的一般格式
函数:用来实现功能
Python应该用的是
define作为函数关键词,但GDScript中使用func作为关键词。格式如下所示1
2func name_here(vari a: int) -> bool #括号里透数据类型,箭头指定返回类型
return true #首行缩进说明其仍然属于函数中流:包括if-else,for-while循环,continue-break,数学运算,数值比较等
类:和我的想法差不多,有功能的节点可视为一个类
内置函数
游戏默认有两个内置函数,且都以下划线开头。两个函数如下所示
1 | func _ready() -> void: |
_ready,我打算叫他预备函数,在节点准备好后就会开始运行
_process,我打算叫运行函数,游戏每帧都会执行
在父节点中可能会更改子节点的属性。有两种方式可以调用
1 | get_node("node path") |
输入后,自动补全会列出所有可用的子节点。
关于GDScript更详细的学习内容,可以查看我发布的另一篇基于Brackeys的快速入门GDScript课程的笔记
增量时间(Delta)
上文提到了运行函数是每帧执行的操作,但这也带来一个问题。
假设一个物体每帧移动10个像素,在30帧/秒内将会移动30 * 10 = 300像素。但如果我用的是神威太湖之光来打游戏,帧数可能会到60帧,120帧甚至3000帧/秒,那么这个物体将会移动600个像素甚至更高,而过高的移动速度会让游戏根本没法玩。
我刚好遇到一个例子,就是在我的电脑上玩DJMAX TECHNIKA 2时,倒计时会数的很快。查了贴吧之后才知道这是因为该游戏原先为街机开发,用的是一块60Hz的触摸屏。而我的电脑屏幕刷新率很高,从而导致运行速度过快
因此,为了解决在不同帧率的机器上有一致的运行速度,我们需要一个统一的时间间隔,而这就是增量时间
增量时间为创建一帧所需要的时间。例如30帧的增量时间就是1s / 30f ≈ 0.0333
具体的使用如表格所示
| 速度 (每帧像素) | FPS | 间隔时间 (秒) | 原运动 (每秒) | 间隔运动 (每秒) |
|---|---|---|---|---|
| 10 | 30 | 1 / 30 = 0.033 | 10 * 30 = 300 | 10 * 30 * 0.033 = 10 |
| 10 | 60 | 1 / 60 = 0.017 | 10 * 60 = 600 | 10 * 60 * 0.017 = 10 |
| 10 | 120 | 1 / 120 = 0.008 | 10 * 120 = 1200 | 10 * 120 * 0.008 = 10 |
可以看到,增量时间就是与原来的运动速度相乘,从而抵消以实现原来的运动速度
在具体的代码中,将需要的量与delta相乘
1 | pos.x += speed * delta |
后续的很多函数中会在构建中自动运用增量式案的运动,所以不用一直考虑增量时间,不过,这仍然是一个重要的概念
获取输入
这一部分在GDScript笔记中亦有记载,这里复制粘贴一下
要获取输入有两个步骤:
- 创建映射事件
首先打开项目 - 项目设置 - 输入映射
建立新的映射之后按下加号,绑定键位。这里采用视频所给出的案例:创建一个名为my_action的事件,内容为按下空格键就会改变Label的颜色
- 脚本调用映射事件
用于按键绑定的系统函数**_input**函数格式如下
1 | func _input(event): |
值得一提的是,按下有两个函数,is_action_pressed和is_action_just_pressed. 核心区别就在于前者会一直检测按下的状态,而后者只检测第一次按下
有一个函数在搞2D游戏时用起来挺不错,即Input.get_vector,参数顺序通常为(negative_x, positive_x, negative_y, positive_y),在Godot体系中是左右上下。每次执行都会在对应的参数上+1
可以参考以下代码
1 | # 设置direction变量,调用函数 |
更多节点该怎么办
唯一名称访问
假设出现了复杂的场景,节点也将层层嵌套。如果直接将这个节点拖进编辑器,路径会很长。
如果这个节点很独特,可以右键点击选中“作为唯一名称访问”
节点之间互相访问
在Godot中,最重要的就是节点之间能调用属性,因此需要掌握他们链接的方法
(待完善)
物理
前面的环节都在讲移动一个精灵,但是在游戏中,精灵和精灵之间肯定会有碰撞,还会有专门的墙体限制精灵活动,这就需要用到物理属性了
物理是游戏运动的基础,图像本身没有碰撞属性,必须使用碰撞体和物理体节点(如Area2D、PhysicsBody2D)来处理物理交互。
CollisionObject和 PhysicsBody是物理属性中的基础。在PhysicsBody中包含了三个属性。其作用如下表所示
| 名字 | 定义 | 作用 |
|---|---|---|
| StaticBody | 静态碰撞体 | 不能自己移动,但其它物体可与其碰撞 |
| CharacterBody | 代码操控实体 | 由代码驱动的玩家或敌人,通过内置方法实现复杂移动 |
| RigidBody | 物理实体 | 仅通过物理力量移动(如手榴弹等),给定初速度即可移动 |
| Area | 检测区域 | 检测其他物体是否进入 |