Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#博弈中NPC的异步行为_C#_.net_Asynchronous_Mono_C# 5.0 - Fatal编程技术网

C#博弈中NPC的异步行为

C#博弈中NPC的异步行为,c#,.net,asynchronous,mono,c#-5.0,C#,.net,Asynchronous,Mono,C# 5.0,这个问题与……有关。 上下文 当Miguel de Icaza在上首次为游戏介绍C#5异步框架时,我非常喜欢在游戏中使用async和wait来处理“脚本”(可以说,因为它们是C#,在我的例子中,是编译的——及时但无论如何都要编译) 即将推出的游戏引擎似乎也能处理脚本,但从我的角度来看,在想法和实现之间确实存在差距 在中,有人使用wait让NPC在游戏其余部分仍在运行时执行一系列指令 主意 我想更进一步,允许NPC同时执行多个动作,同时以顺序方式表达这些动作。 大致如下: class NonPla

这个问题与……有关。

上下文 当Miguel de Icaza在上首次为游戏介绍C#5异步框架时,我非常喜欢在游戏中使用
async
wait
来处理“脚本”(可以说,因为它们是C#,在我的例子中,是编译的——及时但无论如何都要编译)

即将推出的游戏引擎似乎也能处理脚本,但从我的角度来看,在想法和实现之间确实存在差距

在中,有人使用
wait
让NPC在游戏其余部分仍在运行时执行一系列指令

主意 我想更进一步,允许NPC同时执行多个动作,同时以顺序方式表达这些动作。 大致如下:

class NonPlayableCharacter 
{
    void Perform()
    {
        Task walking = Walk(destination); // Start walking
        Task sleeping = FallAsleep(1000); // Start sleeping but still walks
        Task speaking = Speak("I'm a sleepwalker"); // Start speaking
        await walking; // Wait till we stop moving.
        await sleeping; // Wait till we wake up.
        await speaking; // Wait till silence falls
    }
}
为了做到这一点,我使用了乔恩·斯基特的《世界杯》和以往一样精彩

实施 我的玩具实现由两个文件组成,NPC.cs和Game.cs 全国人大常委会:

使用系统;
使用System.Threading.Tasks;
命名空间异步框架
{
公营人大
{
公共NPC(国际id)
{
this.id=id;
}
公共异步void执行()
{
任务喋喋不休=说话(“我有超能力…”);
等待发言(“\t\t\t…我可以边说话边说话!”);
等待唠叨;
完成=正确;
}
公共bool Done{get{return Done;}}
受保护的异步任务(字符串消息)
{
int-previousLetters=0;
双字母=0.0;
while(字母1.0){
System.Console.Out.WriteLine(“[”+this.id.ToString()+“]”+message.Substring(0,(int)Math.Floor(Math.Min(字母,message.Length)));
previousLetters=(int)Math.Floor(字母);
}
}
}
私有int-id;
私有布尔完成=假;
私有只读双字母每毫秒=0.002*Game.Rand.Next(1,10);
}
}
Game.cs:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace asyncFramework
{
    class Game
    {
        static public Random Rand { 
            get { return rand; }
        }

        static public Task<double> Frame {
            get { return frame.Task; }
        }

        public static void Update (double ellapsedTime)
        {
            TaskCompletionSource<double> previousFrame = frame; // save the previous "frame"
            frame = new TaskCompletionSource<double> (); // create the new one
            previousFrame.SetResult (ellapsedTime); // consume the old one
        }

        public static void Main (string[] args)
        {
            int NPC_NUMBER = 10; // number of NPCs 10 is ok, 10000 is ko
            DateTime currentTime = DateTime.Now; // Measure current time
            List<NPC> npcs = new List<NPC> (); // our list of npcs
            for (int i = 0; i < NPC_NUMBER; ++i) { 
                NPC npc = new NPC (i); // a new npc
                npcs.Add (npc); 
                npc.Perform (); // trigger the npc actions
            }
            while (true) { // main loop
                DateTime oldTime = currentTime;
                currentTime = DateTime.Now;
                double ellapsedMilliseconds = currentTime.Subtract(oldTime).TotalMilliseconds; // compute ellapsedmilliseconds
                bool allDone = true;
                Game.Update (ellapsedMilliseconds); // generate a new frame
                for (int i = 0; i < NPC_NUMBER; ++i) {
                    allDone &= npcs [i].Done; // if one NPC is not done, allDone is false
                }
                if (allDone) // leave the main loop when all are done.
                    break;
            }
            System.Console.Out.WriteLine ("That's all folks!"); // show after main loop
        }

        private static TaskCompletionSource<double> frame = new TaskCompletionSource<double> ();
        private static Random rand = new Random ();
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Threading.Tasks;
命名空间异步框架
{
班级游戏
{
静态公共随机Rand{
获取{return rand;}
}
静态公共任务框架{
获取{return frame.Task;}
}
公共静态无效更新(双ellapsedTime)
{
TaskCompletionSource previousFrame=frame;//保存上一个“frame”
frame=newtaskcompletionsource();//创建一个新的
previousFrame.SetResult(ellapsedTime);//使用旧的
}
公共静态void Main(字符串[]args)
{
int NPC_NUMBER=10;//NPC的数量10可以,10000可以
DateTime currentTime=DateTime.Now;//测量当前时间
列出NPC=新列表();//我们的NPC列表
对于(int i=0;i
这是一个非常简单的实现

问题 然而,它似乎并没有像预期的那样起作用

更准确地说,NPC_的数字是10、100或1000,我没有问题。但在10000或以上时,程序不再完成,它会写一段时间的“讲话”行,然后再也不会在控制台上运行。 虽然我不想在我的游戏中同时拥有10000个NPC,但它们也不会编写无聊的对话框,还会移动、设置动画、加载纹理等等。所以我想知道我的实现出了什么问题,以及我是否有机会修复它

我必须确定代码是在Mono下运行的。此外,“有问题”的值在您的位置可能不同,它可能是计算机特定的东西。如果这个问题在.Net下无法重现,我将在Windows下尝试

编辑 在.Net中,它最多运行1000000次,尽管初始化需要时间,但这可能是一个特定于Mono的问题。 调试人员的数据告诉我,确实有NPC没有完成。遗憾的是,目前还没有关于原因的信息

编辑2 在Monodevelop下,在不使用调试器的情况下启动应用程序似乎可以解决问题。不知道为什么

结束语 我意识到这是一个非常非常冗长的问题,我希望你能花点时间阅读,我真的很想理解我做错了什么


事先非常感谢。

我不确定这是否相关,但这句话让我印象深刻:

allDone &= npcs [i].Done; // if one NPC is not done, allDone is false
我建议等待您的
Perform
方法。由于您希望所有NPC异步运行,请将它们的
Perform
Task
添加到列表中,并使用
Task.WaitAll(…)
完成

反过来,你也可以这样做
allDone &= npcs [i].Done; // if one NPC is not done, allDone is false
var scriptList = new List<Task>(npcs.Count);

for (int i = 0; i < NPC_NUMBER; ++i) 
{
  var scriptTask = npcs[i].Perform();
  scriptList.Add(scriptTask);

  scriptTask.Start();
}

Task.WaitAll(scriptList.ToArray());
Game.Update(ellapsedMilliseconds); // generate a new frame
GC.Collect(0, GCCollectionMode.Optimized, true);
protected async Task Speak(string message)
{
    int previousLetters = 0;
    double letters = 0.0;
    while (letters < message.Length)
    {
        double ellapsedTime = await Game.Frame;

        await Task.Yield();
        Console.WriteLine("Speak on thread:  " + System.Threading.Thread.CurrentThread.ManagedThreadId);

        letters += ellapsedTime * LETTERS_PER_MILLISECOND;
        if (letters - previousLetters > 1.0)
        {
            System.Console.Out.WriteLine("[" + this.id.ToString() + "]" + message.Substring(0, (int)Math.Floor(Math.Min(letters, message.Length))));
            previousLetters = (int)Math.Floor(letters);
        }
    }
}