本篇笔记是对[想在2025年做游戏?用Godot做出你的第一个2D游戏吧:安装Godot_哔哩哔哩_bilibili]的总结

Part0 系统

游戏引擎及导出模板下载官网

设置语言:gamemanager界面右上角Settings

创建新项目:左上角“+创建”

(进入项目之后)

​ 左下角:文件系统 可将外部文件直接拖入以导入 导入的文件可双击预览

​ 左上角:节点管理(场景树)

​ 右侧:检查器

​ 右上角:运行项目

​ 顶部:切换2D 3D 脚本(Script)

​ 顶部下方:切换对节点的选择、移动、旋转、锁定等操作

​ 鼠标中键:拖动视角

​ 鼠标滚轮:缩放视角

​ 中间蓝色框:默认渲染区域

文件管理

​ 游戏场景(.tscn)放在Scenes文件夹

​ 代码文件(.gd)放在Scripts文件夹

设置窗口缩放

项目->项目设置->显示->窗口->拉伸->模式,可选择让场景随窗口放大缩小

viewport 像素吸附

canvas_items 不限像素

管理导出模板

编辑器->管理导出模板->下载或导入

导出项目

项目->导出->添加,选择操作系统->启用内嵌PCK

Part1 搭建场景

添加一个”Node2D“作为根节点

在该Node2D根节点下

​ 添加”Sprite2D“节点作为场景

​ 在右侧的检查器中,将所需的场景拖入”Texture“中

像素风格设置:左上角项目->项目设置->渲染->纹理->将默认纹理过滤设置为Nearest

设置主场景:第一次运行项目时会弹出窗口,将背景场景设置为主场景即可

添加摄像机:Camera2D(粉色方框)

​ 在右侧检查器中,改变”Zoom“的数值以改变方框大小

Part2 创建玩家并添加动画

点击顶部下方场景栏的加号”+“,新建一个场景

添加节点“CharacterBody2D”作为玩家的根节点

在该节点下添加”AnimatedSprite2D“节点

左侧会出现一个黄三角警告,需要在右侧检查器中,设置"SpriteFrames"图片帧

点击Animation->SpriteFrames右边的<空>,新建SpriteFrames,再点击创建好的SpriteFrames即可打开之

在下方的SpriteFrames栏中,上侧的网格图标可分割并添加数个图片,组成一个动画(如”idle“待机动画)

​ 动画帧率可调

​ 可设置游戏开始时就自动播放某一动画

将玩家场景添加到主场景:回到主场景(背景场景)左侧节点栏上方,用链接图标即可将某一场景添加到主场景

Part3 添加代码

为玩家添加代码:选中玩家场景的根节点,点击右上侧一个有绿色加号的图标

​ 使用Node:Default模板

​ 可通过”创建“新代码或”加载“已有代码的方式将代码挂载到某一节点

Part4 操控玩家

为玩家设置速度(附2之5,6)

以键盘操控玩家移动

​ 接收输入信号:项目->项目设置->输入映射->添加新动作并分配键位

实时检测键盘的输入(附2之8)

将玩家的速度赋值为输入与速度的乘积,形如:

velocity=Input.get_vector(”left“,"right","up","down")*move_speed

Part5 播放动画

在角色的脚本中,声明一个类型为AnimatedSprite2D的变量animator,并使其暴露在检测器中(附2之10)

在检测器中,给animator的“Animator”赋值(可拖动或选择)为Part2中创建的AnimatedSprite2D节点(在场景树中)

在特定情况下播放动画,如在角色速度为0时播放待机(idle)动画,否则播放跑步动画,形如:

if velocity == Vector2.ZERO:
animator.play("idle")
else:
animator.play("run")

Part6 添加碰撞体-场景边界空气墙

在主场景中,添加一个"StaticBody2D"节点

​ 在其之下添加"CollisionShape2D"节点

​ 在右侧的检查器中为其添加“Shape”,其中的“WorldBoundaryShape2D”适合用来做空气墙,检查器中的“Transform”->"Position"可用于精确调整位置

