创建自己的模拟游戏/简易地图编辑器
在上一课中,我们取得了实质性的进展。现在,我们不再仅仅是在游戏结束前有一个简单的按钮点击,而是拥有了一个角色,可以在更大的区域内移动,被墙壁阻挡,掉入深渊而死亡,然后找到宝藏后获胜。
这一切都很好,但我们的游戏需要更多内容。是时候添加更多地图、地图等级以及我们自己的简易地图编辑器,这样我们就可以快速创建地图、生成地图文件,并以全新的复杂程度玩我们的游戏了。
编程最棒的事情之一就是能够将更大更复杂的问题分解成更小更易于管理的片段。包含文件就是实现这种功能的一种方式。让我们看看我们在上一课中编写的用来在屏幕上显示地图的自定义函数。您是否注意到我们的 character.php 文件变得有点拥挤,难以阅读?如果我们能够从该页面上的代码中删除 displayMap() 函数,但仍然可以在该页面上使用它,那不是很好吗?
包含文件的作用正是如此。使用包含文件非常简单。首先,您创建一个新文件。我喜欢将包含许多函数的文件命名为一些通用的东西:functions.php。这样,当您以后返回寻找东西时,如果您发现一个不在当前文件中的函数被使用,您就知道在哪里检查才能找到它。
接下来,您在 functions.php 中放置一些代码。在本例中,就是 displayMap 函数。所以我们只需要将该函数从 character.php 文件剪切/粘贴到 functions.php 文件中。
最后但同样重要的是,我们返回 character.php,并在页面顶部写下
<?php session_start(); include('functions.php'); //rest of the code here like normal.... ?>
这做了什么?它实际上将 functions.php 文件的内容转储到 character.php 页面上。这样,您在 functions.php 中包含的任何代码片段现在都可以在该页面上访问,就像我们直接在 character.php 页面中编写 displayMap() 函数一样。多么整洁!
我相信您已经看到了这样做的益处。它使一切都更容易阅读。
问题:何时适合创建函数?
函数是非常棒的东西。我的经验法则就是,如果您有一段代码,甚至是一些您计划反复使用的页面格式,将其变成一个函数。这样,您就不需要一遍又一遍地重复输入相同的代码,只需要调用您的函数并传递唯一的参数。
以我们的角色移动为例。每次有人点击一个按钮时,我们都需要检查他们按下了哪个按钮、他们在移动的哪个方向以及如何对该方向上的内容做出反应。您是否注意到每个方向的代码中都有相似之处?如果您遇到了这样的情况,那么是时候停下来考虑函数了。
试试看!您能将角色移动转换成一个函数吗?以下是一个提示:每次玩家移动时,您真正需要知道的只是移动的方向。然后,根据该方向,您可以检查地图的 x 和 y 值以查看那里有什么。
在本课中,我们将创建一个地图编辑器,我们可以用它来相当快地创建地图文件。在我们的地图编辑器中,我们希望在完成地图编辑后,将创建的地图文件自动下载或导出。要做到这一点,您需要了解一些关于文件和 http 标头的信息。尽管这些东西听起来很难,但实际上只需要几行代码。
让我们谈谈 HTTP 标头。HTTP 代表超文本传输协议,是我们用来在线查看文件的一种方式。您可能熟悉 FTP、文件传输协议或 TCP/IP、传输控制协议/互联网协议等其他协议。但我们只关注其中一种。
每次您从互联网上的某个地方请求一个文件时,都会发生很多事情。如果您想了解所有内容的工作原理,我强烈建议您访问维基百科的网络部分。但是,您需要了解的一件更重要的事情是,对于您在线查看的任何文件,它都以标头信息开头,这些信息描述了文件的类型、文件长度和文件内容。
PHP 作为一种服务器端编程语言,可以用来在其他人在线查看文件之前设置您创建的任何文件的标头。通过这种方式,我们可以使用 PHP 告诉浏览器,我们在 HTML 文件中写入的任何内容都应该像音乐文件、应用程序、PDF 或文本文件一样对待。我们想要什么都可以!
创建一个文件并将其命名为 testdownload.php。现在将以下内容放入其中
<?php //let's create a name for the file you'll download $filename = "My Funky File.txt"; //Tell PHP that we want to change the header information for this .php file and instead it'll become a .txt file header("Content-Type: text"); //Now we add an additional statement that's meant to make your browser automatically download this file's content header('Content-Disposition: attachment; filename="' . $filename .'"'); //now anything we echo on this page will become a part of the file we're downloading! think of all the possibilities! echo "This is my totally awesome, funky cool file that I made download automatically using .php! You can't even tell this was actually inside a .php script because the headers are being set to text :)"; ?>
就是这样!您看,只需几行代码,您就可以创建一个文件,该文件会自动下载您在页面上 echo 的任何内容,并使用您想要的文件名和扩展名。我们可以将此概念与我们的地图编辑器一起使用,在设置标头后将用户选择的所有选项 echo 到页面,并为地图文件创建自动下载。
从文件读取有点复杂。我不会介绍这个概念,而是直接给出我为地图编辑器编写的实际代码,并添加大量注释来解释我做了什么以及原因。请注意,我编写了此文件读取器来处理地图编辑器生成的文件格式。它可能不适用于您自己创建的任何地图文件,因此您需要先使用地图编辑器重新创建它们。
我还想提醒您一件事。我将我的地图文件保存在另一个名为 maps 的目录中。如果您将地图文件保存在其他位置,则需要更改 $directory 变量以反映这一点。如果您将地图文件保存在与游戏和地图编辑器文件相同的位置,则取消注释第一个 $directory 行,并注释掉第二个 $directory 行。
<?php /************** * Load Maze File * NOTE: This was designed specifiically for files made with the map editor * it's not guaranteed to work for a file you made and formatted yourself. * Please use the editor to generate these files for you. **************/ function loadMap($filename, $level) { $map = array(); //if you keep the map files in a particular directory //fill that in below. Otherwise you can leave this blank //$directory = ""; $directory = "maps/"; if (file_exists($directory . $filename . "_" . $level . ".txt")) { //open our file for reading the contents $fileline = file($directory . $filename . "_" . $level . ".txt"); $x = 0; //while there is data in the file //read it one line at a time foreach ($fileline as $line_num => $line) { $i = 1; $y = 0; //we need to reset this each time //so our row always starts at zero //if this data is the start of our map //it should always be a wall if (substr($line, $i, 1) == "W") { //start pulling the info for the first row //keep loading in info until we reach the end of the line //in the row while (substr($line, $i, 1) != "\n") { if ($i % 2 != 0) //we do this so we don't load //in any of the spaces between characters { $map[$x][$y] = substr($line, $i, 1); $y++; } $i++; //take the next character in the row } $x++; //increment to the next row } } return $map; //return the array with all the map data } else return "File not found!"; } ?>
此函数主要做三件事。首先,它检查文件是否存在,如果不存在,则会显示一条错误消息。否则,它将打开文件,并搜索该文件,直到找到地图的第一行。我们知道何时找到地图的第一行,因为它将是一个 W 字符,即围绕地图外侧的所有墙壁。一旦它从地图文件中找到了一行,它就会将其插入数组并按 1 递增数组变量。这样,地图的每一行和每一列都会被读取,直到它不再找到任何内容为止。
我们知道何时到达了一行的末尾(或地图中一行的末尾),因为我们遇到了一个 \n 字符。这与文件中的回车符或换行符相同。这告诉我们这一行没有其他内容需要读取,因此我们递增数组以开始从下一行读取。
如果这看起来有点超出您的理解范围,请不要担心。当您在下一课中学习读取或插入数据库中的值时,这实际上要容易得多。
我知道我说过我不会深入 AJAX 和 Javascript,但是当我创建地图编辑器时,我意识到如果添加一些 Javascript 来进行自动颜色编码,会更容易实现视觉效果。因此,我将介绍我编写的两个函数及其工作原理。
Javascript 使用与 PHP 中不同的标签开头,但它有开始和结束标签。
<script language="javascript"> function setColor(object) { object.style.backgroundColor = object.options[object.selectedIndex].style.backgroundColor; object.style.color = object.options[object.selectedIndex].style.color; } function resetColors(object) { var i; //we need to make sure we skip the buttons at the //bottom of the page, so we have to subtract 2 from //all the items in the form for (i = 0; i < (object.length-2); i++) setColor(object[i]); } </script>
第一个函数很简单。它获取 select 框中选项的颜色,并将 select 框更改为与该颜色匹配。
第二个函数稍微复杂一些。当我们调用它时,我们传递给它一个表单,即地图编辑器文件中的 <form> 和 </form> 标签之间的所有内容。这包括我们用来让您创建地图的所有 select 框。然后,它遍历所有这些 select 框,并调用 setColor 函数。
我们使用第二个函数的原因与第一次加载编辑器有关。第一次加载编辑器时,我们运行一个 PHP 脚本,以便地图的边框自动变成墙壁。当我们这样做时,我们仍然希望更新我们设置的墙壁的颜色。这就是 resetColors 函数的作用,它遍历页面上的每个 select 框,并将它们设置为适当的颜色。您会注意到,当您第一次启动编辑器时,它会显示所有白色的 select 框,几秒钟后,地图的边框会变为灰色。这种变化是由 javascript 调用来重置颜色造成的。尝试从地图编辑器中删除 resetColors 调用。您现在尝试运行它时是否看到了区别?
我知道以前没有这样做过,但我感觉我们已经到了需要更多解释的地步了。现在,我将讨论地图编辑器、它的一些功能以及如何使用它。
地图编辑器是一个非常棒且实用的工具,我们可以用它来快速有效地构建这个游戏。它具有三个主要功能。您打开它时看到的第一个页面是设置地图的名称和等级。如果您正在同一张地图上制作多个等级,那么它们都需要相同的名称。然后,您可以输入地图的宽度和高度。我建议使用 15 x 15 或更小的尺寸,否则您需要进行大量的滚动操作,但无论您选择什么尺寸都可以。
完成地图详细信息填写后,点击开始地图编辑器。接下来你会看到一个拥有很多实用功能的屏幕。
- 为了加快地图构建速度,所有边缘会自动变成墙壁。为了地图文件加载器的顺利进行,请确保地图边缘始终有墙壁。
- 地图编辑器也采用了颜色编码,使一切都更具视觉美感。
- S 代表角色的起始位置。你可以设置多个起始位置,但我提供的文件总是选择离棋盘顶端最近的起始位置。如果你想添加随机选择起始位置的功能,欢迎尝试。
- 地图编辑器的另一个功能是 L,代表梯子。当角色站在梯子上时,可以上下移动。当角色处于最高地图层级(第 1 层)时,无法向上移动。反之,当角色处于最低地图层级时,无法向下移动。目前,我们假设所有地图有 5 个层级。
- 地图编辑器的最后一个(也是最好的)功能是导出文件按钮。它可以让你自动将地图以 .txt 文件的形式下载。然后,你可以使用这些 .txt 文件将地图加载到你的游戏中并进行游玩!
在这个版本的《死亡陷阱》中,我们需要添加上下梯子和掉入陷阱的功能。首先,最简单的做法是创建一个用于所有游戏移动的函数。
完成上述步骤后,我们需要将我们的 $_SESSION 变量设置为函数全局变量。这意味着该函数可以访问我们已有的 $_SESSION 变量中的值。通过在会话中设置地图名称和层级,我们始终知道当前所在的地图和层级。如果将相同的概念应用于地图数组值,我们始终知道加载后地图中的内容。
现在,每当角色处于陷阱上时,我们需要更改角色所在的层级,使他们下降一层(除非他们不在地图的最后层级!)。为了方便起见,我们将确保第 5 层的地图上没有陷阱。
角色的层级下降到下一张地图文件后,我们将加载该新层级的地图。在角色可以再次开始游玩该层级之前,我们需要找到该新地图的起始位置。为此,我编写了两个简单的函数。
<?php /************** * This finds the position of the starting location * marked with the value S and returns the X * coordinate. It MUST be passed an entire array * filled with maze data for it to work. * * Tip!: The variable name in the function parameter * (in this case its $array) does not have to match * the name of the variable you pass to the function * when you call it. **************/ function startPositionX($array) { for ($x = 0; $x < height($array); $x++) for ($y = 0; $y < width($array); $y++) if ($array[$x][$y] == "S") return $x; } /************** * This finds the position of the starting location * marked with the value S and returns the Y * coordinate. It MUST be passed an entire array * filled with maze data for it to work. **************/ function startPositionY($array) { for ($x = 0; $x < height($array); $x++) for ($y = 0; $y < width($array); $y++) if ($array[$x][$y] == "S") return $y; } ?>
其中一个函数用于查找起始位置的 X 坐标,另一个函数用于查找 Y 坐标。使用这两个函数,我们可以重置角色在新加载的地图上的默认位置。请注意,高度和宽度是我编写用于查找二维数组高度和宽度的附加函数。
梯子使用了类似的概念,但有一个区别。如果角色站在梯子上,他们可以选择向上或向下移动。为此,我为梯子编写了一个特殊的 if 语句。当角色站在梯子上时,可以使用向上和向下按钮上下移动梯子,而不是在地图上向后或向前移动。如果角色处于最底层,我们允许他们向后退,而不是向下移动梯子,如果他们处于顶层,我们允许他们向前移动,而不是向上移动一层。
我们的游戏正在逐步完善!我对目前的成果非常满意。不仅可以上下移动梯子、掉入陷阱、找到宝藏,而且玩起来也很有趣。现在,我认为我们为角色移动机制构建了一个非常坚实的基础。我认为现在是时候通过添加数据库来将游戏的复杂度提升到新的高度了。
工作版本
源代码
地图文件
亲自尝试
在本课程中,我们真正开始将更多内容整合在一起。现在,我们知道如何从外部数据源加载地图并在地图上的特定点切换地图。现在,我们已经拥有了一个相当不错的游戏地图/角色移动机制框架,一旦游戏完成,就可以使用这个框架。
但这还不是我们想要的!我们需要从数据库加载和准备所有内容,以便可以随时根据需要进行更改。在下一课中,我们将学习 SQL 简介,学习如何设置和连接数据库、创建表格以及将迄今为止完成的所有内容(包括简单的地图编辑器)更改为从数据库提取数据和保存数据到数据库。
看看!仅仅 5 堂课,我们就开始学习如何与数据库进行交互了。