Godot 学习笔记(2):信号深入讲解

文章目录

  • 前言
  • 相关链接
  • 环境
  • 信号
    • 简单项目搭建
    • 默认的信号
      • 先在label里面预制接收函数
      • 添加信号
    • 自定义无参数信号
      • 为了做区分,我们在label新增一个函数
    • 自定义带参数信号
      • Button代码
      • label代码
      • 连接信号
    • 自定义复杂参数信号
      • 自定义GodotObject类
      • Button
      • Label
      • 连接信号
    • 父传子
      • Callable,信号回调
        • Button
        • Lable
        • 连接信号
        • 参数个数不对的异常问题
        • 解决异常方法
    • 手动连接信号
    • 信号等待
    • Node注入,取代信号
      • 基于Action的信号模拟
        • Button
  • 总结

前言

这里我们深入学习一下Godot的信号。对于数据流的控制一直是前端最重要的内容。

相关链接

Godot Engine 4.2 简体中文文档

环境

  • visual studio 2022
  • .net core 8.0
  • godot.net 4.2.1
  • window 10

信号

信号就是传输数据的一种方式,信号是单向数据流,信号默认是从下往上传递数据的。即子传父

简单项目搭建

在这里插入图片描述

默认的信号

信号的发出和接收是需要配合的,有点像【发布订阅】模式。信号的发布是带有参数的。这里Button是发布者,Lable是订阅者。

在这里插入图片描述

我这里建议先在订阅者一方先新建函数,再链接信号。因为Godot在gdscript中是可以自动新建代码的,但是在.net 中需要我们手动新建代码。

先在label里面预制接收函数