可将所有空气墙整合到一个Node2D节点下,并锁定,以使场景整洁

Part7 添加碰撞体-角色

在角色场景的根节点下,添加一个“CollisionShape2D”节点

​ 在右侧的检查器中添加“Shape”,用合适的图形概括角色外形。

Part8 创建敌人

新建场景,以“Area2D”作为敌人的根节点

​ Area2D是一个物理节点,可检测是否有别的物理节点碰到了它

用“AnimatedSprite2D”为敌人添加动画,方法同前

用“CollisionShape2D”为敌人添加碰撞体,方法同前

回到主场景,注意不要选中任何节点,将敌人的场景链接到主场景中

Area2D下没有velocity参数,但可以通过改变position来控制敌人的移动,形如:

position += Vector2(-100,0) * delta

(若不加“* delta”则会导致按帧改变位置,使移速过快)

解决玩家与怪的叠放次序问题:

​ 按照物体在y轴上的坐标来渲染:选中根节点->在右侧检查器中选择"Ordering"->勾选 Y Sort Enabled

Part9 碰撞检测

来到敌人场景->右侧节点面板下找到信号栏->选择body_entered(body: Node2D)->选择敌人节点并连接

自动创建了如下函数

func _on_body_entered(body: Node2D) -> void:

每次body entered信号被触发,该函数下语句便会被执行

需判断敌人碰到的是玩家而非他物:

if body is CharacterBody2D: #body指碰到的物体

Part10 游戏结束并刷新场景

实现”碰到敌人就输掉游戏“

来到玩家代码,添加函数:

func game_over():
get_tree().reload_current_scene() #重新加载当前场景

回到敌人代码

if body is CharacterBody2D: #body指碰到的物体
body.game_over() #body即代指玩家,可直接调用写好的game_over函数

设置游戏结束时玩家的动画,在game_over函数中:

await get_tree().create_timer(3).timeout #等待3秒倒计时

可使用bool型变量记录游戏是否结束

添加失败动画,方法同前

在game_over函数中,播放该动画:

animator.play("game_over")

总结如下:

func game_over():
animator.play("game_over")
await get_tree().create_timer(3).timeout
get_tree().reload_current_scene()

Part11 不断发射子弹

新建场景,Area2D作根节点,Sprite2D作子弹图片,CollisionShape2D作碰撞体

添加脚本:子弹移动同前

每隔一段时间就发射子弹

回到玩家节点,添加“Timer”节点,在右侧的检查器中,不勾选“One Shot”以使循环执行,勾选“Autostart”以使在游戏开始时自动执行

在Timer的节点->信号栏中,双击“timeout()“,将其连接到玩家的代码上,可将其命名成”_on_fire“

可在Timer节点的检查器中对这个倒计时循环进行精细的控制

声明一个类型为”PackedScene“的变量来储存子弹的场景,命名为”bullet_scene“

在_on_fire函数下,新声明一个局部变量bullet_node来存子弹场景,并让其生成在玩家边合适的位置:

func _on_fire() -> void
var bullet_node = bullet_scene.instantiate()
bullet_node.position = position #前一个position是子弹的,后一个是玩家的
get_tree().current_scene.add_child(bullet_node)

回到玩家场景的根节点,将右侧检查器中的“Bullet Scene”快速加载为子弹的场景

可在_on_fire函数中自由设计开火条件(如只能站定才能开火,游戏结束后无法开火等)

Part12 性能优化

在子弹的_ready()函数加添加一个倒计时(附2之16)

倒计时结束后摧毁生成的子弹(附2之20)

Part13 消灭敌人-分组功能

给敌人添加被消灭的动画,方法同前,注意死亡动画不需要重复播放

检测敌人被子弹打到

回到敌人场景根节点,添加area_entered(area: Area2D)信号,并连接到敌人的代码

区分敌人和子弹,避免敌人碰到自己人而触发被消灭

回到子弹场景,右侧节点->分组->添加分组并命名为“bullet”

