我正在try 用C#在Godot4中创建一个交互和对话系统.使用互动系统,我想与一个NPC互动,这将触发任务对话.对话系统似乎工作得很好,但我遇到了关于使用Async/AWait的交互系统的问题.以下是代码:

public async override void _Input(InputEvent @event)
{
    if (@event.IsActionReleased("Interact") && canIneract && activeAreas.Count > 0)
    {
        canIneract = false;
        interactDisplay.Hide();
        var result = activeAreas[0].Interact.Call(otherBody);
        await ToSignal((GodotObject)result, "DialogueComplete");

        canIneract = true;
    }
}

我正在翻译我正在观看的tutorial 个GDSript代码,他们的代码看起来像这样:

func _input(event):
    if event.is_action_pressed("interact") && can_interact:
        if active_areas.size() > 0:
            can_interact = false
            label.hide()

            await active_areas[0].ineract.call()
            can_interact = true

我的代码与他的代码略有不同,但await行才是最重要的.我正在try 在我的交互系统上使用await,直到我的对话系统结束.然而,在C#中,我必须使用toSignal方法来等待,就像您在第一个示例中看到的那样.我有点困惑,因为在GDScript中实现相同操作的方式可能与C#版本非常不同.我try 在线查找解决方案并阅读文档,得到的唯一提示是使用toSignal方法,并传入我想要的信号名称.但我一直收到这个错误.

E 0:00:05:0142   Godot.NativeInterop.NativeFuncs.generated.cs:108 @ Godot.Error Godot.NativeInterop.NativeFuncs.godotsharp_internal_signal_awaiter_connect(IntPtr , Godot.NativeInterop.godot_string_name& , IntPtr , IntPtr ): Parameter "p_source" is null.
  <C++ Source>   modules/mono/signal_awaiter_utils.cpp:37 @ gd_mono_connect_signal_awaiter()
  <Stack Trace>  Godot.NativeInterop.NativeFuncs.generated.cs:108 @ Godot.Error Godot.NativeInterop.NativeFuncs.godotsharp_internal_signal_awaiter_connect(IntPtr , Godot.NativeInterop.godot_string_name& , IntPtr , IntPtr )
                 SignalAwaiter.cs:18 @ Godot.SignalAwaiter..ctor(Godot.GodotObject , Godot.StringName , Godot.GodotObject )
                 GodotObject.base.cs:174 @ Godot.SignalAwaiter Godot.GodotObject.ToSignal(Godot.GodotObject , Godot.StringName )
                 InteractionManager.cs:88 @ void InteractionManager+<_Input>d__15.MoveNext()
                 :0 @ void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine >(TStateMachine& )
                 :0 @ void InteractionManager._Input(Godot.InputEvent )
                 Node.cs:2075 @ Boolean Godot.Node.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
                 CanvasItem.cs:1374 @ Boolean Godot.CanvasItem.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
                 Node2D.cs:516 @ Boolean Godot.Node2D.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
                 InteractionManager_ScriptMethods.generated.cs:66 @ Boolean InteractionManager.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
                 CSharpInstanceBridge.cs:24 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Call(IntPtr , Godot.NativeInterop.godot_string_name* , Godot.NativeInterop.godot_variant** , Int32 , Godot.NativeInterop.godot_variant_call_error* , Godot.NativeInterop.godot_variant* )

我不知道我的信号名称是否正确,我已经try 了所有方法,但似乎都不起作用.我引用的信号来自名为DialogueManager EventHandler的对话管理器,但显然DialogueManager不是信号名称.

在这一点上,我不知道我是否在朝着正确的方向前进,是否只是简单地没有在C#API中实现我正在寻找的东西,或者可能我犯了一个简单的拼写错误.有什么 idea 吗?

推荐答案

他们似乎使用await作为协程,而不是信号(请注意,他们传递给await的不是信号).

它在幕后的工作方式是,当GD脚本达到await时,它返回GDScriptFunctionState,它编码脚本上要继续的位置,并计划继续.在呼叫方,await将在GDScriptFunctionStatecompleted信号上恢复.

因此,假设这在C#中起作用,请try completed信号.Apparently it does not work.


无论如何,如果你是完全用C#实现这一点,我会建议你使用Func<T, Task>或类似的语言,而不是Callable.

事实上,C#tasks的工作原理与此类似.如果你用C#写一个async方法,编译器会把它重写成一系列的延续.当执行代码时,第一个块返回Task,并调度下一个延续,当最后一个延续完成时,它设置Task完成.

※:Who did async/await first?


Addendum based on comments

我正在寻找正在等待触发的特定信号,以便代码可以继续

你已经知道如何等待信号:你用ToSignal.

然而,这并不是在等待一个信号:

await active_areas[0].ineract.call()

在GDScriptawait中有两个用例:它可以等待信号或协程.而这似乎是后者.请参见Awaiting for signals or coroutines.

另一方面,C#中的代码正在等待调用Interact返回的对象的信号:

var result = activeAreas[0].Interact.Call(otherBody);
await ToSignal((GodotObject)result, "DialogueComplete");

所以... Interact指向的代码需要返回一个发出该特定信号的对象.

请注意,如果您在从Interact调用返回之前发出信号,则调用它的代码(如上图所示)将不会等待信号(因为代码尚未返回).

因此,需要明确的是:信号必须由返回Interact AFTER Interact返回它的对象发出.

One work around would be use to a deferred call inside the code pointed by 100 to emit the signal.


我还应该提到,我不仅try 等待某个特定任务完成,而且该任务还调用其他方法,其中一些方法必须通过输入激活.

您可以拥有一个处理输入并发出信号的对象,然后等待该信号.

Csharp相关问答推荐

C#中的包版本控制

Blazor:用参数创建根路径

如何使用Automapper映射两个嵌套列表

实体核心框架--HasColumnType和HasPrecision有什么不同?

(乌龙)1&#比c#中的UL&#慢吗?

限制特定REST API不被访问,但部署代码

自动映射程序在GroupBy之后使用项目

如何在实体框架中添加包含列表?

异步实体框架核心查询引发InvalidOperation异常

依赖项注入、工厂方法和处置困境

HttpClient SendAsync与多线程环境中的ArchiveZip

使用CollectionView时在.NET Maui中显示数据时出现问题

为什么C#/MSBuild会自发地为不同的项目使用不同的输出路径?

如何使用实体框架核心对字符串_agg使用强制转换为varchar(Max)

C#如何获取字符串中引号之间的文本?

从HTML元素获取 colored颜色

如何使用LINQ在C#中填充列表列表?

使用postman 测试配置了身份的.NET 6应用程序

除非首先访问使用的终结点,否则本地API上的终结点不起作用

将文本从剪贴板粘贴到RichTextBox时,新文本不会在RichTextBox ForeColor中着色