Godot 4 教程《勇者传说》依赖注入 学习笔记(0):环境配置
文章目录
- 前言
- 相关地址
- 环境配置
- 初始化环境配置
- 文件夹结构
- 代码结构
- 代码运行
- 资源文件导入
- 像素风格窗口环境设置
- 背景设置,Tileap使用
- 自动TileMap
- 人物场景
- 动画节点添加
- 站立节点添加
- 移动动画添加
- 通过依赖注入获取Godot的全局属性
- 项目声明
- 当前项目逻辑讲解
- 角色下降
- 添加代码
- 位置问题的思考
- 在Node2D上面挂载Lable节点
- 在CharacterBody2D下面挂载
- 解决方案
- 修改代码
- 动画节点的问题,需要重新绑定
- 为什么我要这么写
- 动画效果
- 初始化AnimationPlayer
- 输入映射
- 获取输入
- 简单移动
- 完善输入和添加动画
- 完善跳跃手感
前言
我之前解决了C# 的IOC的配置,现在来认真学习一个完整的Godot 项目。我看B站上面这个教程非常的好,所以打算用C# 去复刻一下,使用IOC依赖注入的想法。
相关地址
十分钟制作横版动作游戏|Godot 4 教程《勇者传说》#0
人物素材
环境素材
Gclove2000/GodotNet_LegendOfPaladin
环境配置
- Windows 10
- .net core 8.0
- Visual Studio 2022
- godot.net 4.2.1
初始化环境配置
Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能
文件夹结构
- Godot:Godot项目+主要游戏逻辑代码
- GodotProgram:帮助类
代码结构
- GodotNet_LegndOfPaladin:Godot主要逻辑
- SceneModels:场景IOC对象
- SceneScirpts:场景对应脚本
- Util: Godot API帮助类
- PackedSceneHelper:打包场景加载
- Program:IOC容器
- GodotProgram:C# 主要逻辑
- Assets:资产文件
- DB:数据库对象
- Interfaces:接口
- Service:服务
- Utils:帮助类
代码运行
资源文件导入
人物素材
环境素材
像素风格窗口环境设置
背景设置,Tileap使用
自动TileMap
Godot 官方2D C#重构(3):TileMap使用
大致实现效果
绘制TimeMap地形需要比较强的熟练度。多多联系即可
人物场景
长按左键选择站立动画
动画节点添加
站立节点添加
点击6次,添加6个关键帧
移动动画添加
和上面的一样
通过依赖注入获取Godot的全局属性
Godot的全局属性是通过字符串的方式获取的,这非常容易出问题。而且我们也希望这种配置信息能在项目启动的时候就获取
Godot ProjectSettings 字符串对应数据
项目声明
public class GodotProjectSettingHelper{private NlogHelper nlogHelper;public readonly float Gravity = 0;public GodotProjectSettingHelper(NlogHelper nlogHelper){this.nlogHelper = nlogHelper;Gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");}}
当前项目逻辑讲解
所以我们新建一个场景的逻辑是
- 新增XXX.tscn
- 挂载XXXScene.sc脚本
- IOC注入XXXSceneModel.cs 类
- PackedSceneHelper添加对应的PackedScene
详情请看我的Github源码
Gclove2000/GodotNet_LegendOfPaladin
角色下降
添加代码
public class PlayerSceneModel : ISceneModel
{private NlogHelper nlogHelper;private GodotProjectSettingHelper godotProjectSettingHelper;public PlayerSceneModel(NlogHelper nlogHelper,GodotProjectSettingHelper godotProjectSettingHelper) {this.nlogHelper = nlogHelper;this.godotProjectSettingHelper = godotProjectSettingHelper;}private CharacterBody2D characterBody2D;public override void Process(double delta){//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);//让物体以这个速度进行移动characterBody2D.MoveAndSlide();nlogHelper.Debug($"x:{characterBody2D.Velocity.X},y:{characterBody2D.Velocity.Y}");}public override void Ready(){nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");}
}
位置问题的思考
我们知道CharacterBody2D就是为了获取CollisionShape2D的位置。因为他的位置取决于重力,物理碰撞,加速度等多方面因素。相当于他的位置是自动变化的
在Node2D上面挂载Lable节点
在CharacterBody2D下面挂载
解决方案
我们只需要CharacterBody2D给我们的位置更改即可,而在Godot中,Position都是相对父节点的位置。所以每次Character移动的时候,我们将CharacterBody2D的位置获取,然后我们将Character的相对位置 设置为0即可
修改代码
public override void Process(double delta)
{//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);//让物体以这个速度进行移动characterBody2D.MoveAndSlide();var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;}
动画节点的问题,需要重新绑定
主要,如果修改动画节点的位置,会导致绑定出现问题
为什么我要这么写
因为我们不一定会写横版战斗游戏,横版战斗是有重力的,但是俯视角战斗又没有重力了,或者说不是垂直向下的重力,而是俯视角的效果。比如【以撒的结合】
动画效果
在Godot中,AnimationPlayer通过【Play】这个函数来播放动画。但是Godot中,Play是通过字符串的形式调用的。为了保证字符串的正确性,我们添加一个Enum枚举类型来对其进行限制
初始化AnimationPlayer
//枚举类型,防止拼写错误
public enum AnimationFlame { REST, idel,running }......public override void Ready()
{nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");//初始化子节点characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");//播放动画animationPlayer.Play(AnimationFlame.idel.ToString());
}
输入映射
我们输入上下左右,一般都是wasd,但是因为我们可能要做手柄,可能也要做移动端。所以最好设置一个输入映射好一些。
我的输入是,wsad是上下左右,【j】/【空格】是跳跃
获取输入
Godot 输入处理
我们在任意一个节点下面去获取按钮事件
public override void Process(double delta)
{//获取move_left对应按下事件if (Input.IsActionPressed("move_left")){nlogHelper.Debug("move_left 按下");}}
简单移动
public const float RUN_SPEED = 200;
.......public override void Process(double delta)
{var velocity = new Vector2();var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());var y = godotProjectSettingHelper.Gravity * (float)delta;var x = direction * RUN_SPEED;//在C# 中,velocity = characterBody2D.Velocity;//X是最终速度,所以不需要相加velocity.X = x;//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。velocity.Y += y;characterBody2D.Velocity = velocity;//让物体以这个速度进行移动characterBody2D.MoveAndSlide();//同步场景根节点位置var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;
}
完善输入和添加动画
using Godot;
using GodotNet_LegendOfPaladin.Utils;
using GodotProgram.Interfaces;
using GodotProgram.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static GodotNet_LegendOfPaladin.Utils.GodotProjectSettingHelper;namespace GodotNet_LegendOfPaladin.SceneModels
{public class PlayerSceneModel : ISceneModel{public const float RUN_SPEED = 200;public const float JUMP_VELOCITY = -300;//枚举类型,防止拼写错误public enum AnimationFlame { idel, running,jump }#region IOC注入private NlogHelper nlogHelper;private GodotProjectSettingHelper godotProjectSettingHelper;public PlayerSceneModel(NlogHelper nlogHelper, GodotProjectSettingHelper godotProjectSettingHelper){this.nlogHelper = nlogHelper;this.godotProjectSettingHelper = godotProjectSettingHelper;}#endregion#region 子节点获取private CharacterBody2D characterBody2D;private AnimationPlayer animationPlayer;private Sprite2D sprite2D;public override void Ready(){nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");//初始化子节点characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");sprite2D = this.Sence.GetNode<Sprite2D>("Sprite2D");//播放动画animationPlayer.Play(AnimationFlame.idel.ToString());}#endregionpublic override void Process(double delta){//初始化速度var velocity = new Vector2();//初始化动画节点var animation = AnimationFlame.idel;var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());var y = godotProjectSettingHelper.Gravity * (float)delta;var x = direction * RUN_SPEED;var isOnFloor = characterBody2D.IsOnFloor();//在C# 中,velocity = characterBody2D.Velocity;//X是最终速度,所以不需要相加velocity.X = x;//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。velocity.Y += y;//如果在地上并且按下跳跃,则直接给一个y轴的速度if(isOnFloor && Input.IsActionJustPressed(InputMapEnum.jump.ToString())){velocity.Y = JUMP_VELOCITY;}if (isOnFloor){if (Mathf.IsZeroApprox(direction)){animation = AnimationFlame.idel;}else{animation = AnimationFlame.running;}}else{animation = AnimationFlame.jump;}//方向翻转if (!Mathf.IsZeroApprox(direction)){sprite2D.FlipH = direction < 0;}characterBody2D.Velocity = velocity;//让物体以这个速度进行移动characterBody2D.MoveAndSlide();//同步场景根节点位置var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;animationPlayer.Play(animation.ToString());}}
}
完善跳跃手感
如果玩过超级马里奥或者别的平台跳跃游戏,都知道有一个手感的东西。就是有个跳跃的提前量。我们现在是正好落地的时候按下跳跃才能跳起来,现在我们将跳跃的按钮进行存储,给与一定的缓冲间隔。
/// <summary>
/// 最长跳跃等待时间
/// </summary>
public const int JUMP_WAIT_TIME = 3000;
/// <summary>
/// 初始化的时候让时间往后退一点,防止时间过快
/// </summary>
private DateTime jumpLastTime = DateTime.Now.AddDays(-1);......
public override void Process(double delta)
{......if (Input.IsActionJustPressed(InputMapEnum.jump.ToString())){jumpLastTime = DateTime.Now;}if (isOnFloor){//如果在地上并且按下跳跃,则直接给一个y轴的速度//超时判断if (jumpLastTime.AddMilliseconds(JUMP_WAIT_TIME) > DateTime.Now){//如果刚好触发了跳跃,给个速度,将jumpLastTime推前velocity.Y = JUMP_VELOCITY;jumpLastTime = DateTime.Now.AddDays(-1);}......}......
}
相关文章:
Godot 4 教程《勇者传说》依赖注入 学习笔记(0):环境配置
文章目录 前言相关地址环境配置初始化环境配置文件夹结构代码结构代码运行 资源文件导入像素风格窗口环境设置背景设置,Tileap使用自动TileMap 人物场景动画节点添加站立节点添加移动动画添加 通过依赖注入获取Godot的全局属性项目声明 当前项目逻辑讲解角色下降添加代码位置问…...
强行让Java和Go对比一波[持续更新]
概述 很多Java开发如果想转Golang的话,比较让Java开发蛋疼的第一是语法,第二是一些思想和设计哲学的Gap,所以我这儿强行整理一波Java和Golang的对比,但是由于GO和Java在很多方面都有不同的设计,所以这些对比的项可以更…...
理解七层网络协议
osi体系结构 上三路(管数据) 应用层 通过http等,把传输的格式,数据打包 处理网络应用。直接为端用户服务,提供各类应用过程的接口和用户接口。例如:HTTP、Tenlent、FTP、SMTP、NFS等。基于TCP的FTP、HTTP…...
网络协议——HTTP协议
目录 编辑 一,HTTP协议基本认识 二,认识URL 三,http协议的格式 1,发送格式 2,回应格式 四,服务端代码 五,http报文细节 1,Post与Get方法 2,Content_lenth 3&…...
八股面试——数据库——索引
索引的概念 B树的概念: 索引的作用 聚簇索引与非聚簇索引 聚簇索引就是主键值,在B树上,通过主键大小(数据在B树叶子节点按主键顺序排序)寻找对应的叶子节点,叶子节点保存的一整条记录。 非聚簇索引&#x…...
【二分查找】Leetcode 二分查找
题目解析 二分查找在数组有序可以使用,也可以在数组无序的时候使用(只要数组中的一些规律适用于二分即可) 704. 二分查找 算法讲解 当left > right的时候,我们循环结束,但是当left和right缩成一个点的时候&#x…...
Python+Vuecil笔记
Nginx 进入目录: C:\nginx-1.20.2\nginx-1.20.2 start nginx 开始 nginx -s stop 停止 nginx -s quit 退出CSS 通过标签去写css 循环展示数据 JS 点击时执行事件 Django 配置media 在seetings里面修改 STATIC_URL /static/ MEDIA_URL /upload/ MEDIA_ROOT os.pat…...
C语言关于随机数知识点的总结
在C语言中,随机数的生成通常依赖于特定的库函数,最常用的是 <stdlib.h> 头文件中的 rand() 函数。以下是对随机数知识点的总结、举例和分析: 随机数知识点总结 1.随机数种子:rand() 函数生成的随机数是伪随机数࿰…...
网络应用层和传输层
网络中有很多协议这些协议的不同导致了分层这一现象,不同层的主要功能不一样。 应用层:应用程序。数据具体如何使用 传输层:关注起点和终点 网络层:关注路径规划 数据链路层:关注相邻节点的转发 物理层࿱…...
Vue3:优化-从响应式数据中获取纯数据
一、情景说明 我们知道,Vue3中,创建变量时,常用ref、reactive来包裹,这样,这个变量就是响应式数据 然而,有时候,我们只需要纯数据 例如,我们在调用后端接口的时候,我们只…...
C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成?
C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成? 手术麻醉系统与医院信息系统的集成是一个关键步骤,它有助于实现信息的共享和流程的协同,从而提高医疗服务的效率和质量。手麻系统与lis、his、pacs等系统的对接是医院信息化建设的重…...
学习CSS Flexbox 玩flexboxfroggy flexboxfroggy1-24关详解
欢迎来到Flexbox Froggy,这是一个通过编写CSS代码来帮助Froggy和朋友的游戏! justify-content 和 align-items 是两个用于控制 CSS Flexbox 布局的属性。 justify-content:该属性用于控制 Flexbox 容器中子项目在主轴(水平方向)…...
springboot项目如何配置跨域?
在Spring Boot项目中配置跨域(CORS,Cross-Origin Resource Sharing)主要是为了允许来自不同源(不同的协议、域名或端口)的前端应用能够访问后端API。Spring Boot提供了多种方式来配置跨域支持。 1. 使用CrossOrigin注…...
实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类
devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…...
算法第三十九天-验证二叉树的前序序列化
验证二叉树的前序序列化 题目要求 解题思路 方法一:栈 栈的思路是「自底向上」的想法。下面要结合本题是「前序遍历」这个重要特点。 我们知道「前序遍历」是按照「根节点-左子树-右子树」的顺序遍历的,只有当根节点的所有左子树遍历完成之后…...
Rust---复合数据类型之字符串与切片(2)
目录 字符串操作删除 (Delete)连接 (Concatenate)字符串转义前情回顾: Rust—复合数据类型之字符串(1) 字符串操作 删除 (Delete) 删除方法仅适用于 String 类型,分别是: pop(),remove(),truncate(),clear(),此外还有drain() 方法。 pop 方法:pop() 方法返回一个 O…...
iOS 应用内网络请求设置代理
主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用,我们可以通过界面来进行设定(是否开启代理、服务端、端口),从而达到类似系统上的设定 具体链接参考:为 iOS 网络请求设置代理…...
什么是MariaDB
2024年4月6日,周六晚上 今晚在Debian12上安装mysql时,运行后却发现是MariaDB MariaDB是一个开源的关系型数据库管理系统(RDBMS),它是MySQL的一个分支和替代品。MariaDB由MySQL的原始开发者之一Michael "Monty&qu…...
【面试八股总结】传输控制协议TCP(三)
参考资料 :小林Coding、阿秀、代码随想录 一、TCP拥塞控制⭐ 1. 慢启动 – Slow Start 慢启动是指TCP连接刚建立,一点一点地提速,试探一下网络的承受能力,以免直接扰乱了网络通道的秩序。 慢启动算法: 初始拥塞窗口…...
今年过去了多少天?(switch)
//今年已经过去了几天? #include <stdio.h> int monthday(int year,int month){switch(month){case 1:return 31;case 2:if ((year % 4 0 && year % 100 ! 0)||year % 400 0){return 29;}else{return 28;}break;case 3:return 31;case 4:return 30;…...
提升团队工程交付能力,从“看见”工程活动和研发模式开始
作者:张裕、雅纯 理想中的研发团队应当具有以下特征: 总是工作在最高优先级的事项上 理想的研发团队能够识别并始终集中精力在当前最紧迫和最有价值的任务上。这需要团队具备出色的项目管理能力和决策能力,以便能够正确评估优先级࿰…...
前端学习之DOM编程案例:全选反选案例
代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>全选反选</title> </head> <body><input type"checkbox" id"all">全选<ul><li><…...
golang map
1.底层实现 2.如何解决hash冲突 3.扩容机制 4.无序 5.非线程安全 6.不可寻址 runtime/map.go 1.底层实现 底层基于hash表实现,实现有2个结构体hmap,bmap,map由若干个桶存储,每个桶存8个元素,使用链地址解决hash冲突 …...
设计模式:享元模式案例
让我们以游戏开发中的棋类游戏(例如国际象棋)为例来展示享元模式的代码实现。在这个例子中,棋子的类型是内部状态,而棋子的位置是外部状态。 Java 代码示例 import java.util.HashMap; import java.util.Map;// 享元接口 interf…...
pandas(day5)
一. 检测重复值 1.1 检测 data pd.read_csv("./teacher/订单数据.csv")检测行与行之前是否有重复值 data.drop_duplicates()检测 列是否有重复值出现, keep first 从前往后判定 , last是从后往前判定data.drop_duplicates(subset["产…...
如何注册midjourney账号
注册Midjourney账号比较简单,准备好上网工具,进入官网 Midjourney访问地址: https://www.midjourney.com/ 目前没有免费使用额度了,会员最低 10 美元/月,一般建议使用30美元/月的订阅方案。了解如何订阅可以查看订阅…...
探索数据结构:特殊的双向队列
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:数据结构与算法 贝蒂的主页:Betty’s blog 1. 双向队列的定义 **双向队列(double‑ended queue)**是一种特殊的队列…...
16_I2C库函数
I2C库函数 1.void I2C_DeInit(I2C_TypeDef* I2Cx);2.void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);3.void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);4.void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);5.void I2C_DMACmd(I2C_Type…...
十八、Rust gRPC 多 proto 演示
十八、Rust gRPC 多 proto 演示 网上及各官方资料,基本是一个 proto 文件,而实际项目,大多是有层级结构的多 proto 文件形式,本篇文章 基于此诉求,构建一个使用多 proto 文件的 rust grpc 使用示例。 关于 grpc 的实现…...
【Linux】Linux64位环境下编译32位报错skipping incompatible的解决办法
本文首发于 ❄️慕雪的寒舍 问题 如题,当我尝试在wsl2的ubuntu中使用-m32选项编译32位程序的时候,出现了下面的两种报错 ❯ g -m32 test.cpp -o test1 && ./test1 In file included from test.cpp:1: /usr/include/stdio.h:27:10: fatal error…...
wordpress屏蔽蜘蛛爬虫/百度查重入口
第一章 Emacs 基础 1.1 理解文件和缓冲区的不同 编辑器并不是对某个文件本身进行编辑。事实上,他们会先把文件的内容放到一个临时性的缓冲区里,然后再对缓冲区里的东西进行编辑。在通知编辑器保存缓冲区的内容之前,存放在磁盘上的原始文件是不…...
新乡做网站公/站长工具seo排名
UIView的常用属性 UIView的常用属性1——父子视图属性 1. superview 获得自己的父控件对象 2. subviews 获得自己的所有子控件对象注意: 一个视图最多只能有一个父视图 一个视图可以有多个子视图UIView的常用属性2——位置尺寸属性 1. frame 控件所在…...
wordpress技巧:开启wordpress多站点功能/建一个网站大概需要多少钱
有一个月没有写goweb,今天在登录MySQL8.0的时候发现闪退,一度怀疑自己把密码记错了(因为密码错误会闪退的),但是始终试不出来,最后发现是服务自动关闭了,重新启动即可。遇到这个问题不要慌张&am…...
万网云主机 wordpress/免费的seo网站下载
1. 导入命名空间。 using Windows.Phone.Devices.Notification; 2. 通过调用对 VibrationDevice 类的静态 GetDefault 方法获取对振动控制器的引用。 VibrationDevice vibrationDevice VibrationDevice.GetDefault(); 3. 通过调用 VibrationDevice 类的 Vibrate 方法开始振动。…...
怎么注册公司最好/廊坊网站排名优化公司哪家好
.NET读取json数据并绑定到对象 原文:.NET读取json数据并绑定到对象需要引用的命名空间: 读取的具体应用: this代表本实体(对象),通过PopulateObject,直接将读取到的json数据与对象进行绑定 Json保存的具体应…...
唐山做网站优化公司/短网址链接生成
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼最近几天一直在redhat6.5 64位版本的linux系统上安装的eas7.5的服务端,但问题多多,快崩溃了,有没有安装过的,有经验的给分享一下啊??目前问题是启用管理控制台…...