回到敌人代码,判断撞到的是否为子弹:

func _on_area_entered(area: Area2D) ->void
if area.is_in_group("bullet"):#被子弹撞到了
#让敌人停止运动
$CollisionShape2D.queue_free() #删除敌人碰撞体积,防止尸体吞箭
#摧毁打死敌人的子弹
#播放死亡动画
#摧毁死亡的敌人

Part14 不断生成敌人

在主场景的根节点上(重点)新建代码“GameManager”

回到主场景,添加一个Timer节点,勾选Autostart

在该Timer节点的信号面板中,双击timeout(),选中根节点的GameManager以连接,可命名为_spawn_slime()

希望敌人随机生成在一定范围中

​ 范围赋值为随机值(附2之23)

生成敌人和生成子弹代码类似:

@export var slime_scene : PackedScene

func _spawn_slime() -> void:
var slime_node = slime_scene.instantiate()
slime_node.position = Vector2(x,randf_range(a,b))
get_tree().current_scene.add_child(slime_node)

选中场景根节点,在右侧的检查器中看到Slime Scene变量,将其设置成敌人的场景

使敌人生成得越来越快

声明一个类型为Timer的变量spawn_timer,通过控制它来控制生成间隔,记得在检查器中将其设置到连接了生成敌人代码的Timer上。

func _process(delta: float) -> void:
spawn_timer.wait_time -= 0.2 * delta
spawn_timer.wait_time = clamp(spawn_timer.wait_time,1,3)

敌人到达左侧边界,则摧毁

if position.x < value:
quene_free()

Part15 记分

在GameManager代码中,声明一个记分的变量score:

@export var score : int = 0

在敌人被消灭的代码中,获取主场景的根节点(因为GameManager连接在那)

get_tree().current_scene.score += 1

Part16 UI

回到主场景,添加"CanvasLayer"节点,出现的蓝色大框为其渲染区

在CanvasLayer之下,添加“Label”节点,在右侧检查器的Text中编辑文字,可自由设置文字参数

如:Theme Overrides中可设置字体、颜色、大小等

在其下Fonts可快速加载某一字体文件(.ttf)

显示分数

来到GameManager代码,声明一个类型为Label的变量

@export var score_label : Label

将score节点拖动到GameManager检查器中的score_label中

在process函数中实时显示分数:

score_lable.text = "Score: " + str(score)

显示Game Over

创建好节点后,先点右侧眼睛按钮让它隐藏

在玩家死亡代码中,告诉GameManager播放gameover

get_tree().current_scene.show_game_over()

在GameManager中设置show_game_over函数,显示gameover

@export var game_over_label: Label
func show_game_over()
game_over_label.visible = true

在检查器中将game over label设置成gameover节点

Part17 音乐音效

需要循环播放的,要在预览界面勾选“循环”并重新导入

音效

来到玩家场景,添加节点“AudioStreamPlayer”

将音效文件拖入节点右侧检查器中,可调节其参数

可使用拖动的方式,将音效节点拖到对应的代码函数中,使其按需播放

可用.play()或.stop()来控制其播放与停止

.playing 表示它正在播放,是一种状态

背景音乐

在主场景添加节点“AudioStreamPlayer”,将BGM文件拖入检查器,勾选Autoplay

令失败重启不影响BGM播放

让BGM节点存在于主场景节点之外,使用godot自动加载功能,与主场景同时存在

将BGM保存为一个场景,而非节点

左上角项目->项目设置->全局->自动加载->BGM场景->+添加

附1 快捷键

2D界面中按F 使选中的节点居中

ctrl+A 新建节点

ctrl+Z 撤回

ctrl+D 复制并粘贴

ctrl+S 保存

ctrl+X 剪切整行代码

旋转中按住ctrl 磁吸

F5 运行项目

F8 退出运行

附2 系统函数与参数

func _ready() -> void:

该函数下的语句会在游戏开始运行时或被加入场景时被执行

print()

输出括号中的内容

func _process(delta: float) -> void:

