第一个2DGodot游戏-从零开始-逐步解析

视频教程地址:https://www.bilibili.com/video/BV1Hw411v78Y/
前言
大家好,这一集我将要带领大家完成官方文档里的第一个2DGodot游戏,从零开始,逐步解析,演示游戏的制作全过程,尽量让,就算是新入坑的兄弟也能流畅清晰地完成这个项目。
之所以做这个视频是因为,有些才入门学习的兄弟在自己看文档学习的过程中,难免会有一些暂时疑惑,懵懵懂懂的地方,有时候如果少看了文档中某一步骤或者细节,后面再逐步找错是非常麻烦的。
所以在这个视频中,这个游戏制作的思路,代码作用,我会尽量都讲一下,将大家的疑惑最小化。
同时,基于Godot4.1的这个游戏的完整的项目文件和游戏素材都可以在我的项目仓库或者是共享群文件中都可以找到。
首先我们来看一下游戏的效果:
下面我们开始项目的讲解:
思路讲解
首先,我们需要知道我们要做的游戏,并且理清楚游戏的思路。
游戏就是简单的躲避游戏,控制我们的小人在屏幕中运动,躲避随机生成的敌人,如果碰到了敌人,那我们就输了,游戏的分数就是我们的生存时间,时间越久分数越高。
好了,游戏的思路就是这么简单,但我们做出这个游戏只有这些大白话描述的规则肯定是远远不够的。我们要将其转化为方便我们做出游戏程序的语言,也就是分析出游戏中包含的模块,对象及其功能。
那么我们的游戏可以分析拆分出什么呢?
根据文档中的思路,我们将其拆分为以下几部分:
主场景,敌人场景,玩家场景,平视显示器HUD,
并且我整理出每个场景我们需要做的事情,如下:
项目设置:窗口大小:480,720
主场景(Main):
- 新建Node节点命名为Main- 实例化子场景player命名为Player- 添加三个计时器Timer,分别命名为MobTimer,ScoreTimer,StartTimer,时间分别设置为0.5,1,2s,StartTimer设置为仅播放一次,其他默认无限播放- 新建AudioStreamPlayer2D,命名为DeathSound,阵亡时播放的音乐- 新建AudioStreamPlayer2D,命名为Music,作为bgm,Looping设置为启用- 新建Maker2D,命名为StartPosition,将position改为240,450- 新建Path2D,将其命名为MobPath,在窗口四边为其添加路径,添加子节点PathFollow2D将其命名为MobSpawnLocation- 新建ColorRect,设置背景颜色,层级后移- 实例化子场景hud命名为HUD- 绑定脚本,联系多个场景组件- 游戏开始,结束对应操作- 设置敌人随机出现运动- 定义一些函数
敌人(Mob):
- 新建RigidBody2D,命名为Mob,修改重力缩放为0- 添加子节点AnimatedSprite2D,并为其设置fly,walk,swim动画帧- 设置碰撞区域CollisionShape2D,调整其形状大小与图片吻合,取消mask层,避免敌人间相互碰撞- 命名对象组- 按照喜好设置缩放比- 绑定脚本
玩家(Player):
- 新建Area2D,命名为Player- 新建AnimatedSprite2D,设置up与walk动画- 新建碰撞区域CollisionShape2D,调整大小- 根据喜好设置合适的缩放比- 绑定脚本- 设置上下左右映射- 速度归一化- 设置碰撞函数回调,碰撞信号
平视显示器(HUD)
这是一种信息显示,显示为游戏视图顶部的叠加层。
CanvasLayer 节点允许我们在游戏其余部分上方的图层上绘制 UI 元素,这样它显示的信息就不会被任何游戏元素(如玩家或生物)所掩盖。
- 新建CanvasLayer命名为HUD- 新建Label,命名为ScoreLabel,上中,设置字体及大小,用于显示分数- 新建Label,命名为Message,居中,用于显示一些信息- 新建Button,命名为StartButton,中下,用于点击触发函数开始游戏再来一次- 新建Timer,命名为MessageTimer,消息显示的倒计时- 添加脚本
接着我们准备游戏素材,直接文档中下载,然后拖进我们的项目文件夹。
反派在文档中将其命名为mob/mɑːb/,我们查询了一下翻译,是这个意思,不知道大家会不会享受这种顺便背单词的感觉,当然,你可以将它命名为任何你喜欢的名字。在这里,我们和文档保持一致,就命名为mob。