using Godot;
using System;public partial class Label : Godot.Label
{private int num = 0;// Called when the node enters the scene tree for the first time.public override void _Ready(){this.Text = "修改";}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}/// <summary>/// 接受按钮点击/// </summary>public void RecevieButtonDown(){this.Text = $"{num}";num++;}}

添加信号

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义无参数信号

我们在Button的代码里面添加信号

using Godot;
using System;public partial class Button : Godot.Button
{// Called when the node enters the scene tree for the first time./// <summary>/// 添加自定义信号/// </summary>[Signal]public delegate void MyButtonClickEventHandler();public override void _Ready(){//在按钮按下时添加信号发送this.ButtonDown += () => EmitSignal(nameof(MyButtonClick));}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}}

在这里插入图片描述

为了做区分,我们在label新增一个函数

	/// <summary>/// 为了做区分,我们新增一个函数/// </summary>public void RecevieButtonDown2(){GD.Print("我是自定义无参信号");this.Text = $"{num}";num++;}

在这里插入图片描述
在这里插入图片描述

自定义带参数信号

这边比较复杂,需要了解C# 的delegate。

C#中委托(delegate)与事件(event)的快速理解

不理解的话那就先凑合着用好了。

Button代码

using Godot;
using System;public partial class Button : Godot.Button
{// Called when the node enters the scene tree for the first time./// <summary>/// 添加自定义信号/// </summary>[Signal]public delegate void MyButtonClickEventHandler();private int num = 0;/// <summary>/// 添加带参数型号/// </summary>[Signal]public delegate void AddNumberEventHandler(int number);public override void _Ready(){//我们给AddNumber添加功能,delegate只能添加或者删除函数,有点类似于触发器。//每次调用的时候,num自动++AddNumber += (item) => num++;//在按钮按下时添加信号发送this.ButtonDown += () =>{EmitSignal(nameof(MyButtonClick));//触发按钮信号EmitSignal(nameof(AddNumber),num);};}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}}

label代码

using Godot;
using System;public partial class Label : Godot.Label
{private int num = 0;// Called when the node enters the scene tree for the first time.public override void _Ready(){this.Text = "修改";}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}/// <summary>/// 接受按钮点击/// </summary>public void RecevieButtonDown(){this.Text = $"{num}";num++;}/// <summary>/// 为了做区分,我们新增一个函数/// </summary>public void RecevieButtonDown2(){GD.Print("我是自定义无参信号");this.Text = $"{num}";num++;}public void AddNumber(int number){this.Text = $"{number}";GD.Print($"我是代参数信号,num:[{number}]");}}

连接信号

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义复杂参数信号

在这里插入图片描述

GD0202: The parameter of the delegate signature of the signal is not supported¶

在这里插入图片描述

想要了解更多差异,需要看这个文章。

Godot Engine 4.2 简体中文文档 编写脚本 C#/.NET

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义GodotObject类

using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace CSharpSimpleTest.models
{public partial class Student:GodotObject{public string Name = "小王";public int Age = 5;public Student() { }}
}

Button

using CSharpSimpleTest.models;
using Godot;
using System;public partial class Button : Godot.Button
{// Called when the node enters the scene tree for the first time./// <summary>/// 添加自定义信号/// </summary>[Signal]public delegate void MyButtonClickEventHandler();private int num = 0;/// <summary>/// 添加带参数型号/// </summary>[Signal]public delegate void AddNumberEventHandler(int number);private Student student = new Student() { Name = "小王",Age = 24};[Signal]public delegate void StudentEventHandler(Student student);  public override void _Ready(){//我们给AddNumber添加功能,delegate只能添加或者删除函数,有点类似于触发器。//每次调用的时候,num自动++AddNumber += (item) => num++;//在按钮按下时添加信号发送this.ButtonDown += () =>{EmitSignal(nameof(MyButtonClick));//触发按钮信号EmitSignal(nameof(AddNumber),num);//触发Student信号EmitSignal(nameof(Student),student);};}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}}

Label

在这里插入图片描述

using CSharpSimpleTest.models;
using Godot;
using System;public partial class Label : Godot.Label
{private int num = 0;// Called when the node enters the scene tree for the first time.public override void _Ready(){this.Text = "修改";}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}/// <summary>/// 接受按钮点击/// </summary>public void RecevieButtonDown(){this.Text = $"{num}";num++;}/// <summary>/// 为了做区分,我们新增一个函数/// </summary>public void RecevieButtonDown2(){GD.Print("我是自定义无参信号");this.Text = $"{num}";num++;}public void AddNumber(int number){this.Text = $"{number}";GD.Print($"我是代参数信号,num:[{number}]");}/// <summary>/// 自定义复杂参数/// </summary>/// <param name="student"></param>public void ReviceStudent(Student student){this.Text = $"student:Name[{student.Name}],Age[{student.Age}]";}}

连接信号

在这里插入图片描述

至于对于的显示逻辑,是基于C# Variant这个类

C# Variant

在这里插入图片描述

在这里插入图片描述

父传子

Callable,信号回调

[教程]Godot4 GDscript Callable类型和匿名函数(lambda)的使用

在这里插入图片描述

在这里插入图片描述

Button
using Godot;
using System;
using System.Diagnostics;public partial class test_node : Node2D
{// Called when the node enters the scene tree for the first time.private Label _lable;private Button _button;private int num = 0;[Signal]public delegate int NumAddEventHandler();public override void _Ready(){_lable = this.GetNode<Label>("Label");_button = this.GetNode<Button>("Button");_lable.Text = "修改";_button.ButtonDown += _button_ButtonDown;NumAdd += () => num;}public void _button_ButtonDown(){_lable.Text = $"按下修改{num}";GD.Print($"按下修改{num}");num++;}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}}
Lable
using CSharpSimpleTest.models;
using Godot;
using System;public partial class Label : Godot.Label
{private int num = 0;// Called when the node enters the scene tree for the first time.public override void _Ready(){this.Text = "修改";}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}/// <summary>/// 接受按钮点击/// </summary>public void RecevieButtonDown(){this.Text = $"{num}";num++;}/// <summary>/// 为了做区分,我们新增一个函数/// </summary>public void RecevieButtonDown2(){GD.Print("我是自定义无参信号");this.Text = $"{num}";num++;}public void AddNumber(int number){this.Text = $"{number}";GD.Print($"我是代参数信号,num:[{number}]");}/// <summary>/// 自定义复杂参数/// </summary>/// <param name="student"></param>public void ReviceStudent(Student student){this.Text = $"student:Name[{student.Name}],Age[{student.Age}]";}public void CallBackTest(Callable callable, Callable callable2){callable.Call();callable2.Call(23);}}
连接信号

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

参数个数不对的异常问题
public void CallBackTest(Callable callable, Callable callable2)
{try{callable.Call();//callable2.Call(23);//如果我们参数个数不对,也不会在C#中抛出异常,会在Godot中抛出异常callable2.Call();}catch (Exception e){GD.Print("发送异常");GD.Print(e.ToString());}}

在这里插入图片描述
在这里插入图片描述
这是个十分危险的使用,因为我们无法溯源对应的代码,也无法try catch找到异常的代码,因为这个代码是在C++中间运行的。

解决异常方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

手动连接信号

由于Godot 对C# 的支持不是很够,所以我们点击Go to Method的时候,是不能直接跳转到对应的代码的。
在这里插入图片描述

    private Timer timer;private Godot.Button btn;public override void _Ready(){//先获取信号btn = GetNode<Button>("../Button");//再手动接受信号btn.Connect("Student",new Callable(this,nameof(ReviceStudent)));}

详细可以看官方文档的最佳实践
在这里插入图片描述

信号等待

在这里插入图片描述

在这里插入图片描述

using CSharpSimpleTest.models;
using Godot;
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;public partial class Label : Godot.Label
{private int num = 0;// Called when the node enters the scene tree for the first time.private Timer timer;public override void _Ready(){//获取Timertimer = GetNode<Timer>("Timer");//启动Timertimer.Start();this.Text = "修改";WaitTimeout();}// Called every frame. 'delta' is the elapsed time since the previous frame.public override void _Process(double delta){}/// <summary>/// 接受按钮点击/// </summary>public void RecevieButtonDown(){this.Text = $"{num}";num++;}/// <summary>/// 为了做区分,我们新增一个函数/// </summary>public void RecevieButtonDown2(){GD.Print("我是自定义无参信号");this.Text = $"{num}";num++;}public void AddNumber(int number){this.Text = $"{number}";GD.Print($"我是代参数信号,num:[{number}]");}/// <summary>/// 自定义复杂参数/// </summary>/// <param name="student"></param>public void ReviceStudent(Student student){this.Text = $"student:Name[{student.Name}],Age[{student.Age}]";}public void CallBackTest(Callable callable, Callable callable2){callable.Call();//throw new Exception("error");//callable2.Call(23);//如果我们参数个数不对,也不会在C#中抛出异常,会在Godot中抛出异常callable2.Call();}public async Task WaitTimeout(){while (true){await ToSignal(timer, Timer.SignalName.Timeout);GD.Print($"收到Timer信号,num[{num}]");this.Text = $"{num}";num++;}}}

在这里插入图片描述

Node注入,取代信号

信号最大的问题就是:

  • 入参不固定
  • godot.net 对C# 支持力度不够
  • 编译报错在外部C++代码,Debug难度大
  • 不符合OOP的编程逻辑

比如我们在Button.cs中添加如下属性

    /// <summary>/// 新增的姓名/// </summary>public string MyName = "我是Button";

在这里插入图片描述
我们就可以在Lable中拿到这个属性

在这里插入图片描述
在这里插入图片描述

基于Action的信号模拟

Button

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
但是这样有个问题,Action需要初始化,不然会报空异常

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
当然,也可以使用event Action,因为event Action是不允许在外部重写的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以event Action 是最优的写法,是最不会出现问题的。

在这里插入图片描述

总结

信号就是Godot中数据沟通方式。信号的出现就是为了将复杂的数据处理简单化为接口的形式。再加上Godot中的Sence,这个就有利于我们面向对象的编程习惯。

但是信号是没有参数的声明的,而且参数出现问题会外部抛出异常,所以我们最好就使用event Action 回调来代替信号。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/279848.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是神经网络?

一、什么是神经网络&#xff1f; 神经网络又称人工神经网络&#xff0c;是一种基于人脑功能模型的计算架构&#xff0c;因此称之为“神经”。神经网络由一组称为“节点”的处理单元组成。这些节点相互传递数据&#xff0c;就像大脑中的神经元相互传递电脉冲一样。 神经网络在…

深度学习pytorch——高阶OP(where gather)(持续更新)

where 1、我们为什么需要where&#xff1f; 我们经常需要一个数据来自好几个的取值&#xff0c;而这些取值通常是不规律的&#xff0c;这就会导致使用传统的拆分和合并会非常的麻烦。我们也可以使用for循环嵌套来取值&#xff0c;也是可以的&#xff0c;但是使用for循环就意味…

【数据可视化】使用Python + Gephi,构建中医方剂关系网络图!

代码和示例数据下载 前言 在这篇文章中&#xff0c;我们将会可视化 《七版方剂学》 的药材的关系&#xff0c;我们将使用Python制作节点和边的数据&#xff0c;然后在Gephi中绘制出方剂的网络图。 Gephi是一个专门用于构建网络图的工具&#xff0c;只要你能提供节点和边的数…

攻防实战 | 记一次nacos到接管阿里云百万数据泄露

在某次攻防当中&#xff0c;通过打点发现了一台nacos&#xff0c;经过测试之后发现可以通过弱口令进入到后台&#xff0c;可以查看其中的配置信息 通过翻看配置文件&#xff0c;发现腾讯云的AK,SK泄露&#xff0c;以及数据库的账号密码。操作不就来了么&#xff0c;直接上云&am…

jmeter打开文件报异常无法打开

1、问题现象&#xff1a; 报错部分内容&#xff1a; java.desktop does not export sun.awt.shell to unnamed module 0x78047b92 [in thread "AWT-EventQueue-0"] 报错部分内容&#xff1a; kg.apc.jmeter.reporters.LoadosophiaUploaderGui java.lang.reflect.Invo…

多种智能搜索算法可视化还原 3D 魔方

2024/03/19&#xff1a;程序更新说明&#xff08;文末程序下载链接已更新&#xff09; 版本&#xff1a;v1.0 → v1.2 ① 修复&#xff1a;将 CLOSED 表内容从优先级队列中分离开来&#xff0c;原优先级队列作 OPEN 表&#xff0c;并用链表树隐式地代替 CLOSED 表&#xff0c;以…

macOS系统中通过brew安装MongoDB

Macos 修改目录权限&#xff1a; sudo chmod -R 777 你的文件夹 本文使用homebrew进行安装简单&#xff0c;因为从官网下载安装包并手动安装需要移动安装包到合适的目录下并配置环境变量等一大堆操作后才能使用数据库&#xff08;若没有安装过brew请自行百度进行安装brew&am…

改进YOLOv8注意力系列六:结合SEAttention轻量通道注意力、ShuffleAttention重排特征注意力模块、SimAM无参数化注意力

改进YOLOv8注意力系列五:结合ParNetAttention注意力、高效的金字塔切分注意力模块PSA、跨领域基于多层感知器(MLP)S2Attention注意力 代码SEAttention轻量通道注意力ShuffleAttention重排特征注意力模块SimAM无参数化注意力加入方法各种yaml加入结构本文提供了改进 YOLOv8注…

SQL数据库和事务管理器在工业生产中的应用

本文介绍了关系数据库在工业生产中的应用以及如何使用事务管理器将生产参数下载到PLC&#xff0c;以简化OT/IT融合过程。 一 什么是配方&#xff08;Recipe&#xff09; 我们以一家汽车零件制造商的应用举例&#xff0c;该企业专业从事汽车轮毂生产制造。假设该轮毂的型号是“…

短视频矩阵系统技术交付

短视频矩阵系统技术交付&#xff0c;短视频矩阵剪辑矩阵分发系统现在在来开发这个市场单个项目来说&#xff0c;目前基本上已经沉淀3年了&#xff0c;那么我们来就技术短视频矩阵剪辑系统开发来聊聊 短视频矩阵系统经过315大会以后&#xff0c;很多违规的技术开发肯定有筛选到了…

Java开发从入门到精通(九):Java的面向对象OOP:成员变量、成员方法、类变量、类方法、代码块、单例设计模式

Java大数据开发和安全开发 &#xff08;一)Java的变量和方法1.1 成员变量1.2 成员方法1.3 static关键字1.3.1 static修饰成员变量1.3.1 static修饰成员变量的应用场景1.3.1 static修饰成员方法1.3.1 static修饰成员方法的应用场景1.3.1 static的注意事项1.3.1 static的应用知识…

用Stable Diffusion生成同角色不同pose的人脸

随着技术的不断发展&#xff0c;我们现在可以使用稳定扩散技术&#xff08;Stable Diffusion&#xff09;来生成同一角色但不同姿势的人脸图片。本文将介绍这一方法的具体步骤&#xff0c;以及如何通过合理的提示语和模型选择来生成出更加真实和多样化的人脸图像。 博客首发地…

[C语言]一维数组二维数组的大小

对于一维数组我们知道取地址是取首元素的地址&#xff0c;二维数组呢&#xff0c;地址是取第一行的地址&#xff0c;sizeof(数组名)这里计算的就是整个数组的大小&#xff0c;&数组名 表示整个数组&#xff0c;取出的是整个数组的地址&#xff0c;显示的是数组的首元素 记…

javascript:void(0);用法及常见问题解析

文章目录 用法&#xff1a;常见问题解析&#xff1a;示例&#xff1a;用法补充&#xff1a;注意事项&#xff1a;替代方案示例&#xff1a;安全性考虑&#xff1a;替代方案建议&#xff1a;ES6语法替代&#xff1a;性能优化&#xff1a;最佳实践&#xff1a; 在 JavaScript 中&…

【双指针】算法例题

目录 二、双指针 25. 验证回文数 ① 26. 判断子序列 ① 27. 两数之和II - 输入有序数组 ② 28. 盛最多水的容器 ② 29. 三数之和 ② 二、双指针 25. 验证回文数 ① 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一…

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——差分进化算法(DE)

基于python语言&#xff0c;采用经典差分进化算法&#xff08;DE&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果4. 代码片段参考 往期优质资源 经过一年多的创作&#xff0c;目前已经成…

Docker简介与安装

简介 用来快速构建、运行、管理应用的工具简单说&#xff0c;帮助我们部署项目以及项目所依赖的各种组件典型的运维工具 安装 1.卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \dock…

解决虚拟机Linux ens33 没有 IP 地址

解决方法&#xff1a; 先进入 root 模式 sudo su 查看目录 ls /etc/sysconfig 找到上述文件夹 ls /etc/sysconfig/network-scripts/ 用 vim 打开 ifcfg-ens33 这个文件&#xff08;不都是这个名字&#xff0c;按这个方法找到这个文件就行&#xff09; vim /etc/sysconfig/netw…

农业四情监测设备—全面、准确地收集农田环境数据

型号推荐&#xff1a;云境天合TH-Q3】农业四情监测设备是一种高科技的农田监测工具&#xff0c;旨在实时监测和管理农田中的土壤墒情、作物生长、病虫害以及气象条件。这些设备综合运用了传感器、摄像头、气象站等技术手段&#xff0c;能够全面、准确地收集农田环境数据&#x…

H264字节流编码格式

1.H264码流格式——字节流格式 字节流格式是大多数编码器&#xff0c;默认的输出格式。它的基本数据单位为NAL单元&#xff0c;也即NALU。为了从字节流中提取出NALU&#xff0c;协议规定&#xff0c;在每个NALU的前面加上起始码&#xff1a;0x000001或0x00000001&#xff08;0…