该函数下的语句会在游戏的每一帧被执行(基于电脑可能有所不同)

若改成 _physics_process则会以固定60帧/秒运行

extends CharaceterBody2D

出现在代码顶端,表示该代码是由CharaceterBody2D类型延申而来,可用其下的参数

velocity = v

CharacterBody2D特有的参数,给节点速度赋值v

Vector2(x,y)

二维向量,能表示在x轴,y轴上的数值

move_and_slide()

CharacterBody2D特有的功能,可让该节点以设置好的velocity来移动

Input.get_vector(negative_x,positive_x,negative_y,positive_y)

获取左,右,上,下四个方向上的输入

var a : int = 1

声明a是一个值为1的整型变量

@export

将某个变量暴露在左侧检查器中

Vector2.ZERO

向量值为0,可用于判断速度是否为零,形如velocity == Vector2.ZERO

animator.play()

animator为自定义的AnimatedSprite2D类型变量,该函数功能为播放括号中指定的动画

position

节点的世界坐标

func _on_body_entered(body: Node2D) -> void:

Area2D的函数,每次body entered信号被触发(碰到物体),该函数下语句便会被执行

get_tree().reload_current_scene()

重新加载当前场景

get_tree().create_timer(t).timeout

创建倒计时,括号中的t为具体的时间

bullet_scene.instantiate()

bullet_scene为自定义的PackedScene类型变量,该函数可生成一个bullet_scene节点

get_tree().current_scene.add_childe(node)

将第二个括号中的node节点变成当前场景的子节点

return

提前结束函数

queue_free()

摧毁当前节点

area.is_in_group("group1")

这个area场景属于分组“group1”

area.queue_free()

摧毁area节点

randf_range(a,b)

a~b之间随机生成一个数(含a不含b)

clamp(value,min,max)

将value的值限制在min和max之间

附3 报错

1.indented

与缩进有关的报错

Godot 2D游戏开发笔记的更多相关文章

  1. Phaser是一款专门用于桌面及移动HTML5 2D游戏开发的开源免费框架

    Phaser是一款专门用于桌面及移动HTML5 2D游戏开发的开源免费框架,提供JavaScript和TypeScript双重支持,内置游戏对象的物理属性,采用Pixi.js引擎以加快Canvas和W ...

  2. 关于《Unity3D/2D游戏开发从0到1》书籍再版说明

    关于<Unity3D/2D游戏开发从0到1>第一版本在2015年7月1日全国发行,累计得到不少国内高校教师.培训机构的好评.但是由于Unity官方对于技术不断的升级与版本的快速迭代,基于U ...

  3. 《Unity3D/2D游戏开发从0到1(第二版本)》 书稿完结总结

    前几天,个人著作<Unity3D/2D游戏开发从0到1(第二版)>经过七八个月的技术准备以及近3个月的日夜编写,在十一长假后终于完稿.今天抽出一点时间来,给广大热心小伙伴们汇报一下书籍概况 ...

  4. 《Unity3D/2D游戏开发从0到1》正式出版发行

    <Unity3D/2D游戏开发从0到1>正式出版发行 去年个人编写的Unity书籍正式在2015年7月正式发行,现在补充介绍一下个人著作.书籍信息:      书籍的名称: <Uni ...

  5. Unity 2D游戏开发教程之精灵的死亡和重生

    Unity 2D游戏开发教程之精灵的死亡和重生 精灵的死亡和重生 目前为止,游戏项目里的精灵只有Idle和Walking这两种状态.也就是说,无论精灵在游戏里做什么,它都不会进入其它的状态,如死亡.于 ...

  6. Unity 2D游戏开发教程之摄像头追踪功能

    Unity 2D游戏开发教程之摄像头追踪功能 上一章,我们创建了一个简单的2D游戏.此游戏中的精灵有3个状态:idle.left和right.这看起来确实很酷!但是仅有的3个状态却限制了精灵的能力,以 ...

  7. Unity 2D游戏开发教程之2D游戏的运行效果

    Unity 2D游戏开发教程之2D游戏的运行效果 2D游戏的运行效果 本章前前后后使用了很多节的篇幅,到底实现了怎样的一个游戏运行效果呢?或者说,游戏中的精灵会不会如我们所想的那样运行呢?关于这些疑问 ...

  8. Unity 2D游戏开发教程之使用脚本实现游戏逻辑

    Unity 2D游戏开发教程之使用脚本实现游戏逻辑 使用脚本实现游戏逻辑 通过上一节的操作,我们不仅创建了精灵的动画,还设置了动画的过渡条件,最终使得精灵得以按照我们的意愿,进入我们所指定的动画状态. ...

  9. Unity 2D游戏开发教程之游戏精灵的开火状态

    Unity 2D游戏开发教程之游戏精灵的开火状态 精灵的开火状态 “开火”就是发射子弹的意思,在战争类型的电影或者电视剧中,主角们就爱这么说!本节打算为精灵添加发射子弹的能力.因为本游戏在后面会引入敌 ...

  10. Unity 2D游戏开发教程之游戏中精灵的跳跃状态

    Unity 2D游戏开发教程之游戏中精灵的跳跃状态 精灵的跳跃状态 为了让游戏中的精灵有更大的活动范围,上一节为游戏场景添加了多个地面,于是精灵可以从高的地面移动到低的地面处,如图2-14所示.但是却 ...

