Godot Start
-
godot engine utils and sample, example, demo, tutorial, learning, course
-
目前这个项目可以在 godot 3.3,3.4,3.5中运行,不支持godot 4.x(正式版本发布才考虑支持)
-
这是一个关于godot的基本使用示例和学习教程的工程项目,B站配套视频教程
-
godot start学习交流qq群,710511812
视频文档修正补充
4.安装和HelloWorld
- 建议再看看底61集的视频,黑白控制台是否隐藏,学会调整运行时候的屏幕位置,避免运行时候屏幕位置出现问题
在线书籍地址:
https://eninix.github.io/godot-start/book/index.html
godot start项目下载
-
github
-
为了防止github时不时被墙,可以把git设置一个代理,科学上网
git下载代码慢的解决方法|无法下载代码的解决方法
git config --global http.proxy http://127.0.0.1:10809
git config --global https.proxy https://127.0.0.1:10809
- godot start学习交流群,710511812
为什么选择godot,而不选择cocos, unity, ue
-
godot比cocos, unity, ue简单,更加易上手
-
godot和cocos对比
- godot的源代码比cocos的源代码少一倍,所以godot源代码更加的简洁,简洁的代码更容易学习底层原理
- cocos主要都用在2D方面,2D方面godot支持的更加全面
- GDScript比JavaScript更加简单,因为GDScript是定制过后的语言
-
godot和unity对比
- unity代码不开源,但是即使开源unity的源代码体积绝对大于godot一倍以上
- godot安装包50M,unity安装几个g
- 目前2d方面godot优于unity,3d方面unity优于godot,godot4.0有望大大缩小和unity的差距
- GDScript学起来也比unity的C#和Lua简单
大部分使用unity的开发人员都在使用Lua做开发,虽然unity官方说的是用C#,但是C#不能热更新,所以实际上工作用的大部分使用的是能够热更新的Lua 比如原神就有用到Lua来去做热更新 现在需要频繁更新的功能,比如活动,在王者荣耀中这些活动大部分都是用h5页面去做了,这个只需要JavaScript就可以了,比较完美和超前的解决方案 所以unity的语言比较杂,用C#,Lua,Javascript都有可能 GDScript兼顾性能的同时,还带来比较简洁的语法,还可以热更新。 因为godot只需要用一个GDScript语言,所以远远比unity简单
-
godot和ue对比
- 自主可控(避免被“卡脖子”),从开源软件的角度分析,godot是游戏引擎界的Linux,ue和unity算是Windows
- ue虽然开源源代码,但是代码量太大,历史包袱太重,不适合深入研究底层代码的人
-
godot的作者尽最大努力的减少第三方库的依赖,最终使其代码非常精简,适合学习
-
源代码开源,不收费,unity和ue都是要收费的,ue超过100万美元触发5%的分成费用
-
使用godot你既可以用GDScript去编写代码,也可以用C++去编写代码,还可以去改底层引擎代码
-
用godot你能感觉我能把控底层,我能把控每一行代码的底层细节,这个是程序员的浪漫,godot在国外比较火是有原因的
为使用godot我应该选择什么语言,C# or GDScript
- GDScript快速加载无需编译,无任何等待
- GDScript有内置的高性能类型入Vector,更加有效率
- GDScript多线程支持更加友好,其它脚本多线程支持很差
- GDScript直接由godot内置引擎解析
- GDScript没有gc,没有垃圾回收器,C#带GC垃圾回收器的语言虽然也是内存安全的,但由于GC的存在,已与底层无缘
- gds更加简单,支持的更加完整,而且是脚本可以热更新
- C#很多库用不了,有限制,如果是为了性能可以在godot中使用C++
- 通过学习GDScript也可以学到一些编译原理的知识
- godot不仅仅是一个游戏引擎,而且还是一个优质的学习资源
- C#对于godot来说比较重,推荐gds
参考资料
1. godot的界面介绍
侧面分栏(Dock)
-
点击侧面分栏的右上角可以调整分栏的位置
-
左侧面分栏具体包括:
- 文件系统(FileSystem),显示了当前项目中所有的资源文件
- 导入(Import),显示了文件系统分栏中所选资源文件的导入设置。
- 场景(Scene),按照层级结构显示当前场景中的所有节点,可以简单的理解为一个游戏里的场景/关卡
-
右侧面分栏具体包括:
- 属性(Inspector),显示了场景分栏中所选节点的属性。
- 节点(Node),显示了与当前场景分栏中所选节点对应的一些“信息”。
中间面板:
-
主工作区(Workspace)
- 2D,当在场景分栏中所选节点为2D类型时,会自动进入此工作区。
- 3D,当在场景分栏中所选节点为3D类型时,会自动进入此工作区。
- 脚本(Script),此工作区可以对当前项目中的脚本进行编辑。
- 资源库(AssetLib),可以搜索并浏览网站上的资源
-
底部面板(Bottom Panel)
- 隐藏
-
与Unity和UE4不同的是:Godot这种布局关系当前是相对固定的,即它不能随意调整任意一个面板的位置或脱离成独立的窗口。虽然这看似是一个缺点,不过从某种程度上讲也让引擎变得更简单了。
-
如果布局乱了,恢复一下就可以了,Editor | Editor Layout | Default
2. 场景和资源
- 场景 Scene ,就是一个游戏里的场景 / 关卡
- 创建场景,在res面板的文件夹下右键,New Scene创建场景
- 资源 Asset,指游戏里用到的素材、脚本等数据文件
比如,常用的几种类型:
Texture 图片素材 ( *.jpg / *.png)
Audio音频素材 ( *.mp3)
程序脚本GdScript ( *.gd)
- 可以对素材执行删除 Delete 、重命名 Rename 等操作
3. 场景视图和游戏视图
-
场景视图Scene ,即场景编辑器窗口,默认地,创建了一个场景empty
-
鼠标滚轮 :放大/缩小视图
-
鼠标右键拖拽:平移视图
-
网格,每一个大网格包括8*8的小网格,每个小网格8个像素
每一个小格子为:8像素 x 8像素
每一个大格子为:64像素 x 64像素
-
场景视图中的蓝色框区域是可见的范围,对应的就是运行游戏的时候的游戏视图
-
本教程所有的每节课都很简单,这是因为对godot的知识做了拆解,把复杂的知识拆解为一个一个简单的知识点
-
然后把每个简单的知识点单独作为一节课,所以整个课程的难度是一种渐进式的
-
复杂的东西都是由一个一个简单的知识构成的,不要觉得课程简单,如果简单的东西不熟练不练习,后面的课程很可能会跟不上
4. 游戏对象(节点)
-
游戏对象 Node,就是场景中包含的内容,godot所有操作都是基于节点Node
-
演示:向Scene窗口里添加几个图片
1 准备图片素材
2 把图片拖到2D游戏场景中
3 在Scene窗口中,观察新加的游戏对象
- 游戏对象的简单操作:
1 选中游戏对象
从左侧的层次管理器(Scene窗口)中选中游戏对象
2 移动游戏对象
选用移动工具,拖动小方块
3 修改对象名字
在Scene窗口中,可以修改名字、删除对象等操作
5. 坐标系
- 选择移动工具,移动一个对象
- 可以通过鼠标去移动游戏对象,也可以通过键盘方向键移动游戏对象,也可以手动修改position的坐标x和y去更加精确的移动对象
在 Inspector 属性面板:
观察对象的坐标 Position: x, y
可以发现,对象的坐标会随之变化
- 世界坐标系,又称为全局坐标系
y轴向下为正
x轴向右为正
一个像素在真实世界中,可以自行约定,比如约定1像素=1米
-
相对坐标系,又称为局部坐标系或者本地坐标系,相对于父节点的坐标,godot的坐标都是相对坐标
-
全局坐标和局部坐标可以相互转化
Node2D及其子节点的位置可以使用position和gloabl_position来控制,其中,前者是该节点相对于父节点的相对位置,后者是全局位置。
简而言之,position的坐标系是以父节点的位置坐标为原点的坐标系,方向,还是水平向右为x轴正方向,竖直向下为y轴正方向。
需要注意的是,全局位置是以场景的root节点为原点的,并不是以根结点的位置作为原点的
6. 节点的基础操作
- Q,选择工具,最强大的工具
Alt + 拖曳边框缩放点,保持选中目标中心位置不变进行缩放
Shift + 等比列缩放
Ctrl + 鼠标拖曳,以pivot为中心旋转当前对象
- W,移动工具,改变 Position
Move Mode 对象的移动:
单独改变X坐标
单独改变Y坐标
拖拽中间的方块,可以任意拖动
也可以直接在 Inspector 中输入坐标,会更精确一些
- R,旋转工具,改变 Rotation
轴心点,又称中心点,是节点的旋转中心
V,移动轴心点,Shift + V 拖拽轴心点
中心点是一个物体的中心,当我们对物体进行操作的时候,都是以中心点为中心进行对物体的操作
轴心点可以理解为把物体抽象成一个点,物体的位置就是指其轴心点的位置,就是该物体坐标系的原点
后面的课程会继续介绍轴心点
Rotate Mode 对象的旋转
沿轴心点旋转
- S,缩放工具,改变 Scale
Scale Mode 对象的缩放
沿 X 轴缩放
沿 Y 轴缩放
拖拽中间的小方块,X 和 Y 等比例缩放
- F,居中选取对象,非常有用的快捷键
7. 节点操作的工具,多节点选择,轴心点,平滑,尺子
- 多节点选择工具,show a list,主要用来精确选择层叠在一起的节点
- 轴心点工具,移动轴心点,和选择工具中的快捷键V有同样的作用
- 平滑工具,固定场景
- 尺子工具,量图片或者节点的像素
8. 智能对齐Snap和锁定节点
- 智能对齐,Smart Snap
- 网格对齐,Grid Snap
- 锁定节点,使其不能移动
- 子节点不可选中
1. 节点的父子关系
-
在层级树中,对象 (节点) 呈树形显示,一个节点下面,也可以下挂子节点
-
演示:
1 添加两个对象
2 拖拽一个对象到另一个对象,成为子对象 (子节点)
3 移动父对象、旋转父对象,观察
可以发现,当父对象移动时,子对象随之移动
- 理解相对坐标
子对象的坐标轴,是相对于父对象的
1 移动父对象时,子对象的 Position 不发生变化
2 旋转父对象时,子对象的 Rotation 不发生变化
2. 节点的显示和隐藏
- 删除游戏对象
右键 Delete ,或者键盘 Delete 均可
- 恢复
CTRL + Z ,撤销上一步操作
- 更改节点对象名字
右键 Rename,或者双击节点修改
- 显示 / 隐藏
在 Inspector 里,勾选 Visible 复选框,或者在节点右侧点击Toggle Visibility
- 设置长宽比
在 Project | Project Settings | Display | Window 中可以设置长宽比
3. 游戏节点的显示顺序
- 在2D画面中,两个对象如果重叠,谁显示在上面呢?
- 按照节点的顺序
- 在数据结构上的专业术语叫树的广度优先遍历,广度优先遍历的顺序就是最后显示的顺序
4. pivot,轴心点
-
轴心点也叫中心点,中心点是一个物体的中心,当我们对物体进行操作的时候,都是以中心点为中心进行对物体的操作
-
轴心点可以理解为把物体抽象成一个点,物体的位置就是指其轴心点的位置,就是该物体坐标系的原点
-
主要用于旋转和决定对象的位置
-
轴心 Pivot ,指旋转轴、坐标基准点,默认在对象的几何中心
-
轴心的作用:
- 旋转轴,当旋转对象时,是以 Pivot 为轴心来去旋转对象的
- 坐标系的原点,当移动对象时,是以 Pivot 为中心来计算位置Position的
-
添加一个图片,设置其 Pivot 位置,多练习一下,不及小步无以至千里
5. anchor,锚点
- 是一个点,锚点描述的是一个对象的Margin,相对于锚点的坐标
- 锚点的left,top,right,bottom是相对于父节点的值
- 主要是用于描述子节点相对于父节点的位置
- 当对一个节点的子节点进行设置锚点时,子节点的锚点范围只能够是父节点的控件区域内。
- 注意任何布局也都是相对于父窗口矩形的
- 主要用于在GUI中描述子节点相对于父节点的位置
- 后面的课程学到GUI中会继续介绍锚点,现在只做了解
1. 图片素材的准备
-
术语:Sprite 精灵,游戏开发中指一张图片
-
来源不明的图片,切勿在商业用途使用,以免引起版权风险。做一个遵纪守法的好公民。
1. 在学习阶段,可以百度或者从一些资源网站获取,这种方式只能用在学习交流但是无法商用
2. 在正式工作时,公司会有专门的美术人员提供素材
3. 比较大的资源素材商店是是Unity Store
4. 独立开发者可以外包给第三方团队完成
5. 可以从一些素材网站获取正版授权的图片素材,还有一些免版权的网站一样可以获取到
6. 到一些个人外包网站如万能的淘宝或者猪八戒网,外包给大学生或其他找副业赚钱的人
-
推荐几个国外比较好的资源网站,国内的资源网站现在还比较稀缺,需要科学上网
- Untiy Store ,最大的游戏资源网站,可以使用里面的2D图片资源
- craftpix ,国外的一家提供高品质的优质和免费的2D游戏资产的网站
- game dev market ,内容涉及2D、3D、音频和GUI素材,也可以作为一个寻找素材的补充
- kenney ,国外一家做游戏创意原型的资源站
- Fiverr ,一个综合的数字服务提供平台,可以直接在里面找到为我们工作的人,然后他们会提供一些我们定制的服务。
-
一般人很难即精通程序也精通美术,这两种的思维方式不一样。上帝为你打开了一扇门,他同时也很可能关闭了一扇窗户
-
2D 图片的要求:
1 背景图片,一般为 JPG
2 人物、道具等其他图片,一般为PNG ,背景透明
- 演示:PS处理一张图片,去掉背景,做成可用的素材
2. 图片的切割
-
一个 PNG 图片中,可能包含多个素材,使用时需要切割一下
- 第一种方式,将图片用ps之类的工具切割好以后,重新导入godot中使用
- 第二种方式,导入godot中通过Region指定使用的图片,做间接切割
-
一个图片未经切割时,则只包含一个 Sprite素材
3. 图片的合并
-
有时图片太多不好管理,想合并成一整张图片去使用
- 第一种方式,将图片用ps之类的工具合并好以后,重新导入godot中使用
- 第二种方式,在godot中选中多张资源,然后已AtlasTexture的方式重写reimport
-
重写reimport导入过后,也可以把之前的图片删除掉,已节省游戏的包体积和目录文件
4. 图片与渲染器
-
godot是基于节点的,节点有不同的种类,不同种类的节点代表了不同的功能
-
Sprite节点继承于Node2D节点,所以包含Node2D节点的所有属性
-
Sprite节点,用于显示一个Sprite,把一张图片渲染出来
-
节点的种类表示一种功能,而 Sprite 的功能就是显示图片,后面还会说
-
演示和练习:
1 添加一个对象,显示图片1
2 观察 Sprite 的属性值
3 让 Sprite Renderer 更换显示另一张图片,通过拖拽方式或者通过选择文件的方式
4 通过创建一个节点的方式创建Sprite节点
1. 节点和功能的关系
-
节点 Node ,用于实现一种功能,例如,Sprite 节点,用于图片的显示
-
一个节点的功能取决于它挂载了哪些子节点,它包含了哪些功能的子节点,就包含了对应子节点表示的功能
-
节点是可选的,可以添加、可以删除
-
先创建一个空的节点,再选择需要的节点
Sprite用来显示一张图片,再给Sprite增加一个刚体
演示:
1 添加一个空的节点Node
2 挂载 Sprite 节点,然后再挂载RigidBody2D刚体节点
3 移除RigidBody2D刚体节点
2. Node节点
- Node节点,是基类节点,所有节点都会继承Node节点,所以其它类型都包含Node节点的功能
- Node节点是最核心的节点,所有其他类型节点都是由Node节点派生出来的
1. Pause Mode节点的暂停
get_tree().paused = true
节点的三种可能状态有:
Inherit(继承) :处理与否取决于父、祖父等等节点中第一个非 Inherit 状态的节点。
Stop(停止) :无条件停止节点(以及 Inherit 模式的子节点)。暂停时该节点不会进行处理。
Process(处理) :无条件处理节点(以及 Inherit 模式的子节点)。无论暂停与否,该节点都会进行处理。
process方法执行的优先级,对于子节点依然有效
挂载外部的脚本
# 脚本初始化会首先调用这个方法,会在_process()方法之前调用
func _ready():
# get_tree().paused = true
pass
var count = 0
# 每一帧都会调用这个方法
func _process(delta):
count = count + 1
if (count % 60 == 0):
print("parent node")
pass
3. CanvasItem节点
-
CanvasItem节点,CanvasItem -> Node
-
Canvas是画布的意思,所以CanvasItem代表了就是可以被绘制节点,可以设置可视化界面和材质的颜色
-
所有的2D节点和GUI节点都继承于CanvasItem节点
-
CanvasItem是按树的树的广度优先遍历顺序绘制的
-
可以通过设置CanvasItem的Show Behind Parent来改变最终渲染到屏幕上的画面顺序
Texture 贴图,附加到物体表面的贴图
Material 材质,物体的质地,指色彩,纹理,光滑度,透明度,反射率,折射率,发光度。实际就是Shader
Shader 着色器,使用代码来渲染图形的技术,可以控制GPU运算图像效果的一段代码
4. Node2D节点
- Node2D节点,Node2d -> CanvasItem -> Node
Node2D节点继承于CanvasItem节点,CanvasItem节点继承于Node节点,所以Node2D节点包括了CanvasItem节点和Node节点的所有功能
Transform ,Node2d节点的基本属性,在后面的脚本编程中,Transform属性是最常用的
表示:
- Position 位置
- Rotation 旋转
- Scale 缩放
5. 自定义节点
-
当发现现有的节点无法支持新的需求的时候,有两种方法去解决,自定义节点或者自定义脚本,核心都是脚本
-
创建GdScrip脚本,叫MyNode,继承Node2D节点,并自定义节点的icon
extends Node2D
class_name MyNode, "res://icon.png"
- 编写脚本,定义变量,编写代码
export var a = 1
export var b:String
-
保存,如果不保存无法看到我们创建到的节点,这一点需要特别注意
-
添加刚刚创建的自定义节点
6. 节点继承
- 通过继承现有节点,来改变已有节点的功能
- 无论是自定义节点还是节点继承,核心都通过脚本控制达到自己想要的效果
- 从下节课开始说GdScript脚本
1. 脚本的定义
- 游戏脚本 Script ,用代码来控制游戏对象
- godot使用 GdScript 作为脚本语言
- 注意:自本章开始,每节课的项目源码都放在了github项目godot-start,可以直接对照示例项目
- 游戏开发,也是一种程序设计,如果是0基础的同学,建议先学习一个强类型语言比如Java,C#,C++,再来学习GdScript就一通百通了
2. 脚本的使用
- 如何使用一个脚本?
新建脚本 hello.gd ,编辑代码 ,保存一下
把脚本挂载到游戏节点上
运行游戏,点 Play Scene 运行当前游戏场景,在 Output 窗口里观察打印输出
3. 认识脚本
- 因为是GdScript是弱类型语言,所以比较自由,但是我们可以约定一些原则让代码更加的规范:
类名必须与文件名相同,且为小写
尽量继承于 Node2D 节点,Node2D 节点中的Transform是我们用的最多的节点
- 常用函数内部执行顺序,_init _ready _process
默认定义了一些事件函数,例如,
_init() 脚本初始化的时候调用,对象的构造器,类似于Java的构造函数construct
_ready() 开始调用一次,可用于初始化脚本
_process(delta) 每帧调用,帧间隔不等,可用于更新游戏
4.变量和数据类型
- 变量是用于存储信息的"容器"。
var x=5;
var y=6;
var z=x+y;
就像代数那样
x=5
y=6
z=x+y
在代数中,我们使用字母(比如 x)来保存值(比如 5)。
通过上面的表达式 z=x+y,我们能够计算出 z 的值为 11。
在 godot 中,这些字母被称为变量。
- gds数据类型分类
- bool,一个字节,默认为false
- int(同C++和Java long),8个字节,默认为0
- float(同C++和Java double),8个字节,默认为0
- String,默认为null,字符串可以存储一系列字符,如 "John Doe"。
- 数组
- 对象
- null,变量没有被赋值,则默认为null
5.导出变量
- export关键字可以让变量在编辑器中编辑
# 导出一个数字
export var a = 1
# 导出一个节点路径
export var b:NodePath
# 导出一个节点路径,不同的写法
export(NodePath) var c
# 导出一个文件路径
export(String, FILE) var e
# 导出一个文件路径,以txt结尾
export(String, FILE, "*.txt") var d
# 导出一个资源文件路径
export(Resource) var f
# 导出一个颜色
export(Color, RGB) var g
6.函数
- 函数是可以简单的理解为当它被调用时执行的可重复使用的代码块。
- 函数就是包裹在花括号中的代码块,前面使用了关键词 func,当调用该函数时,会执行函数内的代码。
- 空函数需要使用pass关键字
func sayHello():
# 执行代码
- 调用带参数的函数,在调用函数时,您可以向其传递值,这些值被称为参数。
func sayHello(param1, param2):
# 执行代码
- 带有返回值的函数,有时,我们会希望函数将值返回调用它的地方,通过使用 return 语句就可以实现。
- return方法可以指定返回的类型
func sayHello(param1, param2):
# 执行代码
return x
7.变量的作用域
- 局部作用域,变量在函数内声明,变量为局部作用域,只能在函数内部访问
# 此处不能调用 carName 变量
func myFunction():
var carName = "Volvo";
# 函数内可调用 carName 变量
- 全局变量,变量在函数外定义,即为全局变量,整个脚本文件中都可以使用
var carName = " Volvo";
# 此处可调用 carName 变量
func myFunction():
# 函数内可调用 carName 变量
8. 运算符
- 算术运算符
+ 加法 x=y+2 7 5
- 减法 x=y-2 3 5
* 乘法 x=y*2 10 5
/ 除法 x=y/2 2.5 5
% 取模(余数) x=y%2 1 5
- 赋值运算符,赋值运算符用于给 GdScript 变量赋值
= x=y x=5
+= x+=y x=x+y x=15
-= x-=y x=x-y x=5
*= x*=y x=x*y x=50
/= x/=y x=x/y x=2
%= x%=y x=x%y x=0
- 比较运算符,比较运算符在逻辑语句中使用,以测定变量或值是否相等
== 等于 x==8 false
!= 不等于 x!=8 true
> 大于 x>8 false
< 小于 x<8 true
>= 大于或等于 x>=8 false
<= 小于或等于 x<=8 true
- 逻辑运算符,逻辑运算符用于测定变量或值之间的逻辑。
&& and (x < 10 && y > 1) 为 true
|| or (x==5 || y==5) 为 false
! not !(x==y) 为 true
9. 条件语句
-
通常在写代码时,您总是需要为不同的决定来执行不同的动作。您可以在代码中使用条件语句来完成该任务。
-
if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码
if (condition):
当条件为 true 时执行的代码
- if...else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码
if (condition):
当条件为 true 时执行的代码
else:
当条件不为 true 时执行的代码
- if...else if....else 语句- 使用该语句来选择多个代码块之一来执行
if (condition1):
当条件 1 为 true 时执行的代码
elif (condition2):
当条件 2 为 true 时执行的代码
else:
当条件 1 和 条件 2 都不为 true 时执行的代码
- match(switch) 语句 - 使用该语句来选择多个代码块之一来执行
10. 循环语句
- 循环可以将代码块执行指定的次数,如果您希望一遍又一遍地运行相同的代码,并且每次的值都不同,那么使用循环是很方便的
- for
- while
- break 语句跳出循环后,会继续执行该循环之后的代码(如果有的话)
- continue 语句中断循环中的迭代,如果出现了指定的条件,然后继续循环中的下一个迭代
11. 数组和字典的遍历
- 数组遍历
func arrayIterator():
# range等价于for(int i = 0; i < 20; i++)
print("数组遍历方法1:")
for i in range(3):
print(i)
print("数组遍历方法2:")
for ele in arr:
print(ele)
print("数组遍历方法3:")
for index in range(arr.size()):
print(arr[index])
- 字典遍历
func dictionaryIterator():
print("字典遍历方法1:")
for key in dict:
print("key:" + key as String)
print("value:" + dict[key] as String)
print("字典遍历方法2:")
for key in dict.keys():
print("key:" + key as String)
print("value:" + dict[key] as String)
print("字典遍历方法3:")
for value in dict.values():
print("value:" + value as String)
12. 静态变量和静态方法
- const变量(静态变量)
const ANSWER = 42
- 静态方法
static func getAnswer():
return ANSWER
13. 对象
- 真实生活中的对象,属性和方法
- 真实生活中,一辆汽车是一个对象。对象有它的属性,如重量和颜色等,方法有启动停止等
# Inner class,默认继承Object
class Animal:
extends Object # 如果不指定继承的类,默认基础Object
const STATIC_FIELD = "静态变量"
# 属性
var height: int
func _init():
print("Animal 构造方法")
func move():
print("animal,移动")
static func staticFuction():
pass
14. 调试
- 在编写 GdScript 时,如果没有调试工具将是一件很痛苦的事情。
- 你的代码可能包含语法错误,逻辑错误,有了调试工具,这些错误比较容易发现。
15. 参考资料
- godot官方文档
- Godot Tutorials的GDScript Fundamentals Tutorial Series,youtube播放量最高的godot教程视频
- Godot Tutorials的Godot Basics Tutorial Series,youtube播放量最高的godot教程视频
- B站视频
1. 内存管理free
-
godot中的对象分为两种
- 引用计数对象,继承于Reference,当没有引用时会被自动回收
- 非引用计数对象,没有继承于Reference,自能自己手动回收,free或queue_free
-
在godot中,移除一个节点并不会从节点中删除,必须手动调用free或queue_free
2. 垃圾回收的缺点
- GdScript没有垃圾回收,虽然有着内存泄露的风险,但是也保证了性能
3. 引用计数算法
-
对于创建的每一个对象都有一个与之关联的计数器,这个计数器记录着该对象被使用的次数
-
可以立即回收垃圾。因为每个对象在被引用次数为0的时候,是立即就可以知道的。
-
没有暂停时间。这个很容易理解,对象的回收根本不需要另外的GC线程专门去做,业务线程自己就搞定了。
-
不需要stop the world,当然,在多线程的情况下,必要的同步和互斥操作还是需要的。
-
一个致命缺陷是循环引用,就是, objA引用了objB,objB也引用了objA。这种情况下,这两个对象是不能被回收的。
-
可以使用unreference去释放引用计数的对象
-
引用计数既保留了性能,也保证了更加高效的性能
1. 场景树
- Nodes(节点)是在Godot中创建游戏的基本构建块。当一组节点被添加到树中时,它被称为sence(场景),树被称为sence tree(场景树)
节点是可以表示各种专用游戏功能的对象。给定类型的节点可以显示图形,播放动画或表示对象的3D模型。
该节点还包含一组属性,允许你自定义其行为。
你添加到项目中的节点取决于你需要的功能。
它是一个模块化系统,旨在为你提供构建游戏对象的灵活性。
在项目中,你添加的节点将组织为树结构。在树中,节点被添加为其他节点的子节点。
特定节点可以具有任意数量的子节点,但只能有一个父节点。
2. 帧率
- 帧率 Framerate ,指画面每秒更新多少次 (FPS, Frames Per Second)
比如,
FPS = 50 , 即每 20ms 秒更新一次
FPS = 60, 约 16.7ms 秒更新一次
通过代码可以设置,要求 godot 引擎尽量以此帧率运行 ,但实际帧率还是会有偏差
Engine.target_fps = 120
- delta time上一帧的间隔
匀速移动的优化:
var step = 0.8f * deltaTime;
其中,
0.8f 表示每秒位移 0.8 单位
3. 节点的生命周期
- 在Godot中,一个游戏的启动大致流程如下:
Godot的main启动一个进程,加载所需的驱动设备(如渲染设备:GL/GLES/Vulkan等)、音频设备,输入控制器设备等等;
然后进入主循环,加载一个自动创建的对象——SceneTree(场景管理系统对象,它用户管理场景图),
这个对象包含一个RootViewPort节点(它是一个Node),该节点包含一个默认的ViewPort(以便提供默认渲染的输出视口)。
当用户用Godot编辑器创建一个关卡(或场景文件),并设置默认的启动的场景文件,Godot将该场景文件的根节点附加到RootViewPort节点上,
当节点进入场景树(SceneTree),变为活动状态。
按场景树顺序依次回调各个子节点的_init(),_ready()等声明函数。
4. 节点的获取方式
# 获取当前节点
var currentNode1 = $"."
var currentNode2 = self
# 获取父节点
var parentNode1 = get_parent()
var parentNode2 = $"../"
# 获取子节点
var subNode1 = $SubNode2
var subNode2 = $"SubNode2"
var subNode3 = get_node("SubNode2")
# 根节点查找法,会返回节点树从上到下找到的第一个节点
var subNode4 = get_tree().root.find_node("SubNode2", true, false)
5. process和physics_process
- 平时我们看到的动画,实际上是由很多静止的画面连续切换组成的
- 其中每个静止的画面,我们都称为一帧,比如60帧的动画,就是一秒播放60个静止的画面,组成的动画
- godot 的 _process 相当于 unity 的 Update
内部对代码就会在每一帧之前被执行,也就是引擎每渲染一幅的画面之前,都会执行它里面的代码
- godot 的 _physics_process 相当于 unity 的 FixedUpdate
内部的代码会在每个物理帧之前被执行,
因为godot的物理模拟是单独进行的,每次进行物理模拟的时候,如计算一个刚体小球的运动轨迹,每进行一次计算,我们就称为是一进行了一个物理帧,
而每次进行物理模拟之前,都会执行_physics_process中的代码
6. Parent和Owner
-
Parent
- 一个节点的Parent就是场景树上它的父级
-
Owner
- 如果不修改默认Owner的话,可以把它视为节点所在场景的顶部节点,如果该节点本身就是顶部节点那么它的Owner为null
-
静态场景结构中默认的Owner
extends Node
class_name TestNode
func _ready():
var parent_name = "NULL"
var owner_name = "NULL"
if get_parent() != null:
parent_name = get_parent().name
if owner != null:
owner_name = owner.name
print(name + "'s parent is <" + parent_name + "> and it's owner is <" + owner_name + ">" )
node_3's parent is <node_2> and it's owner is <node_0>
node_2's parent is <node_1> and it's owner is <node_0>
node_1's parent is <node_0> and it's owner is <node_0>
node_0's parent is <root> and it's owner is <NULL>
- 动态创建的节点的Owner是null
1. 信号signal
-
信号是用来完成模块或功能之间通信的媒介,其实就是约定了一些方法的回调形式
-
设计模式上叫做观察者设计模式
1. 观察者和被观察者是抽象耦合的,解耦模块
2. 建立一套统一的触发机制
-
Godot引擎官方建议在你的游戏开发中更多的使用信号来完成模块或功能间的通信
-
第一种使用方法
# 第一种信号接受方法,通过在场景中配置信号的接收方法
func _on_Button1_pressed():
print("hello button1")
- 第二种使用方法
# 第二种信号接受方法,通过代码控制信号的接收,更加的灵活,比较推荐方式
func _ready():
$Button2.connect("pressed", self, "onButton2")
func onButton2():
print("button2 pressed")
2. 自定义信号
- 自定义信号
signal mySignal(a, b)
- 发送信号
emit_signal("mySignal", 1, 2)
- 解除绑定信号
disconnect("mySignal", 1, 2)
3. 异步回调yield
- yield, to produce a result, answer, or piece of information,立即结束当前函数调用,无需等待
其本质,就是能让一个函数在执行过程中暂停(挂起),然后在接收到恢复指令以后继续执行的机制。
- yield(obj, signal),函数立即返回,并且保存当前执行的位置和状态
GDScriptFunctionState yield( Object object=null, String signal="" )
- yield返回GDScriptFunctionState类型对象,类似于Java的CompleteFuture
GDScriptFunctionState 是记录一个协程状态的对象,实际上它就代表(引用)着该协程。
- resume恢复GDScriptFunctionState保存的调用函数状态
- yield的三种用法
- yield()和resmue()组合,yield()来挂起,用resmue()来恢复
- yield(对象,信号S)的形式,把这个协程(即 GDScriptFunctionState)注册为 节点N上信号S的接收者,当 节点N发出信号S以后,函数会恢复执行。
- yield(协程对象C,"completed")的形式,协程失效(即GDScriptFunctionState的is_valid为false)以后,它会释放一个"completed"信号,用这个信号恢复上一层协程。
4. 多线程
- 什么是进程?
电脑中有时会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。比如QQ、浏览器
- 什么是线程?
进程想要执行任务就需要依赖线程。换句话说,就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。
- 那什么是多线程?提到多线程这里要说两个概念,就是串行和并行,搞清楚这个,我们才能更好地理解多线程。
- 串行,其实是相对于单条线程来执行多个任务来说的,比如下载一个文件要等到上一个文件下载完
- 并行,下载多个文件,开启多条线程,多个文件同时进行下载,这里是严格意义上的,在同一时刻发生的,并行在时间上是重叠的
1. 屏幕窗口设置
-
Editor | Editor Settings | Editor,设置控制台是否隐藏
-
Editor | Editor Settings | Window Placement,设置编辑器运行游戏窗口的位置
-
Project | Project Settings | Display,设置游戏窗口的大小等相关参数
-
Project | Project Settings | Display | Hide Home Indicator,ios的 Home 键指示隐藏
2. 单位和像素
-
屏幕分辨率(屏幕像素),屏幕分辨率上的像素点数,单位是px,4:3 是最常见屏幕比例,显示设置可以看到
-
图片像素
-
屏幕像素和图片像素有什么关系
在屏幕显示图片时,如果屏幕的长宽比或者像素数和图片一致,只需要每个屏幕像素的像素点表示出图片上的像素就可以了,1:1对应显示出来。
那如果图片像素数和屏幕像素数不一样呢?
当图片像素大于屏幕像素时,屏幕也是进行合并显示的。
比如一张1200W像素的图片,要在300W像素的显示器(长宽比一致)上显示,那么系统就需要将图片像素进行四合一计算然后再显示。
当图片像素数大于屏幕像素数时,高像素图片和低像素图片的显示精细度是一样的!
- DPI(dots per inch),DPI在高分辨率显示器和手机普及之后,调了之后,画面上的字体等会变大变小。
比如我使用一个27寸的4k显示器,如果DPI 100%的话,那么字体就是27英寸的1080p显示器的1/4大小,完全没法看了。
这个时候,使用DPI 200%,字就又大又清楚了。
这个过程在windows上面就是DWM(desktop windows manager)做了scaling。
- 在godot中,一般position的1个单位长度等于1个图片像素
3. 垂直同步
- Vsync,垂直同步又称场同步(Vertical Hold)
我们平时所说的打开垂直同步指的是将该信号送入显卡3D图形处理部分,从而让显卡在生成3D图形时受垂直同步信号的制约。
当我们选择"等待垂直同步信号"(即打开垂直同步)时,显卡绘制3D图形前会等待垂直同步信号,
当该信号到达时,显卡开始绘制3D图形,如果显卡性能较为强劲,在下个垂直同步信号到来之前已经完成了对该帧的渲染,
显卡就会暂停处理,等下个垂直同步信号到来后才开始渲染下一帧。
由此可见,当打开垂直同步时,游戏的FPS要受刷新率的制约,对于高端显卡而言,限制了其性能的发挥。
假设我们选择不等待垂直同步信号(也就是我们平时所说的关闭垂直同步),
那么游戏中屏幕渲染完整个屏幕的画面后,显卡和显示器无需等待垂直同步信号就能够开始下一屏图像的绘制,自然能够全然发挥显卡的实力。
可是不要忘记,正是由于垂直同步的存在,才使得游戏进程和显示器刷新率同步,使得画面更加平滑和稳定。
取消了垂直同步信号,固然能够换来更快的速度,可是在图像的连续性上势必打折扣。
这也正是非常多朋友抱怨关闭垂直后发现画面不连续的理论原因。
- CRT显示器学名为“阴极射线显像管”,是一种使用阴极射线管(Cathode Ray Tube)的显示器。
屏幕上的图形图像是由一个个电子束击打屏幕而发光的荧光点组成
电子枪从屏幕的左上角的第一行(行的多少根据显示器当时的分辨率所决定,比如800X600分辨率下,电子枪就要扫描600行)开始,从左至右逐行扫描,
第一行扫描完后再从第二行的最左端开始至第二行的最右端,一直到扫描完整个屏幕后再从屏幕的左上角开始,这时就完成了一次对屏幕的刷新,周而复始。
从CRT显示器的显示原理来看,单个像素组成了水平扫描线,水平扫描线在垂直方向的堆积形成了完整的画面。
显示器的刷新率受显卡DAC控制,显卡DAC完成一帧的扫描后就会产生一个垂直同步信号。
- 液晶显示器借助于薄膜晶体管驱动的有源矩阵液晶显示器,它主要是以电流刺激液晶分子产生点、线、面配合背部灯管构成画面。
在电场的作用下,利用液晶分子的排列方向发生变化,使外光源透光率改变(调制),完成电一光变换,
再利用R、G、B三基色信号的不同激励,通过红、绿、蓝三基色滤光膜,完成时域和空间域的彩色重显。
LCD的刷新率与CRT不同,因为LCD和CRT的显像方式不同,CRT是靠不断刷新画面来使显示器显示图像的,而LCD只要改变发光颗粒就能使显示器中的画面动起来
正是由于LCD与CRT显像方式不同,LCD显示器本身不会出现屏幕闪烁的现象
打开垂直同步可以使得画面平滑、稳定。
关闭垂直同步,则可以明显提高帧数,获得更快的速度,代价就是牺牲稳定性,显卡持续高负荷运转势必发热,进而影响计算速度。
4. 屏幕坐标
- 刚开始学习的时候可能有点疑惑,godot的坐标系,原点既然在左上角
- unity,cocos的2d原点都在左下角,就很符合数学里面的象限,左下角的2d坐标系感觉很复合习惯
后来了解到,计算机屏幕是从左上角开始刷新的,2d坐标系左上角为原点可以屏幕坐标系吻合可以提升一点效率。
unity的2d坐标系虽然在左下角,但是unity的屏幕坐标系依然在左上角,不统一。
虽然godot的2d坐标系在左上角的坐标系刚开始看不舒服,但是和屏幕坐标系吻合了,也算一种统一,就不需要untiy2d的那么多概念了,为godot点赞。
因为单论平面内容制作,左上原点更符合视觉习惯,也更符合设计常识,比如ps。
- 世界坐标系:又称为全局坐标系,以场景树的root节点为坐标系原点
- 相对坐标系:又称为局部坐标系或者本地坐标系,相对于父节点的坐标,godot的坐标都是相对坐标
- 屏幕坐标:屏幕的左上角为坐标系原点
5. 全局和相对坐标的相互转化
- 全局坐标和局部坐标(相对坐标)可以相互转化
Node2D及其子节点的位置可以使用position和gloabl_position来控制。
其中,前者是该节点相对于父节点的相对位置,后者是全局位置。
简而言之,position的坐标系是以父节点的位置坐标为原点的坐标系,方向,还是水平向右为x轴正方向,竖直向下为y轴正方向。
需要注意的是,全局位置是以场景的root节点为原点的,并不是以当前场景的根结点的位置作为原点的
# 坐标点测试用例
func positionTest():
print(position)
print(global_position)
print(to_global(position))
print(to_local(global_position))
pass
6. 深度遍历显示节点
- 一个游戏可以包含多个场景,但是一个场景中必须有一个根节点,一个根节点可以包含多个不重名的子节点(unity的子节点可以同名),不同名更加符合习惯,为godot点赞。
7. Sprite节点和Image类的使用
-
CanvasItem节点,CanvasItem -> Node -> Object
-
Canvas是画布的意思,所以CanvasItem代表了就是可以被绘制节点,可以设置可视化界面和材质的颜色
-
所有的2D节点和GUI节点都继承于CanvasItem节点
-
Sprite节点,Node2d -> CanvasItem -> Node -> Object
-
用来显示一张图片
-
Texture类,Resource -> Reference -> Object
-
Texture 贴图,附加到物体表面的贴图,实际上就是包含一张Image图片
-
可以用在3D模型中当作贴图,或者2D的Sprite中当作图片,或者GUI的背景
-
Image类,Resource -> Reference -> Object
-
包含了图片的数据
-
总结
1. 向量的基础
- a·b=||a||||b||cosθ, 这个是向量的内积,又叫数量积,又叫点积。
- axb = ||a||||b||sinθ,这个是向量的外积,又叫向量积,又叫叉积。
- 常量以godot游戏引擎为准,Vector是我从unity文档复制过来的
2. 通过输入事件来控制物体移动
- 事件系统是游戏开发过程中需要涉及到交互常用的功能。
- 使用事件系统不仅可以将输入行为(例如:键盘、鼠标、触摸)以事件的形式发送到应用程序
- 也可以将游戏过程中的发生的,需要其他对象关注的事情通过事件的形式回应。例如:游戏胜利后需要打开结算或者奖励界面。
1. 物理系统
- 物理系统(PhysicsSystem)用于管理所有物理相关的功能,目前它负责同步物理元素、触发物理事件和调度物理世界的迭代。
- 物理世界迭代时会对物理元素进行物理计算,比如计算各物体是否产生碰撞,以及物体的受力情况。当计算完成后,物理系统会将物理世界更新到场景世界中,从而使游戏对象产生相应的物理行为。
- Godot 的物理系统提供了高效的组件化工作流程和便捷的使用方法。目前支持刚体、碰撞组件、触发和碰撞事件
- 用一句话总结物理系统,就是模拟真实世界的碰撞
2. RigidBody节点
- 刚体是组成物理世界的基本对象,你可以将刚体想象成一个你不能看到(绘制)也不能摸到(碰撞)的带有属性的物体。
- mass,刚体质量
- weight,刚体加速度
- linear velocity,移动速度
- angular velocity,旋转速度
- applied forces,施加的力
- torque,扭矩
- damp,衰减系数,值越大物体移动越慢,可以用来模拟空气摩擦力等效果。
3. 刚体实战
-
RigidBody,动态刚体,有质量,可以设置速度,会受到重力影响。
-
Kinematic,运动刚体,零质量,可以设置速度,不会受到重力的影响,但是可以设置速度来进行移动。
-
Static,静态刚体,零质量,零速度,即不会受到重力或速度影响,但是可以设置他的位置来进行移动
-
Area2D,一块区域,能够检测到物体的碰撞,但是不会做任何操作
-
碰撞检测Layer和Mask,Layer表明当前刚体属于那一层,Mask表面当前物体的遮罩
1. Line2D 节点
- 在 2D 空间中通过几个点连成的线,可以通过代码动态添加和删除
注意:默认情况下,Godot一次最多只能绘制 4,096 个多边形点。
要增加这个限制,请打开项目设置,修改下面两个设置
ProjectSettings.rendering/limits/buffers/canvas_polygon_buffer_size_kb
ProjectSettings.rendering/limits/buffers/canvas_polygon_index_buffer_size_kb。
2. RemoteTransform2D 节点
- RemoteTransform2D,类似与设计模式中的代理模式,代理一个节点
RemoteTransform2D pushes its own Transform2D to another CanvasItem derived Node in the scene.
It can be set to update another Node's position, rotation and/or scale. It can use either global or local coordinates.
3. Path2D 节点
- Path2D,包含了一个曲线路径数据
Contains a Curve2D path for PathFollow2D nodes to follow,Describes a Bézier curve in 2D space.
- PathFollow2D,要和Path2D结合在一起使用
This node takes its parent Path2D, and returns the coordinates of a point within it, given a distance from the first vertex.
It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node.
The descendant nodes will then move accordingly when setting an offset in this node.
4. Tilemap 节点
-
tilemap的由tileset组成,tileset由tile一个个单个图块组成
-
基本上通过熟练使用get_cell、set_cell、world_to_map这些函数就可以解决大多数普通关卡制作需求
-
自动填充bitmask
-
如图所示,这是一个3×3的autotile(自动图块),如果我还没有设置bitmask(位遮罩),那么此时放置图块时效果如下图所示
-
可以看到,如果没有设置bitmask,那么放置图块时只显示左上角的部分
-
接下来我把bitmask设置在中心区域,如图所示,接下来,我再放置autotile时,效果就不一样了,效果如下图所示:
-
可以看到,图中其它图块都是左上角,但中间的部分改变了,接下来我再把bitmask的范围加大,接触到相邻的图块,接下来效果就又不一样了
-
可以看到,当放置了一圈图块后,在中间添加图块时,相邻的图块全都改变了
5. Navigation2D 节点
- Navigation2D 节点可以实现自动寻路
- 目前使用最广泛的是 AStar 算法,在Godot中,Navigation2D完全的集成了此算法,让使用变得易常简单
-
Collision 和 Navigation 。字面意思, Collision区域将是无法通过的,而Navigation可以,且寻路总是在Navigation的区域里进行。
-
引擎的作用就是为了减少大量复杂的工作,就像AStar寻路一样,在Godot中,可以非常简单的使用,就像它的函数名一样 simple 。
-
当然,游戏总不会这么简单容易,可能有非常多的情况与限制,都需要针对性处理才能满足需求。
1. CanvasItem之draw和update
-
Canvas是画布的意思,所以CanvasItem代表了就是可以被绘制节点,可以设置可视化界面和材质的颜色
-
所有的2D节点和GUI节点都继承于CanvasItem节点
-
CanvasItem是按树的树的深度优先遍历顺序绘制的
-
draw指定了要绘制的东西
-
当要draw绘制的改变了,需要调用update
-
hide和show,隐藏和现实节点
-
CanvasItem可以绘制直线,正方形,长方形,圆,图片
1. 动画系统
- godot中的动画其实就是一个一个图片的轮播
sprite解释,上世纪70年代,在德州电器公司,一个叫Daniel Hillis的前辈最早把Sprite这个词用在计算机图形上,在展示界面上,
有一些东西在实现层面并不是和整个画面融为一体的,而是『漂浮』在其他画面之上,像『幽灵』一样,所以被称为Sprite。
一张一张的图片组成了一个会动的精灵
- godot内置了通用的动画系统用以实现基于关键帧的动画。
除了支持标准的位移、旋转、缩放动画和帧动画之外,还支持任意组件属性和用户自定义属性的驱动,
再加上可任意编辑的时间曲线和创新的移动轨迹编辑功能,能够让内容生产人员不写一行代码就制作出细腻的各种动态效果。
2. Timer节点实现动画
-
Timer节点,意思是计时器秒表,在godot中可以利用他的定时器特性来实现动画帧
-
看名字就知道这是一个“计时器”。在 Godot 中一切皆节点,所以看到这种纯功能性的节点不要觉得奇怪
-
我们完全可以不使用节点,直接使用代码 Timer.new() 动态创建一个计时器也是没任何问题的;
Timer 时间计时器节点的属性非常简单,根据需求可以设置其等待时间、重复计时以及是否自动开始,这些属性我们也可以在 GDScript 脚本中使用代码修改:
wait_time :等待时间,即计时时长,结束触发 timeout 信号
one_shot :是否是一次性,如果是,只会触发一次 timeout 信号
autostart :自动开始,载入场景后计时,也可以使用 start 方法手动开启
3. Tween节点实现动画
-
在游戏开发过程中,我们一般使用 AnimationPlayer 节点来实现移动、缩放、颜色渐变等动画效果
-
Tween 即渐进/过渡的意思,从一种状态在一定时间内变化到另一种状态,从而产生一种视觉动画。
-
渐变节点使用非常简单方便,可以对一个物体的任意属性进行动画控制,当然,也可以同时处理多个动画对象。其主要方法有以下几个:
repeat :是否重复
start() :开始渐变,结束后触发 tween_completed 信号
interpolate_property() :设置进行动画的节点属性以及时长等,需要传递属性名称、开始结束值、时长等参数
这里最重要的方法是 interpolate_property() ,可以在 Godot 编辑器中按 F4搜索 Tween 类进行查看。
当然,和 Timer 节点一样,我们完全可以在代码中动态创建Tween 对象。
Smoothly animates a node's properties over time.
Tweens are useful for animations requiring a numerical property to be interpolated over a range of values.
The name tween comes from in-betweening, an animation technique where you specify keyframes and the computer interpolates the frames that appear between them.
Tween is more suited than AnimationPlayer for animations where you don't know the final values in advance.
4. AnimationPlayer节点实现动画
- AnimationPlayer是时间和属性的变化,是一种动画的表现
5. AnimatedSprite节点实现动画
- AnimatedSprite是序列帧的简便的用法
1. 光照系统Light2D
- godot 的 2D 动态光照
- 首先看看 Demo 的预览效果。可以看到,当我们在 Demo 中移动光源的位置,小人和场景也会随之表现出不同光照的情景
- 带法线贴图的Sprite和普通的 Sprite 有什么区别呢? 通过对比不难看出它们的差别主要是集中在材质上面。小人使用了自定义的 mat_normal 材质
2. 法线贴图NormalMap
- 法线贴图的定义
法线贴图就是在原物体的凹凸表面的每个点上均作法线,通过RGB颜色通道来标记法线的方向,
你可以把它理解成与原凹凸表面平行的另一个不同的表面,但实际上它又只是一个光滑的平面。
对于视觉效果而言,它的效率比原有的凹凸表面更高,若在特定位置上应用光源,可以让细节程度较低的表面生成高细节程度的精确光照方向和反射效果。
在物理世界中,我们看到的物体的颜色,其实是物体本身反射光线的颜色,因为物体的材质不同,会吸收部分不同的颜色分量而导致我们看到的物体颜色不同。
模拟光照的过程实际上就是模拟整个光的传播过程。
-
需要注意的是,法线贴图在3D游戏中运用的更多一点,2D稍微少很多
-
法线贴图的制作软件laigter
- godot中使用法线贴图非常的简单
3. 光照和阴影LightOccluder2D
- 光照是指光的照射,godot 中光照的实现模拟了光对真实世界的影响。在场景中添加光源可以使场景产生相应的光照和阴影效果,获得更好的视觉效果。
4. 粒子系统
- 粒子系统是游戏引擎特效表现的基础,它可以用于模拟的火、烟、水、云、雪、落叶等自然现象,也可用于模拟发光轨迹、速度线等抽象视觉效果。
中大型游戏中,几乎没有哪个游戏不使用粒子特效的。
掌握粒子系统对游戏开发极其重要,合理地使用粒子特效对游戏效果绝对是锦上添花、如虎添翼。
常见的粒子特效有:烟花、灰尘、火焰、爆炸、光环、雪花、雨滴、溅射等等等等。比如下面的这张非常熟悉的效果图,使用的就是粒子特效:
1. GUI系统
- 图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。
图形用户界面是一种人与计算机通信的界面显示格式。
允许用户使用鼠标等输入设备操纵屏幕上的图标或菜单选项,以选择命令、调用文件、启动程序或执行其它一些日常任务。
与通过键盘输入文本或字符命令来完成例行任务的字符界面相比,图形用户界面有许多优点。
图形用户界面由窗口、下拉菜单、对话框及其相应的控制机制构成,在各种新式应用程序中都是标准化的,即相同的操作总是以同样的方式来完成,
在图形用户界面,用户看到和操作的都是图形对象,应用的是计算机图形学的技术。
- https://docs.godotengine.org/en/3.3/getting_started/step_by_step/ui_game_user_interface.html
2. GUI的字体选择
- 由于 Godot 使用 OpenGL 渲染,所以没法直接用系统字体,需要创建字体资源(Resource),而且在 UI 组件中,默认字体没法显示中文。
在 Godot 中使用自定义字体的步骤如下:
复制字体文件(ttf/tts等格式)到游戏目录内
创建字体资源(DynamicFont) , 并配置对应字体文件
控件中使用字体资源,配置字体大小,字体颜色
字体资源复用(Make Unique)
-
godot默认不显示中文,需要下载中文的字体
-
windows自带的字体,要收费,有版权风险,C:\Windows\Fonts
-
思源黑体,免费,开源,https://github.com/adobe-fonts/source-han-sans/releases
由Google和Adobe在2014年7月正式推出的开源字体,
不仅可以免费商用而且全面支持中文简体、中文繁体(香港)、中文繁体(台湾)、日文和韩文,还有七种字体粗细,整个字形个数接近50万。
免费可商用
3. GUI的锚点Anchor
- 是一个点,锚点描述的是一个对象的Margin,相对于锚点的坐标
- 锚点的left,top,right,bottom是相对于父节点的值
- 主要是用于描述子节点相对于父节点的位置
- 当对一个节点的子节点进行设置锚点时,子节点的锚点范围只能够是父节点的控件区域内。
- 注意任何布局也都是相对于父窗口矩形的
- 主要用于在GUI中描述子节点相对于父节点的位置
1. Camera2D相机
- Godot的 Camera2D 节点,也就是我们说的摄像机,它提供了不少可以定义的属性来处理游戏中的镜头,并且非常简单。
- 摄像机的作用
其实不用添加摄像机,我们的游戏也能够显示出画面来,但是当移动角色时,画面并不会跟着角色移动,正好我们有一个很大的地图,要如何展示呢。
摄像机的作用就是做为屏幕可见区域的镜头,让你可以看到它照到的区域部分。当角色移动或是需要展示其它区域时,移动的就是摄像机的镜头。
- 同一时间,只可能有一个摄像机处于激活状态。它是自动的,激活一个,其它的都会被置为未激活状态。
2. Viewport可视化窗口实现小窗口
- root就是根节点的viewport
3. CanvasLayer节点
- 它是一个节点, 为所有子代和孙代添加一个单独的2D渲染层.
- Viewport的子节点默认在图层 "0 " 处绘制, 而CanvasLayer将在任何数字层处绘制.
- 数字较大的图层将绘制在数字较小的图层之上.CanvasLayers也有自己的变换, 不依赖于其他层的变换.
- 这使得当我们对游戏世界的观察发生变化时,UI可以固定在屏幕空间中.
1. godot的文件系统
- 资源路径
访问资源时,使用主机OS文件系统布局可能很麻烦且不可移植。为了解决这个问题,创建了特殊路径 res://。
路径res://将始终指向项目根目录 (project.godot所在的位置,因此res://project.godot始终有效)
仅当从编辑器本地运行项目时,此文件系统才是读写的。
导出时或在其他设备(例如手机或控制台,或从DVD运行)上运行时,文件系统将变为只读状态,并且将不再允许写入。
- 用户路径
诸如保存游戏状态或下载内容包之类的任务仍需要写入磁盘。
为此,引擎确保存在始终可写的特殊路径user://。
根据项目运行所在的操作系统,此路径的解析方式有所不同。
Windows: %APPDATA%\Godot\
macOS: ~/Library/Application Support/Godot/
Linux: ~/.local/share/godot/
2. 通过文件持久化游戏数据
3. autoload单例模式
1. AudioStreamPlayer节点播放声音
- AudioStreamPlayer适合用来播放BGM,AudioStreamPlayer2D、AudioStreamPlayer3D播放时声源带有位置信息,会出现左右声道不一致的问题。
- 每个AudioStreamPlayer可以将音频绑定到某一个Audio Bus中,然后直接控制Bus的音量。 例如,以下代码可以使名为Master的Bus静音。
AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), mute)
- 声频信号是一组数字信号,以二级制的形式存储在文件中
- 音频信号流就是一个声音从它的源头到输出的整一个流程,这个流程中会经历多种设备
- 音频混合,混音
- ogg与mp3一样也是一种有损压缩的音频格式文件
ogg音频格式文件与其它音频不同在于它是完全免费、开放、没有专利限制的。
由于ogg格式是完全开放和免费的,所以可以获得大量的编码器和播放器,这也是为何MP3编码器如此少而且大多是商业软件的原因。
ogg文件格式可以不断地进行大小和音质的改良,而不影响旧的编码器或播放器。
- ogg相比MP3它可以在相对较低的数据速率下实现比MP3更好的音质
ogg相比MP3它可以在相对较低的数据速率下实现比MP3更好的音质
虽然目前ogg格式的音频文件在音质与MP3格式的文件相当,但由于ogg使用了一种灵活的格式,
能够在文件格式已经固定下来后还能对音质进行明显的调节和新算法训练。
此外,Ogg Vorbis支持VBR(可变比特率)和ABR(平均比特率)两种编码方式,Ogg还具有比特率缩放功能,可以不用重新编码便可调节文件的比特率。
- ogg格式可以对所有声道进行编码,支持多声道模式,而不像MP3只能编码双声道
多声道音乐会带来更多临场感,欣赏电影和交响乐时更有优势,这场革命性的变化是MP3无法支持的。
相信在未来人们对音质要求不断提高,Ogg的优势将更加明显。
支持ogg格式的播放器有很多,如winamp、千千静听等,你也可以使用转换器转换为自己喜欢的格式。
1. Http网络请求
- 超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。
HTTP是应用层协议,同其他应用层协议一样,是为了实现某一类具体应用的协议,并由某一运行在用户空间的应用程序来实现其功能。
HTTP是一种协议规范,这种规范记录在文档上,为真正通过HTTP进行通信的HTTP的实现程序。
HTTP诞生之初主要是应用于WEB端内容获取,那时候内容还不像现在这样丰富,排版也没那么精美,用户交互的场景几乎没有。
一、设计模式六大原则
- 1.单一职责原则
一个类只负责一项职责。
- 2.里氏替换原则
所有引用父类的地方必须能透明地使用其子类的对象。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。
比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,
如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
子类中可以增加自己特有的方法。
- 3.依赖倒置原则
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。
- 4.接口隔离原则
一个类对另一个类的依赖应该建立在最小的接口上。
接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。
- 5.迪米特法则
迪米特法则又叫最少知道原则,一个对象应该对其他对象保持最少的了解。
- 6.开闭原则
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
二、23种设计模式
1.创建型模式
- 简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。
- 工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。
- 抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。
- 建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。如StringBuilder的append()
- 单例模式:饿汉式,懒汉式,双重检测,静态内部类,枚举类实现具有天然的线程安全并且避免反射和反序列化漏洞
- 原型模式:prototype,通过复制现有的实例来创建新的实例。如深克隆,浅克隆
2.结构型模式
- 适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。如各种Adapter
- 组合模式:将对象组合成树形结构以表示的层次结构。可以理解成组合,如窗体控件,一个下滑的窗口中包含的List
- 装饰模式:动态的给对象添加新的功能。如Java的IO流
- 代理模式:为其他对象提供一个代理以便控制这个对象的访问。如静态代理,动态代理javaassist
- 亨元模式:通过共享技术来有效的支持大量细粒度的对象。
- 外观模式:facade,对外提供一个统一的方法,来访问子系统中的一群接口。
- 桥接模式:将抽象部分和它的实现部分分离,取代多层继承,多层继承违反单一职责。如DriverManager -- JDBC驱动 -- (MySQL Oracle)
3.行为型模式
- 模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。
- 解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。如Spring的expression
- 策略模式:定义一系列算法,把他们封装起来,并且使它们可以相互替换。
- 状态模式:允许一个对象在其对象内部状态改变时改变它的行为。
- 观察者模式:对象间的一对多的依赖关系。
- 备忘录模式:在不破坏封装的前提下,保持对象的内部状态,以便提供一个可回滚的操作。
- 中介者模式:用一个中介对象来封装一系列的对象交互。如java反射method.invoke()
- 命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。如执行sql语句
- 访问者模式:对于存储再一个集合中的对象,它们可能具有不同的类型,不同的访问者,其访问方式不同。
- 责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。
- 迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。如Iterator接口
godot 可以调用外部的IDE进行脚本的编辑,这里记录一下相关的配置
-
工欲善其事必先利其器,一款好用的编辑器可以极大的提高开发效率
-
Godot 自带的代码编辑器对于代码提示使用起来比较难受、经常出现打完后不提示或者提示错误的情况,极度的不智能。
-
恰好官方就支持 VSCode 作为第三方编辑器,而且支持 Debug 调试功能,这里记录一下配置流程。
-
官方的Godot Tools插件支持断点调试,智能补全,文档查看等非常多的功能,支持比较全面
-
进入 Editor - EditorSetting - Text Editor - External,配置好 “Exec Path” 和 “Exec Flags” 后勾选 “Use External Editor”
-
vscode 编辑器设置
/Programs/Microsoft VS Code/Code.exe
{project} --goto {file}:{line}:{col}
- idea 编辑器设置
C:/Program Files/JetBrains/IntelliJ
{project} {file}:{line}
使用不同版本的godot如何避免版本冲突
-
在godot.exe的同级目录创建一个 .sc 或者 sc 文件,这样不同版本的godot就可以使用不同的配置了,后面godot将自动使用self-contained-mode模式
屏幕常用
-
Editor | Editor Settings | Editor | Hide Console Window,设置控制台是否隐藏,3.5版本已经没有Hide Console Window这个选项了
-
Editor | Editor Settings | Run | Window Placement | Rect,设置编辑器运行游戏窗口的位置
工具准备
- python
- SCons,项目的管理工具
- Visual Studio 或 MinGW-w64,主要提供了C++的编译环境
python
-
官网下载python,选择win64可执行的安装,左下角点击Add Path,自动添加环境变量
-
python -v ,查看版本
-
pip是python的包管理工具,python自带了pip
pip install requests # 普通安装依赖
pip uninstall requests # 卸载
pip install -r install.txt # 从文件中批量安装依赖
pip install requests --proxy="http://127.0.0.1:10809" # 通过代理下载依赖
pip list # 已经安装的库
pip install --upgrade requests
SCons
- 安装godot的项目依赖管理工具SCons
- pip install SCons --proxy="http://127.0.0.1:10809"
- 在命令行输入scons,看有没有反应,没有安装会提示没有这个命令
Visual Studio
- 官网下载Visual Studio 2019,然后选择C++编译工具安装就行
- 如果不想安装VS,那么使用C++编译工具MinGW依然可以
MinGW-w64
- MinGW 的全称是:Minimalist GNU on Windows
- 它实际上是将经典的开源 C语言 编译器 GCC 移植到了 Windows 平台下,并且包含了 Win32API ,因此可以将源代码编译为可在 Windows 中运行的可执行程序
- 还可以使用一些 Windows 不具备的,Linux平台下的开发工具
- 一句话来概括:MinGW 就是 GCC 的 Windows 版本,MinGW-w64 是开源软件,可以免费使用
- https://winlibs.com/ ,选择UCRT runtime下载,解压过后将bin配置在Path环境变量中,如D:\Program\mingw64\bin
g++ --version
clang --version
Compile
- 常规编译参数
scons platform=windows # 默认去寻找VS的编译环境,找不到会寻找MinGW的编译环境
scons platform=windows use_mingw=yes # 强制使用mingw编译
scons -j6 platform=windows # 多线程编译
scons platform=windows bits=32 # 软件是64位还是32位置,bits=64 或者 bits=32
- 生产版本发布,默认打包是debug+tools
target=release_debug
target=release # 生产环境发布,可以加快编译速度和减小包的体积 q q
target=debug
- scons -j15 platform=windows target=debug tools=no
tools编辑器选项,godot里,所有带有tools的,是带编辑器的,不带tools是模板
tools可以在debug、release或者release_debug三种都可以,默认release是不带tools的
完成后,将这个打包好的exe丢到模板目录
%USERPROFILE%AppDataRoamingGodottemplates对应godot版本号
打包的文件叫godot.windows.opt.64,就把这个放入上述目录,对印的opt打包名字就改成windows_64_release
完成后就可以通过export导出项目或者将新增加的内容打包为pck作为dlc使用了
- scons -j15 platform=windows target=release tools=no
opt是optimized production template的缩写,是优化过后的模板,这个打包更加的耗时
-
scons -j15 platform=windows target=debug tools=yes ,等价于scons -j15 platform=windows
-
scons -j15 platform=windows target=release tools=yes
-
其它编译参数
scons platform=windows use_lto=yes # MinGW的编译环境,使用这个参数可以让发布的体积更加小,但是需要更多的机器内存
Android Compile
- 增减一个环境变量,这里使用Android Studio自动下载的SDK,ANDROID_SDK_ROOT=C:\Users\jaysunxiao\AppData\Local\Android\Sdk
- 添加到Path环境变量,%ANDROID_SDK_ROOT%\tools; %ANDROID_SDK_ROOT%\platform-tools;
godot.windows.tools.64.exe --editor --path D:/github/godot-project-test
scons -j15 platform=windows use_mingw=yes
scons -j15 platform=android use_mingw=yes target=release android_arch=arm64v8
使用Visual Studio调试Godot的源代码
- scons platform=windows vsproj=yes
使用命令创建vs的解决方案
-
再使用Visual Studio双击打开sln解决方案
-
设置调试参数
使用Clion调试Godot的源代码
-
使用Clion打开项目的文件(根目录)
-
Clion会让你选择一个CMake文件,选择platform/android/java/nativeSrcsConfigs/CMakeLists.txt
-
在Terminal控制台使用命令打开godot编辑器,godot.windows.tools.64.exe --editor --path D:/github/godot-project-test
-
然后Attache到godot的process
使用godot应该选择哪种语言GdScript, Lua, C#, Java, Rust或者C++ ?
-
GdScript是godot亲儿子,定制化后的语言更加简单容易上手,是开源语言
- GDScript快速加载无需编译,无任何等待
- GDScript没有gc,没有垃圾回收器
- 可以热更新
-
C#由微软主导,难度稍微大一点
- C#需要编译和等待
- 运行的时候有gc,会导致卡顿
- 可以热更新,但是极其复杂,https://github.com/focus-creative-games/hybridclr
-
C++大佬随意
-
Java难度稍微大一点,依赖于Jvm,https://github.com/utopia-rise/godot-kotlin-jvm
-
Rust难度非常大,语法复杂,https://github.com/godot-rust/godot-rust
-
Lua简单,https://github.com/perbone/luascript
-
JavaScript简单,https://github.com/godot-js/godot-js
新手如何入门一门编程语言?
-
一点编程语言基础都没有的,先学Java,资料和教程多,遇到问题容易解决
-
godot是基于节点的一个游戏引擎,节点就是一个面向对象编程的思想,GdScript也是面向对象的脚本语言
面向对象的三个基本特征是封装、继承、多态。
所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
- C++ -> C -> Java/C# -> go -> GdScript,难度排名
C#资料少,遇到问题容易卡主学习者
go虽然简单,但是因为不是面向对象的,不推荐学习,godot是面向对象编程的一个游戏引擎
Cpp天生对新手不友好
- 有一点编程基础,直接开搞,GdScript确实非常简单
其它比较好的doge项目实战视频教程
- https://www.bilibili.com/video/BV1pt411p7DK
(新手向)中文讲解Godot官方实例教程【你的第一个游戏】
- https://www.bilibili.com/video/BV1Rb4y1Z7r2
Godot游戏制作 看了必会!!! 你的第一个游戏 项目设置和Player场景制作
- https://www.bilibili.com/video/BV1Ei4y1m7C2
入门篇 005 官方文档第一个2d游戏制作(上)