使用PHP创建游戏的第1部分:检测按键输入
我最近在YouTube上观看了一部关于旧计算机的纪录片,其中展示了一个使用命令行创建早期计算机游戏的视频。这不是基于文本的冒险游戏,而是一种使用文本为在命令行上作为程序运行的图形创建的游戏。这让我想到使用PHP创建这样的东西应该是可能的。如果可以在使用30年的计算机上使用PHP,那么肯定可以使用PHP进行操作,对吗?我认为创建一系列显示如何将其组合在一起的帖子可能会很有趣。
难题的第一部分是解决如何实时检测命令行上来自键盘的输入。这样做的关键是使用php://stdin流包装器,这是一个方便的包装器,用于包装PHP应用程序的传入数据。如果您感兴趣的话,我已经写过有关php://stdin和其他PHP流包装器的文章。我们需要做的是打开一个与php://stdin输入的只读连接,然后使用类似的内容从中读取信息fgets()。
但是,这还不是全部,我们还需要确保打开的流资源在从中读取时不会阻塞PHP应用程序。这是通过调用stream_set_blocking()函数并传入我们希望不阻塞的流作为参数来完成的。
现在,当我们使用流从流中读取数据时,fgets()不会导致程序被锁定。如果没有此安装,程序将在我们尝试从输入中读取时挂起。
$stdin = fopen('php://stdin', 'r'); //将流设置为非阻塞。 stream_set_blocking($stdin, 0); $keypress = fgets($stdin);
不过,这还不是故事的结局。我们还需要告诉命令行界面将键输入直接传递给脚本,而无需进行修改。这是通过在system()函数中运行'sttycbreak-echo'命令来完成的。该system()函数只是将输入的字符串直接传递给命令行,实际上是在运行程序。
'sttycbreak'命令将终端的模式更改为cbreak,有时也称为罕见模式。在此模式下,每个字符在输入后直接传递到终端应用程序,而不是在按下回车按钮之后传递给终端应用程序。-echo标志意味着这将以静默方式完成,而不是将字符传递到终端输出。如果没有适当的设置,我们将需要在每次按键后都按Enter键以进行注册。
system('sttycbreak-echo');
完成所有这些操作后,我们现在需要将一些按键转换成有用的东西。大多数键将转换为它们通常的对应键(例如,按“a”将打印“a”),但是我们还需要翻译一些可能会被按的系统键。这是像箭头键之类的键,可以输入,转义,诸如此类。以下功能将检测其中的一些通用键,并将其转换为字符串而不是字符代码。
function translateKeypress($string) { switch ($string) { case "\033[A": return "UP"; case "\033[B": return "DOWN"; case "\033[C": return "RIGHT"; case "\033[D": return "LEFT"; case "\n": return "ENTER"; case " ": return "SPACE"; case "\010": case "\177": return "BACKSPACE"; case "\t": return "TAB"; case "\e": return "ESC"; } return $string; }
有了这些,我们可以创建一个小脚本,该脚本将侦听传入的按键并报告已按下的按键。如果该键碰巧是一个特殊键,那么它将被转换为该键的字符串表示形式。
$stdin = fopen('php://stdin', 'r'); stream_set_blocking($stdin, 0); system('stty cbreak -echo'); while (1) { $keypress = fgets($stdin); if ($keypress) { echo 'Key pressed: ' . translateKeypress($keypress) . PHP_EOL; } }
下面显示了此脚本的运行情况以及按了一些键之后的情况。
$ php detectkeys.php Key pressed: p Key pressed: h Key pressed: p Key pressed: SPACE Key pressed: g Key pressed: a Key pressed: m Key pressed: e Key pressed: LEFT Key pressed: UP Key pressed: RIGHT Key pressed: DOWN Key pressed: ENTER Key pressed: BACKSPACE Key pressed: ESC Key pressed: TAB
现在,我们有了一种机制来监听被按下的按键,我们可以使用该机制来处理游戏的控件。在下一篇文章中,我将研究使用此控制方法设置游戏并在命令行上呈现输出。
如果您想完整地查看此代码,那么我已经创建了一个GitHubgist,您可以下载并运行它。