随机推荐

  1. git记住多个账号

    前言 git每次推送都需要输入密码,或者两个不同账号间互顶. 如何处理这些问题呢? 两种途径:记住ssh协议公钥和记住多个密码. 前者我一直不推荐,所以不提. git配置文件 git全局的用户名.账号 ...

  2. SJGC 笔试 反思

    1.考察text-align的属性值(不属于) 应该选择top 和  justify  好伤心 只选择了top 2. 考察  instanceof 和 null  和  NaN 但null返回obje ...

  3. jlink + jz2440 + win10 操作方式

    ### 重新烧写 jlink uboot.bin `http://www.jz2440.com/started/j-flash/nor-flash烧写-以uboot为例` 1.第一阶段  通过 jli ...

  4. leetcode 69 x 的平方根 牛顿迭代法

    简介 简单的题, 直接上代码. 其实还挺复杂的. 参考链接 https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by- ...

  5. Golang基础笔记十一之日期与时间处理

    本文首发于公众号:Hunter后端 原文链接:Golang基础笔记十一之日期与时间处理 本篇笔记介绍 Golang 里日期与时间的处理,以下是本篇笔记目录: 当前日期与时间的获取 字符串与时间格式的互 ...

  6. Rust中的代码组织:package/crate/mod

    刚接触Rust遇到一堆新概念,特别是package, crate, mod 这些,特别迷糊,记录一下 一.pakcage与crate 当我们用cargo 创建一个新项目时,默认就创建了一个packag ...

  7. Git--进阶2 分支的理解--九五小庞

    分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN. 如果两个平行宇宙互不干扰,那对现在的你也没啥影响.不过,在某个时间点,两个平行宇宙合并 ...

  8. Win10系统如何清理Hosts文件的问题

    近期有电脑基地用户在电脑的文件过程中发现有一个叫Hosts文件,Hosts文件是做什么的呢?Hosts文件一般用于填补或替代网络里DNS功能的,但是由于Hosts文件中的信息过多会影响到电脑网上,所以 ...

  9. ansible-playbook批量安装tomcat8版本

    ansible-playbook 进行批量安装tomcat8  ansible-playbook 进行安装tomcat操作 说明: 先下载好对应版本的tomcat放到本地目录,然后通过playbook ...

  10. Claude Code:AI编程的深度体验与实践

    前言:从代码补全到智能协作的进化 在AI技术日新月异的今天,开发者们正经历着一场前所未有的效率革命.面对日益复杂的开发需求和快速迭代的技术栈,借助AI工具提升开发效率已不再是选择题,而是必选项. 我的 ...