我正在编写代码来加载和解析游戏中数据的文本。有很多分支阅读器调用 - 例如,地图将包含道具和敌人等数据,并且这些对象有自己的文件被调用和读入。这通常都会快速加载,大约1.5秒< / strong>,但在较慢的机器上,它可能需要 5+秒并导致游戏窗口无响应,直到完成为止。
现在我正在寻找保持窗口活动同时保持加载时间短的方法。我已经将一些加载分离到在主线程后台运行的任务中,然后在加载完成时它告诉主线程切换状态并继续游戏。然而,这有效,我已经从 1.5 秒加载时间变为 53 秒加载时间。切换到这样的后台任务时,这是正常的性能吗?我发布了一些通用代码作为当前处理方式的示例。
Map map = null;
//Main Update Loop
public void Update()
{
if(GameState == Active)
map.Update();
else
ShowLoadingScreen();
}
//LoadWorld gets called from elsewhere, like a UI
public async void LoadWorld()
{
GameState = State.Loading;
await Task.Run(() => { LoadFile("mapdata", out map); });
GameState = State.Active;
map.Start();
}
//This loads the file and reads the first line
//which tells the reader what sort of object it is
public void LoadFile(String file, out Map m)
{
m = new Map(); //create new map
StreamReader sr = new StreamReader(file);
String line;
Object obj = null;
while ((line = sr.ReadLine()) != null)
{
switch(line)
{
case "A":
obj = parseObjectA(line, sr); //continues with its own loop
break;
case "B":
obj = parseObjectB(line, sr); //continues with its own loop
break;
}
map.addObject(obj);
}
}
//This loops through the reader and fills an object with data, then returns it
public Object parseObjectA(String line, StreamReader sr)
{
Object obj = new Object();
while ((line = sr.ReadLine()) != null)
{
String element;
String value;
//parseLine is a function that breaks apart the line into an element and value
parseLine(line, out element, out value);
switch(element)
{
case "name":
obj.Name = value;
break;
case "position":
{
int pos = 0;
Int32.TryParse(value, out pos);
obj.position = pos;
break;
}
}
}
return obj;
}
答案 0 :(得分:0)
我会将此作为评论发布,但我尚未被允许,因此将其扩展为更全面的解释。
从游戏开发的角度来看,我会将加载器创建为后台工作线程。这将使窗口的主线程/形式响应用户输入。
在backgroundWorker中,您可以根据需要启动单个任务来执行单个工作负载,但UI始终是响应式的。
要记住的重要一点是在类的根中创建所需的变量,然后在后台线程中填充它们。这样做意味着您可以在主线程中完成所有内容后轻松读取结果。
举个例子:
class MainThread
{
BackgroundLoader bgLoader;
public MainThread()
{
bgLoader = new BackgroundLoader();
}
public void LoadItems()
{
bgLoader.Load();
}
}
class BackgroundLoader
{
BackgroundWorker backgroundWorker = new BackgroundWorker();
// create the variables to hold the results.
Map map;
public void Load()
{
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerAsync();
while (!backgroundWorker.IsBusy) { }
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// This is where you do the work and load your variables, which you then access once the thread is complete.
map = LoadMap();
}
}