Godot版本:4.3
学习资源:想在2025年做游戏?用Godot做出你的第一个2D游戏吧:游戏场景_哔哩哔哩_bilibili
————————————————————————————————————————
非常感谢老师的辛苦教学!教学质量非常高!
一、godot下载安装及新建项目
windows系统下载:Download for Windows – Godot Engine
godot的GDscript语言和python非常相近,熟悉python的话直接安装默认引擎就行,如果更常用C#那就去安装.net版本。
下载解压后选择最大的.exe文件,打开就是godot的界面了。
在新建项目的右上角点击“settings”可以选择中文。
二、搭建游戏场景
1.可以把素材文件夹直接拖入godot左侧的文件系统窗口中,godot就会把里面的所有素材倒入引擎了。godot文件系统窗口右侧还有更换视图模式,可以按自己喜好更换视图。
2.godot中2d和3d的制作是分开的,2d、3d、脚本的视角都在屏幕正上方可以切换选择。
3.godot的2d视角中可以按住鼠标中键(滚轮)来拖动视角,或者按住空格+点击鼠标来拖动视角。通过鼠标滚轮来选择放大或缩小,或者用触控板模拟滚轮操作。
4.在godot中所有场景和元素都被称之为“节点”(Node),不同节点可以执行不同功能,比如图像、音乐等,且节点可以进行嵌套。主舞台的游戏场景本身也是一个节点,被称之为根节点(root node),如果需要在这个舞台上放置各种元素,那么就要在根节点下方放置不同的子节点,每个子节点下方还可以放置更多子节点。当搭建了足够多场景后,场景中的元素就会呈现出树状结构,因此开发者们将godot左上角的场景窗口称为“场景树”。
5.在godot开始引擎中选择创建2D场景,即可创建一个2D场景的根节点。
6.点击场景窗口左侧的“+”号或者“CTRL+A”来添加子节点。
7.添加背景图片:添加Sprite2D节点,Sprite指图像,Sprite节点被称为“精灵节点”,可以用来显示图片。将素材库中的图片直接拖动到右侧检查器中Sprite的Texture中,就可以为这个Sprite节点赋予图片了。
8.背景图片为什么有点糊?需要在左上角的“项目”->“项目设置”->“渲染”->“纹理”,将默认的纹理过滤设置为“Nearest”,然后像素背景就会比较清晰了。
9.在工程文件上方的一排工具栏中,在指针右侧有一个“移动模式”选项,点击“移动模式”选项或键盘输入“W”进入移动模式,移动模式下可以直接用鼠标拖动选中的节点。如果在移动过程中按住shift,就可以现在这个节点只在水平或数值方向移动。
10.使用快捷键“CTRL+D”可以快速复制粘贴选中节点。双击节点可以重命名。
11.在游戏开发过程中,建议对不同的游戏场景专门建立不同的文件夹,保持良好的开发习惯。
12.点击右上角小三角形或者按下"F5“键可以开始试运行界面,如果一开始没有设置主场景那么这个时候引擎会提示添加主场景。
13.点击运行发现图片只有部分出现在了游戏显示框内,视图拉远发现右下角有一个蓝色的框,godot默认只渲染蓝色框内的元素场景。所以如果想把森里渲染到正中央,需要在场景树中添加一个摄像机(Camera2D节点),摄像机可以把渲染范围内的节点渲染到电脑屏幕上,添加节点后就能看到一个Camera2D节点的紫色方框,代表Camera的渲染范围,可以选中Camera节点,在右侧的”检查器“中选中"Zoom”选项,通过拖拽Zoom选项中的数值,可以实现摄像机渲染范围的修改。
14.场景比较多的话鼠标容易拖拽节点,可以在上方一排工具栏中点击锁形的一个按钮,它可以锁定选中节点不被拖拽。可以在场景书中按住“CTRL”同时选择多个节点,然后一起上锁。
15.针对不同的元素需要布置不同的场景,而在主场景一般只是实例化其他场景,这样有个好处就是如果该元素的某项数值修改了,可以随时实例化到主场景等其他所有应用的场景中。
16.使用Character2D节点可以模拟人物的移动和物理碰撞,所以非常适合作为玩家的根节点存在。
17.AnimatedSprite2D节点通过SpriteFrames引入精灵表(SpriteSheet)的方式让图片以一定的帧数动起来,从而形成动画效果。在AnimatedSprite2D节点的检查器点击SpriteFrames,选择新建SpriteFrames,在SpriteFrames的窗口里,点击网格状的按钮可以添加精灵表,然后根据精灵表的横纵设置右侧的水平和竖直分界。然后按顺序点击要用到的精灵表中的图片,就可以抽取这些图片形成动画了。SpriteFrames窗口的工具栏可以设置帧率和自动播放(游戏开始运行的时候就开始播放,一般放不运动的时候的动画)。
18.如果图片太小了或者比较偏,可以按“F"使图片居中。
19.怎么把其他场景的元素添加到主场景?在主场景的场景树窗格上方的工具栏中选择链接按钮,可以实例化其他场景到主场景。从而实现改一个=改一批。同时,一般不会通过跨场景的方式调用、更改其他场景(假设是C场景)的数据,不然可能影响该场景(C场景)在其他场景(假设是D场景)中的实例化。
20.怎么把代码中的变量标记到检查器中,以便在检查器中拖动赋值?可以在代码中使用@expert类似下一点的代码。
21.怎么实时检测、改变AnimatedSprite的动画效果?那就是在代码中获取AnimatedSprited的实例,然后实时监测调整
@export var animator : AnimatedSprite2D
先在检查器中声明类型,然后直接将场景树中的AnimatedSprite实例拖动到检查器对应空项中,就能实现通过animator控制场景书中的AnimatedSprite实例,类似于:
if is_game_over ==false:
is_game_over=true
animator.play("gameover")
三、GDScript编程
1.选择不同场景的节点,在场景树的上方工具栏选择代码脚本的按钮,点击,然后选择代码模板,代码建议保存在专门的代码文件夹中。然后节点的右侧也有了一个代码的小图标,如果在选中节点的情况下再次点击上方的脚本按钮,那么这个脚本将会取消挂载,如果想挂载回来就再次点击这个按钮,然后再选择加载脚本就行了。
2.所有在ready()函数里面的代码都会在游戏开始运行的时候被执行。
3._process(delta:float)函数和_physics_process(delta:float)函数都会在游戏的每一帧都会被执行一遍,其中_process()函数执行的帧数会因为计算机的频率而不同,有的计算机快,1秒可以200帧。而physics_process()函数执行的帧数就是非常固定的1秒60帧,两个函数内部都有参数delta,都指的两帧之间的时间。对于physics_process函数来说就是(1/60)秒/帧,对于_process函数来说会根据计算机当前运行的性能而不固定。所以对于需要物理计算的数值(比如速度、位移距离、碰撞检测)而言,需要乘以delta来执行计算的情况,比如位移的计算:
position+=Vector
4.velocity、position的数值都是Vector向量,所以都需要对应Vector(x,y)赋值。
5.设置能够监听玩家的信号输入:点击Godot左上角的”项目“->”项目设置“->”输入映射“,在Godot中玩家的每一个输入信号都是一个“动作”(action),所以想要玩家往不同方向移动,就要在“创建新动作”空白栏分别添加“上下左右”的信号标,然后点击右侧的“添加”将动作添加到游戏动作中,分别点击“上下左右”动作右侧的“+”号,弹出监听窗口,这个时候Godot就会监听输入信号,比如可以将“W”和“上”信号绑定。
6.利用玩家的信号输入实现控制Character移动:使用Input函数:
func _physics_process(delta: float) -> void:
if is_game_over == false:
velocity=Input.get_vector("left","right","up","down") * move_speed
move_and_slide()
然后就可以每一帧都将获取到玩家的最新速度,不过一般只有1个像素格,类似于(1,0),所以后面还可以乘上其他的大数,使得每一帧移动速度变快。
四、碰撞体
1.添加玩家操作人物无法逾越的“空气墙”:添加Staticbody2D节点,这个节点不会被外力所移动,所以适合做空气墙。创建节点后右侧有黄色三角提醒,因为此时Staticbody节点下缺少Collisionshape2d节点。Collisionshape2d节点是2d游戏中所有物理物体必须有的一个点,用来显示这个物理节点的碰撞形状。在Staticbody2d节点下添加了Collisionshape2d节点后需要在场景树中点击Collisionshape2d节点,在右侧的检查器中可以在“shape”一栏选择形状,然后上方工具栏选择“移动模式”,鼠标拖动选择位置,其中“WorldBoundaryShape2D”很适合做世界的边界线,它是无限延伸的墙。
2.设置多个“WorldBoundaryShape2D”节点的时候可以直接“CTRL+D”复制,然后选择“旋转模式”或使用快捷键“E”进入旋转模式。旋转模式中按住“CTRL+E”可以实现磁吸旋转。
3.有时候调整其中一个CollisonShape位置的时候可能会发现其他CollisonShape一起移动了,这个可能是“移动模式”转“选择模式”(就是平时用的小鼠标)中出现的bug,只要重新点一下上一层的Staticbody2d节点就行了。
4.如果是其他的CollisionShape的shape类型(比如矩形),可以通过“ALT+鼠标拖拽拉伸”实现中心为原点的缩放
5.玩家控制的游戏人物也需要参与碰撞计算,所以也需要绑定一个CollisionShape参与计算。
6.新建敌人的时候可以选择Area2D作为节点,Area2D可以检测其他Collision节点是否碰撞到了它。通过这个节点可以判断玩家是否撞到了怪物或者武器是否撞到了怪物。
7.Area2D节点可以有body_entered和area_enterd函数,body_entered专门用来检测是不是CharacterBody等body节点,area_enterd专门用来检测是不是Area2D这种area类型的节点
五、信号和函数
1.Area2D节点和Characterbody2D节点不同,Area2D节点没有velocity属性,但是可以直接通过修改position来实现移动效果。
2.在Godot的场景树窗口中越靠下的节点在渲染中就有越高的优先级,所以越靠下的节点就会覆盖住靠上的节点,如果想解决这个问题,那么可以选中整个场景树的根节点,在右侧的检查器中选择“ordering”->“Y Sory Enabled”,实现根据元素在Y轴坐标系上的位置进行渲染,Y值越大(越靠下)越优先渲染。
3.信号栏在Godot编辑器右侧“检查器”右边的“节点”中,点击“节点”,下方有“信号”和“分组”,信号中有很多当前节点可以触发的信号,当这个节点在游戏中触发了相应事件(鼠标点击、碰撞)时候出发信号、执行相应代码。
4.双击选中的信号就会跳出“连接信号到方法”的面板,需要选中挂载这个信号的节点就能在代码中进行程序编辑了,如:
func _on_body_entered(body: Node2D) -> void:
if body is CharacterBody2D and not is_dead:
body.game_over()
get_tree().current_scene._game_over_label()
pass # Replace with function body.
5.创建临时倒计时:使用await get_tree().create_timer(倒计时秒数).timeout
func game_over():
await get_tree().create_timer(2).timeout
get_tree().reload_current_scene()
但这种临时创建的create_timer()可能会造成屏幕闪烁一下的效果,这是因为创建的不是普通Timer二是SceneTreeTimer中的create_timer效果,如果不想要这种效果的话就可以用Timer,不用临时的这个。
六、Timer节点
1.Timer节点和Collision节点一样可以在场景中通过“ALT+A"直接添加进来。添加之后在右侧检查器可以看到“Wait Time”的时长是1s,“One Shot"代表只运行一次(如果勾选上代表倒计时结束不会重新开始),“Autostart”代表该场景启动的时候倒计时自动开始。
2.Timer存在一个专属的“timeout()”信号,如果倒计时时长为1秒,那么每隔1秒timeout()都会被触发一次。timeout()也可以直接在信号栏双击信号,连接到对应场景上,就会在场景的代码中自动生成对应函数。
3.Godot可以通过代码直接在场景中创建新的场景(子节点)!如:
@export var bullet_scene:PackedScene
其中PackedScene对应的就是场景的类,然后通过export公布到检查器中,直接把对应节点拖动到检查器中即可!
然后每次需要调用的时候可以使用instantiate()函数来生成一个节点,生成之后还需要通过add_child()来将生成的子节点绑定到根节点上。如:
var bullet_node=bullet_scene.instantiate()
#bullet_node.position=position#将玩家当前的位置赋值给子弹
bullet_node.position=position+Vector2(6,6)
get_tree().current_scene.add_child(bullet_node)
4.性能优化:如果一直生成节点,那么会持续占用电脑的内存,一定要让生成的节点在一定时间/一定条件下被摧毁。摧毁节点使用queue_free()函数。
七、分组功能
1.分组功能非常必要,比如加入设置了怪物、子弹的节点都是Area2D,那么通过area_enterd函数怪物可以因为子弹触碰而触发死亡的相应程序,但也可能因为其他怪物触发而导致死亡,要规避后者就要针对怪物和子弹进行分组。
2.分组面板在“信号”栏的右侧,在“检查器”右侧的“节点”里面。可以针对场景内部设置分组,也可以设置全局分组,使用is_in_group()函数进行判断:
func _on_area_entered(area: Area2D) -> void:
if area.is_in_group("bullet"):
is_dead = true
animator.play("death")
$SlimeDeadSound.play()
area.queue_free()
get_tree().current_scene.score+=1
await get_tree().create_timer(0.5).timeout
queue_free()
3.Clamp函数:会把相应变量中的数值限制在一定范围内:
func _process(delta: float) -> void:
spawn_timer.wait_time-=0.2*delta
spawn_timer.wait_time=clamp(spawn_timer.wait_time,1,3)
八、游戏UI
1.UI指的是User Interface,指的是玩家各种信息的面板,常见的有生命值、得分、装备等,在Godot中,UI和场景物体是分开渲染的。
2.添加UI可以使用CanvasLayer节点,CanvasLayer节点会单独渲染它所有的子节点,然后再覆盖到已有的场景上。添加CanvasLayer后拉远视角,蓝色方框就是CanvasLayer的工作区间,放置在这个范围的UI组件都会被显示在屏幕上。
3.在CanvasLayer中添加一个Label节点就可以设置一个文本UI了,Label节点的检查器中可以设置文字的多种参数,其中文字字体和颜色的设置可以在Themes Overrides中找到。也可以在Constants中设置描边。
4.Label的数值可以修改,可以在代码中设置Label变量,然后通过检查器绑定到这个Label进行修改和后续的操作。
@export var score_label: Label
@export var Game_over_label:Label
score_label.text="Score:"+str(score)
Game_over_label.visible=true
九、音效
1.在Godot中播放声音的操作也是由节点完成的,可以是AudioStreamPlayer,也可以是AudioStreamPlayer2D、AudioStreamPlayer3D,如果选了2D、3D那么声音会有空间性。(屏幕左边就出现在左声道,屏幕右侧出现在右声道),而AudioStreamPlayer就没有任何空间性。新建AudioStreamPlayer节点后也是通过拖动的方式把音乐拖动到检查器的对应位置。
2.AudioStreamPlayer有多种属性,Volume dB表示声音大小,Pitch Scale表示音高,数值越大声音越尖锐、越快,数值越小声音越低沉、越慢。
3.直接使用play()、playing()函数检测声音播放状态:
func _physics_process(delta: float) -> void:
if is_game_over == false:
velocity=Input.get_vector("left","right","up","down") * move_speed
# 如果速度为0,播放静止动画:
if velocity==Vector2.ZERO:
animator.play("idle")
$RunningAudio.stop()
# 如果速度不为0,播放跑步动画:
else :
animator.play("run")
if not $RunningAudio.playing:
$RunningAudio.play()
move_and_slide()
4.对于需要循环播放的音效(比如跑步音效)可以在音效导入前勾选“循环播放”然后重新导入。
5.对于需要循环播放的BGM,如果放在场景里面,那么场景重开的话BGM也会被重开,如果要实现场景重开而BGM继续播放的效果,就需要将BGM节点放置在重开的这个场景之外,可以使用Godot的自动加载功能。首先先把BGM节点勾选右键选择“将分支保存为场景”,然后删除原BGM场景,通过“项目”->“项目设置”->“全局”->“自动加载”可以选择BGM场景为自动加载场景,那么BGM就不会因为主场景重开而重新加载了。对了BGM一定要在检查器中选择"AutoPlay“这样一进去就可以自动播放了。
十、游戏导出
1.解决不同分辨率下的窗口缩放问题:在左上方“项目”->“项目设置”->“常规”->“窗口”,将“拉伸”调整为Canvas_Items或viewport模式都可以,一般用Canvas_Items,但像素游戏两者都行,两者的区别在于viewport会让游戏物体强行吸附到每一个像素上,包括旋转操作,但CanvasItems不会,所有如果需要有很强烈的像素风,是可以用viewport的。
2.自动进入全屏模式:还是在左上方“项目”->“项目设置”->“常规”->“窗口”中,在“模式”里选择Exclusive FullScreen模式就是全屏模式了:
3.导出游戏:Godot本体非常小,没有导出游戏的相应模板,所以要在左上方工具栏“编辑器”->“管理导出模板”中选择“最佳可用镜像”,然后点击“下载并安装”。亲测内外网都可以下载。
4.将导出模板安装完成后,就可以通过左上角的“项目”->“导出”来进行游戏导出了。游戏模板一般都是配置好的可以直接用,其中在WINDOWS导出模板里面,如果勾选了“内嵌PCK”那么就会生成单一的EXE文件。