我正在开发一个游戏,用PHP编写,在控制台中运行。回想一下旧的MUD和其他基于文本的游戏,甚至是一些ASCII艺术!
无论如何,我试图做的是让事情发生,同时也接受用户输入。
例如,假设这是一个双人游戏,玩家 1 正在等待玩家 2 采取行动。只需侦听消息即可轻松完成此操作。
但是,如果玩家 1 想要更改某些选项怎么办?如果他们想要查看有关游戏状态方面的详细信息,该怎么办?丢掉比赛呢?玩家在等待对手采取行动时可能想做很多事情。
不幸的是,我现在拥有的最好的是Ctrl + C完全杀死了该程序。然后,另一个玩家保持挂起状态,直到连接断开。哦,游戏完全输了。
我通过fgets(STDIN)
获得用户输入.但是这会阻止执行,直到收到输入(这通常是一件好事)。
像这样的控制台程序是否有可能同时处理输入和输出?还是我应该只看其他界面?
简而言之,PHP 不是为此而构建的,但您可能会从这些扩展之一中获得一些帮助。我不确定它们有多彻底,但您真的可能想使用文本 UI 库。(实际上你可能不想为此使用 PHP。
综上所述,您需要逐个字符从STDIN
获取非阻塞输入。不幸的是,从 PHP 的角度来看,大多数终端都是缓冲的,所以在按下 Enter 之前你不会得到任何东西。
如果您在终端上运行stty -icanon
(或操作系统的等效程序)以禁用缓冲,那么以下短程序基本上可以工作:
<?php
stream_set_blocking(STDIN, false);
$line = '';
$time = microtime(true);
$prompt = '> ';
echo $prompt;
while (true)
{
if (microtime(true) - $time > 5)
{
echo "'nTick...'n$prompt$line";
$time = microtime(true);
}
$c = fgetc(STDIN);
if ($c !== false)
{
if ($c != "'n")
$line .= $c;
else
{
if ($line == 'exit' || $line == 'quit')
break;
else if ($line == 'help')
echo "Type exit'n";
else
echo "Unrecognized command.'n";
echo $prompt;
$line = '';
}
}
}
(它依赖于启用本地回显来打印键入字符。
如您所见,我们只是永远循环往复。如果存在某个字符,请将其添加到$line
中。如果按回车键,则进程$line
。同时,我们每五秒滴答一次,只是为了表明我们在等待输入时可以做其他事情。(这将消耗最大的CPU;您必须发出sleep()
才能解决此问题。
这本身并不是一个实际的例子,但也许会让你朝着正确的方向思考。
ncurses(非阻塞模式)和libevent来构建您描述的游戏。这样,您几乎不会消耗 CPU。处理单个键有时很尴尬(自己实现退格键,一点也不好玩 - 你知道各种操作系统在退格键上发送不同的键码吗?),如果你想正确支持 UTF-8,就会变得非常棘手。不过,完全可行。
特别是,通过读取网络和键盘(stdin)输入来广泛使用libevent是有益的。此函数使您能够侦听单个键:http://www.php.net/manual/en/function.ncurses-cbreak.php您可以稍后使用 libevent API 读取。要记住的关键是,您有时最终会一次读取多个密钥,并且必须对其进行处理(因此循环访问您已读取的所有内容)。否则,用户会很恼火地看到并非所有按键都"到达"应用程序,有些按键丢失。
对不起,马修,我将不得不不接受你的答案,因为我自己找到了:
使用以下代码接收用户输入,同时仍执行其他操作:
while(/* some condition that the code running is waiting on */) {
// perform one step or iteration of that code
exec("choice /N /C ___ /D _ /T _",$out,$ret);
// /C is a list of letters that do something
// /D is the default action that will be used as a no-op
// /T is the amount of time to wait, probably best set to one second
switch($ret) {
// handle cases - the "default" case should be "continue 2"
}
}
然后,这可以用来中断循环并进入选项菜单,或触发一些其他事件,或者如果使用得当,甚至可以用于键入命令。