代码
Player.gd
extends Area2Dsignal hit# 玩家移动速度
@export var speed = 400
# 屏幕尺寸
var screen_sizefunc _ready():screen_size = get_viewport_rect().sizeprint(screen_size)func _process(delta):# 玩家的移动向量var velocity = Vector2.ZEROif Input.is_action_pressed("move_right"):velocity.x += 1if Input.is_action_pressed("move_left"):velocity.x -= 1if Input.is_action_pressed("move_down"):velocity.y += 1if Input.is_action_pressed("move_up"):velocity.y -= 1if velocity.length() > 0:# 归一化处理velocity = velocity.normalized() * speed$AnimatedSprite2D.play()else:$AnimatedSprite2D.stop()position += velocity * deltaposition = position.clamp(Vector2.ZERO, screen_size)# 如果x轴速度不是0的话,播放行走动画,if velocity.x != 0:$AnimatedSprite2D.animation = "walk"# 防止上下移动后垂直翻转的状态保留$AnimatedSprite2D.flip_v = false$AnimatedSprite2D.flip_h = velocity.x < 0 elif velocity.y != 0:$AnimatedSprite2D.animation = "up"$AnimatedSprite2D.flip_v = velocity.y > 0func start(pos):# 显示玩家,显示刚体position = posshow()$CollisionShape2D.disabled = falsefunc _on_body_entered(body):# 被撞后隐藏玩家,提交撞击信号print('被撞了')hide()hit.emit()$CollisionShape2D.set_deferred("disabled", true)
Mob.gd
extends RigidBody2Dfunc _ready():var mob_types = $AnimatedSprite2D.sprite_frames.get_animation_names()$AnimatedSprite2D.play(mob_types[randi() % mob_types.size()])func _on_visible_on_screen_notifier_2d_screen_exited():# 安全删除对象queue_free()
HUD.gd
extends CanvasLayersignal start_gamefunc show_message(text):$Message.text = text$Message.show()$MessageTimer.start()func show_game_over():# 显示文本并且开启消息计时器show_message("游戏结束!")# 等待消息计时器结束await $MessageTimer.timeout$Message.text = "躲避坏蛋!"$Message.show()# 创建一个一秒的延迟await get_tree().create_timer(1.0).timeout$StartButton.show()func update_score(score):$ScoreLabel.text = str(score)func _on_start_button_pressed():$StartButton.hide()start_game.emit()func _on_message_timer_timeout():$Message.hide()
Main.gd
extends Node@export var mob_scene: PackedScene
var scorefunc _ready():passfunc game_over():$Music.stop()$DeathSound.play()print('游戏结束')$ScoreTimer.stop()$MobTimer.stop()$HUD.show_game_over()func new_game():$Music.play()get_tree().call_group("mobs", "queue_free")score = 0$Player.start($StartPosition.position)$StartTimer.start()$HUD.update_score(score)$HUD.show_message("Get Ready")func _on_score_timer_timeout():score += 1$HUD.update_score(score)func _on_start_timer_timeout():$MobTimer.start()$ScoreTimer.start()func _on_mod_timer_timeout():# 创建一个敌人实例var mob = mob_scene.instantiate()# 从Path2D上随机选取一个点对象,randf()返回一个浮点数0.0-1.0,progress_ratio为路径偏移量,长度乘百分比var mob_spawn_location = get_node("MobPath/MobSpawnLocation")# 设置随机位置mob_spawn_location.progress_ratio = randf()mob.position = mob_spawn_location.position# 设置敌人的随机运动方向。即垂直于边框,再加上一点随机var direction = mob_spawn_location.rotation + PI / 2direction += randf_range(-PI / 4, PI / 4)mob.rotation = direction# 设置敌人速度var velocity = Vector2(randf_range(150.0, 250.0), 0.0)mob.linear_velocity = velocity.rotated(direction)# 添加敌人对象到主场景add_child(mob)
注意将信号与方法联系起来,每个场景之中的节点信号与方法,还有两个就是start_game信号与hit信号分别对应的开始游戏与结束游戏。
相关文章:
第一个2DGodot游戏-从零开始-逐步解析
视频教程地址:https://www.bilibili.com/video/BV1Hw411v78Y/ 前言 大家好,这一集我将要带领大家完成官方文档里的第一个2DGodot游戏,从零开始,逐步解析,演示游戏的制作全过程,尽量让,就算是新…...
大数据学习(7)-hive文件格式总结
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博>主哦&#x…...
GRU的 电影评论情感分析 - python 深度学习 情感分类 计算机竞赛
1 前言 🔥学长分享优质竞赛项目,今天要分享的是 🚩 GRU的 电影评论情感分析 - python 深度学习 情感分类 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:3分创新点:4分 这…...
kafka简述
前言 在大数据高并发场景下,当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。一般选型是Kafka、RocketMQ,这源于这些中间件的高吞吐、可扩展以及可靠…...
《RISC-V体系结构编程与实践》的benos_payload程序——mysbi跳转到benos分析
1、benos_payload.bin结构分析 韦东山老师提供的开发文档里已经对程序的结构做了分析,这里不再赘述,下面是讨论mysbi跳转到benos的问题; 2、mysbi跳转到benos的代码 3、跳转产生的疑问 我认为mysbi.bin最后跳转到0x22000地址处执行࿰…...
ad5665r STM32 GD32 IIC驱动设计
本文涉及文档工程代码,下载地址如下 ad5665rSTM32GD32IIC驱动设计,驱动程序在AD公司提供例程上修改得到,IO模拟的方式进行IIC通信资源-CSDN文库 硬件设计 MCU采用STM32或者GD32,GD32基本上和STM32一样,针对ad566r的IIC时序操作是完全相同的. 原理图设计如下 与MC…...
TensorFlow入门(十六、识别模糊手写图片)
TensorFlow在图像识别方面,提供了多个开源的训练数据集,比如CIFAR-10数据集、FASHION MNIST数据集、MNIST数据集。 CIFAR-10数据集有10个种类,由6万个32x32像素的彩色图像组成,每个类有6千个图像。6万个图像包含5万个训练图像和1万个测试图像。 FASHION MNIST数据集由衣服、鞋子…...
CSwin Transformer 学习笔记
Cswin提出了上图中使用交叉形状局部attention,为了解决VIT模型中局部自注意力感受野进一步增长受限的问题,同时提出了局部增强位置编码模块,超越了Swin等模型,在多个任务上效果SOTA(当时的SOTA,已经被SG Fo…...
Linux上通过mysqldump命令实现自动备份
Linux上通过mysqldump命令实现自动备份 直接上代码 #!/bin/bash mysql_user"root" mysql_host"localhost" mysql_port"3306" mysql_charset"utf8mb4"backup_location/home/mysql/mysql_back/sql # 是否开始自动删除过期文件,过期时间…...
v-model与.sync的区别
我们在日常开发的过程中,v-model指令可谓是随处可见,一般来说 v-model 指令在表单及元素上创建双向数据绑定,但 v-model 本质是语法糖。但提到语法糖,这里就不得不提另一个与v-model有相似功能的双向绑定语法糖了,这就是 .sync修饰符。在这里就两者的使用进行一下比较和总结: …...
Linux---进程(1)
操作系统 传统的计算机系统资源分为硬件资源和软件资源。硬件资源包括中央处理器,存储器,输入设备,输出设备等物理设备;软件资源是以文件形式保存在存储器上的成熟和数据等信息。 操作系统就是计算机系统资源的管理者。 如果你的计…...
C# U2Net Portrait 跨界肖像画
效果 项目 下载 可执行文件exe下载 源码下载...
华为云云耀云服务器L实例评测|华为云耀云服务器L实例评测包管理工具安装软件(六)
七、华为云耀云服务器L实例评测包管理工具安装软件: 根据企业级项目架构图所示,本章主要是安装公司企业项目的基本环境LNMP,相关的包管理器Composer、Node、Npm、Yarn安装,评测一下包管理工具安装软件是否存在问题,如果…...
在PYTHON中用zlib模块对文本进行压缩,写入图片的EXIF中,后在C#中读取EXIF并用SharpZipLib进行解压获取压缩前文本
在PYTHON中用zlib模块对文本进行压缩长度,写入图片的EXIF中,并在C#中读取EXIF后用SharpZipLib进行解压缩获取压缩前文本。 PS:当压缩后的字节数组长度为单数时,无法写入EXIF的XPComment中,需要在后面增加一个以utf-8编码的空格&a…...
centos / oracle Linux 常用运维命令讲解
目录 1.shell linux常用目录: 2.命令格式 3.man 帮助 4.提示符 5.echo输出字符串或变量值 6.date显示及设置系统的时间或日期 7.重启系统 8.关闭系统 9.登录注销 10.wget 下载文件 11.ps 查看系统的进程 12.top动态监视进程信息和系统负载等信息 13.l…...
EMNLP 2023 录用论文公布,速看NLP各领域最新SOTA方案
EMNLP 2023 近日公布了录用论文。 开始前以防有同学不了解这个会议,先简单介绍介绍:EMNLP 是NLP 四大顶会之一,ACL大家应该都很熟吧,EMNLP就是由 ACL 下属的SIGDAT小组主办的NLP领域顶级国际会议,一年举办一次。相较于…...
互联网Java工程师面试题·Java 并发编程篇·第三弹
目录 26、什么是线程组,为什么在 Java 中不推荐使用? 27、为什么使用 Executor 框架比使用应用创建和管理线程好? 27.1 为什么要使用 Executor 线程池框架 27.2 使用 Executor 线程池框架的优点 28、java 中有几种方法可以实现一个线程…...
mac jdk的环境变量路径,到底在哪里?
在mac 电脑中,直接执行 java -version 显示Jdk的版本为1.8 然后打印Java环境变量 在终端中执行 echo $JAVA_HOME 1、情况一:发现环境变量是空的 我草,没配置环境变量怎么能使用Java ,和查看jdk版本 2、情况二:环…...
PyQt5 PyQt6 Designer 的安装
pip国内的一些镜像 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.…...
数据库:Hive转Presto(四)
这次补充了好几个函数,并且新加了date_sub函数,代码写的比较随意,有的地方比较繁琐,还待改进,而且这种文本处理的东西,经常需要补充先前没考虑到的情况,要经常修改。估计下一篇就可以补充完所有…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...
Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...
