背景
我和几个同学当时想要去做一个多人联机的平面小游戏,但需要渲染视野。然而我们不会,只好请教大佬,而大佬不会 Javascript,所以他给我们的是 C++ 编译后的可执行文件,这就产生了延时。
原始方案
我当时写的是每一次游戏循环都运行一次程序,开启进程后向 stdin
加入数据,再从 stdout
获取。
就像这样:
js
const exec=require('child_process').exec;
function runCommand(command,stdin)
{
return new Promise((res,rej)=>{
let child=exec(command,(err,stdout,stderr)=>{
err||stderr? rej([err,stderr]):res(stdout));
});
child.stdin.write(stdin);
child.stdin.end();
});
}
运行起来的时候确实是可以用了,但是一多人就会有卡顿。
测试的时候发现,这种写法每一次都需要开启一个进程,再把这个进程关掉,这样就造成了时间上非常大的浪费,直接占掉至少 20ms
。这对于 30帧 的游戏来说都是不可理喻的。
改进写法
后来,我就想能不能在服务器一开始的时候就开启一个进程,而后就一直开着,服务器关了它才关。于是我先联系大佬把他的程序加上 while(true)
,而后查阅了大量资料。
后来我们通过 ChatGPT 发现,在 C++ 程序输出的时候 手动把缓冲区清空 ,就可以在 stdout
中得到输出。于是我们写出了下面的代码:
js
const spawn=require('child_process').spawn;
const childProcess=spawn('./modules/vision.exe',[],{stdio:['pipe','pipe','inherit']});
childProcess.stdout.setEncoding('utf8');
var nowOutput=``;
childProcess.stdout.on('data',(data)=>{
nowOutput=data.toString();
});
process.stdin.on('end',()=>{
childProcess.kill();
});
function runCommand(stdin)
{
return new Promise((res,rej)=>{
childProcess.stdin.write(stdin);
res(nowOutput);
});
}
最后延时问题得到解决。