创建你自己的模拟游戏/MySQL数据库类
在上一课中,您学习了函数、读取和写入文件、一些简单的JavaScript以及向游戏中添加功能,以便我们可以交换地图和上下移动地图层级。现在这一切都很好,但我们生活在数据库时代,所以是时候动动脑筋了。让我们开始将到目前为止所做的一切转换为数据库。
市场上有很多大型数据库软件公司,但我个人非常喜欢MySQL(尤其是因为它免费……)。SQL是一种标准化的查询语言,但并不那么标准。大多数基本操作和概念在不同类型的数据库软件中都可用,但并非全部。这里的所有SQL都是假设您使用的是MySQL 4.0或更高版本编写的。
那么,什么是数据库?如果您认为自己从未使用过数据库,那您就错了。您现在是否正在网上阅读这篇文章?猜猜看,您正在阅读数据库中的信息。您几乎可以肯定,您访问的任何大型网站都使用数据库来存储其在线内容。
拿什么来比较呢?如果您曾经使用过Microsoft Excel或Microsoft Access,那么您对我要教授的基本知识就会有一个初步的了解。所以,就是这样。
很多人对其中的一些术语感到困惑,所以在正式使用它们之前,我将先介绍一下。
数据库 - 它可以指代两件事。人们通常用它来指代数据库软件(MySQL、Oracle),但它也指代存储库或大型数据集合,该集合由多个表组成。当我使用术语“数据库”时,我指的是大型数据集合,而不是实际的软件。如果我想指代软件,我会按其名称称呼它:MySQL。可以将数据库想象成Excel中的工作簿,其中包含多个电子表格,但它们都是同一文件的一部分。
表 - 数据库由许多表组成。表可以帮助您将相似的数据收集在一起,形成关系,并为插入其中的数据设置约束/限制。在本课中,我们将创建和使用几个表,这些表构成了我们所有地图数据。可以将表想象成Excel中的单个电子表格。
行 - 行是表中的一条水平数据线。
列 - 列是表中的一条垂直数据线。
键 - 在SQL中,事物由键来标识。可以将键视为区分一条记录与另一条记录的方法。在美国,每个人都有一个唯一的社会安全号码,这样政府就可以区分不同的John Smith。有时键可以由多个部分组成。例如,如果您知道一个John Smith住在佛罗里达州,另一个住在新泽西州,那么您就可以区分这两个John Smith。键的工作方式也是一样的。回到我之前提到的Excel示例,可以将键想象成电子表格文件上的列或行标题之一(顶部的A-Z以及侧边)。
为了学习,在介绍将PHP与SQL结合之前,我将引导您了解一些基本的SQL。我们需要做的第一件事是为“厄运深渊”创建一个数据库。为了帮助您区分我何时编写SQL代码以及何时编写PHP代码,我会在所有SQL语句之前加上mysql>,就像您在mysql命令提示符屏幕上看到的那样。
mysql> CREATE DATABASE pitsofdoom;
比您想象的要简单得多,对吧?大多数人在使用SQL时都有一个通用规则,即他们将SQL命令词大写,并将自己的文本小写。我相信在某些数据库软件中,大写是必需的,但在MySQL中并非必需。您可以选择自己喜欢的任何方式。
这几乎和创建数据库一样简单,但有一些例外。当我们创建表时,必须为将要使用的所有行值提供类型。但是,在这样做之前,我们需要考虑这些表的,也就是游戏地图表的,设计。
让我们这样想
每张地图都有1个名称和多个层级 - 我们需要知道每张地图的最大层级。
每张地图都有很多关于每个层级的数据 - 将这些数据与地图名称和层级数据分开可能是一个好主意,因为数据量很大。此外,由于我们有如此多的地图数据,我们不想重复地图名称等内容(我们实际上只需要知道一次地图名称即可)。
因此,我们游戏中的地图应该至少有两个表。一个表包含地图名称和层级,另一个表包含该特定地图的所有数据。如果我们绘制出表的草图,它们将如下所示
表名称:Map
字段
ID:此地图的唯一编号(数字)
Name:此地图的名称(字符串)
MaxDepth:此地图的最大深度层级(数字)
表名称:MapData
字段
Id:此地图数据信息的唯一编号(数字)
MapId:此数据所属的地图的ID(数字)
X:此地图值的x坐标(数字)
Y:此地图值的y坐标(数字)
Z:此位置在地图上的深度(数字)
Value:地图中字段的值,例如X、T、W、E(单个字符)
现在我们已经设计好了表,我们将把它们转换为SQL。
mysql> CREATE TABLE map ( id integer NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, maxdepth integer NOT NULL, UNIQUE KEY(id));
在这个第一个表中,我们创建了地图信息。我们将其设置成ID号必须唯一,并且在添加记录时会自动递增(因此我们不必自己执行此操作!)。您会注意到,我们想要放入数字的任何内容都具有INTEGER类型。我们想要放入文本的任何内容都具有VARCHAR类型,然后我们指定了该字段的最大字符数。因此,在这种情况下,地图名称的长度不能超过100个字符。
我们创建的表的可视化表示将如下所示
ID Name MaxDepth
这三个字段共同构成了我们的地图表。现在让我们创建我们的地图数据表
mysql> CREATE TABLE mapdata ( id integer NOT NULL AUTO_INCREMENT, mapid integer NOT NULL, x integer NOT NULL, y integer NOT NULL, z integer NOT NULL, value varchar(1), UNIQUE KEY(id))
从视觉上看,这将如下所示
ID MapID X Y Z Value
所有这些字段共同构成了mapdata表。但是,我们的表需要的不仅仅是我们将要添加的数据的列。让我们看看如果我们添加了为Round Hill创建的地图的一些信息,它在视觉上会是什么样子。
ID Name MaxDepth 1 Round Hill 5
我们游戏中的第一张地图的ID号为1。如果您还记得,我们设置了地图表以自动递增ID字段。这意味着它将始终在ID号的值上加1。表中第一个条目的最大深度为5,因为我们的地图有五个层级。现在让我们看看我们的地图数据表在插入一些第一层级信息后的样子
ID MapID X Y Z Value 1 1 0 0 1 W 2 1 0 1 1 W 3 1 0 2 1 W 4 1 0 4 1 W 5 1 0 5 1 W 6 1 0 6 1 W 7 1 0 0 7 W 8 1 0 8 1 W 9 1 0 9 1 W 10 1 0 10 1 W 11 1 0 11 1 W 12 1 0 12 1 W 13 1 0 13 1 W 14 1 0 14 1 W 15 1 1 15 1 W 16 1 1 0 1 W 17 1 1 1 1 X 18 1 1 2 1 X 19 1 1 3 1 E 20 1 1 4 1 E 21 1 1 5 1 E 22 1 1 6 1 E 23 1 1 7 1 W 24 1 1 8 1 T 25 1 1 9 1 E 26 1 1 10 1 W 27 1 1 11 1 E 28 1 1 12 1 E 29 1 1 13 1 E 30 1 1 14 1 W
这些内容看起来熟悉吗?应该熟悉!这是Round Hill地图第一层级的信息。实际上,它是我们导出的地图文件中的前两行。这引出了我们的下一个主题,究竟如何使用MySQL将这些信息添加到数据库中?
首先,让我们尝试将Round Hill的地图信息插入到我们的地图表中。
mysql > INSERT INTO map (name, maxdepth) VALUES ('Round Hill', '5');
SQL中的插入语句由您要插入的表、您要插入数据的字段以及数据组成。数据的顺序应与您输入的列名称顺序匹配。因此,如果我们将值反转为'5'、'Round Hill',当我们尝试将文本值Round Hill插入数值时,最终会出现错误。
现在让我们将一些地图信息插入到mapdata表中。
mysql > INSERT INTO mapdata (mapid, x, y, z, value) VALUES ('1', '0', '0', '1', 'W'), ('1', '0', '1', '1', 'W'), ('1', '0', '2', '1', 'W');
在这种情况下,我实际上使用一个插入语句插入了三行。每个条目都用括号括起来。当您插入内容时,您可以使用这两种格式中的任何一种,哪种对您最有效即可。
一旦您在数据库的表中有了数据,您就可以开始使用它了。假设我们有一个名为members的表,其中包含以下数据
ID Name Username Password Email Show_Email 1 Jade Krafsig varun ilovehorses [email protected] Y 2 John Doe Jdoe imadope [email protected] N 3 Jane Doe Jdoe howdy [email protected] N
我们的数据库中有三个成员。假设John Doe正在尝试使用他的电子邮件地址和密码登录。在我们允许他访问任何仅限成员的区域之前,我们需要验证此用户名和密码是否正确,然后确定他的显示电子邮件状态。
mysql > SELECT id, name, show_email FROM members WHERE email='[email protected]' AND password='imadope';
select语句分为几个部分,我现在只展示一些基础部分。在SELECT单词之后,列出您要查看的列的名称。在FROM单词之后,列出表的名称。WHERE部分非常容易理解。如果我们运行此查询,我们将获得以下表格
ID Name Show_Email 2 John Doe N
立即注意的一件事是,当我们选择某些内容时,我们总是会得到一个TABLE。这意味着我们可以从一个select语句中获取多行数据。例如,请看此查询
mysql > SELECT * FROM members WHERE username='Jdoe';
ID Name Username Password Email Show_Email 2 John Doe Jdoe imadope [email protected] N 3 Jane Doe Jdoe howdy [email protected] N
在此示例中,我们使用星号告诉MySQL我们想要表中所有用户名等于Jdoe的成员的所有列字段。现在您返回了多个记录。查看下面的一些查询,您能否确定如果运行它们将生成什么表?
mysql > SELECT id FROM members WHERE show_email='N'; mysql > SELECT * FROM members WHERE email='[email protected]' OR email='[email protected]'; mysql > SELECT * FROM members WHERE 1=1; mysql > SELECT * FROM members; mysql > SELECT username, password FROM members WHERE username != password; mysql > SELECT * FROM members WHERE id >= 2;
您认为已经弄清楚了吗?很好!让我们回顾一下。第一个查询查找show_email字段设置为N的所有成员。第二个查询选择电子邮件地址为一个值或另一个值的所有列。第三个查询将选择整个数据库中的所有内容,之后的查询也是如此。下一个查询显示用户名和密码,其中用户名字段和密码字段中的值不相同,最后一个查询查找ID大于或等于2的所有成员。
数据通常不会保持静态,尤其是多人在线游戏的玩家数据。人们更改密码、撰写消息、进行任务等等。为了让游戏反映这一点,我们需要在人们玩游戏时更新数据。这就是更新语句的用武之地。让我们使用之前相同的members表。假设John Doe已登录到他的帐户并想要更改他的电子邮件地址
mysql > UPDATE members SET email='[email protected]';
如果您立即意识到这会导致问题,那么您的思维方式是正确的。如果您没有立即注意到错误,请再看看。计算机真的很笨,它们会完全按照您的指示去做。如果您运行此查询,您将更改游戏中所有人的密码为John Doe的新电子邮件地址。多么糟糕的灾难!
这就是键变得很重要的原因。为了识别我们的数据库中属于John的哪条记录,并且只更改属于John的信息的数据,我们可以使用成员表的键:ID。
mysql > UPDATE members SET email='[email protected]' WHERE id='2';
当我们运行此查询时,只有John的电子邮件地址受到影响。完美!
更新语句可以像您想要的那么简单或复杂。我们可以通过确定id号是奇数还是偶数来更新每隔一行,我们可以根据show_email字段更改密码,等等。但是您必须小心使用更新语句。如果我们这样做会发生什么
mysql > UPDATE members SET password='heya', email='[email protected]' WHERE username='jdoe';
现在我们再次遇到更改多条记录的问题。在我们的members表中,John和Jane Doe都使用相同的用户名。如果我们运行此查询,我们将重置他们的两个密码为heya,并将他们的两个电子邮件地址重置为[email protected]。
查看一些其他更新查询。你能弄清楚它们会做什么吗?
mysql > UPDATE members SET password='test' WHERE id <= 1; mysql > UPDATE members SET username='Jade2', password='newpass' WHERE email='[email protected]' AND username='John'; mysql > UPDATE members SET showing_emails='Y';
第一个查询将所有成员的密码设置为test,如果他们的ID号小于1。第二个查询设置所有电子邮件匹配且用户名为John的成员的用户名和密码。第三个也是最后一个查询失败,没有名为showing_emails的列。如果它改为show_email,它将把每个人的show_email值设置为Y。
从数据库中删除内容有时几乎与放入内容一样重要。我运行相当小的服务器,并且有很多活跃的用户在玩游戏。为了使查询更快,我删除了旧数据。还有其他删除数据的理由,我相信您可以想到一些。
所以您知道,无法删除一个文件中某个特定的字段。mysql中的删除是全有或全无的,它要么删除整行,要么不删除。
mysql > DELETE FROM members WHERE id='3';
这将Jane Doe从members数据库中删除。同样,您最终可能会遇到与更新时相同的删除问题。请仔细注意任何删除语句,以免删除数据库中的所有内容!
为了从php文件中访问mysql中的数据库信息,我们必须打开与数据库的连接。我通常将其制作成一个名为dbconnect.php的文件,并在每个需要数据库访问的页面顶部包含它。您的文件将根据您使用的数据库的用户名、密码和名称而有所不同,因此您需要更改此文件以使其适合您
<?php /************ * File: dbconnect.php * Purpose: open database connection *************/ //open our database connection with the correct username & password mysql_connect("localhost", "USERNAME_HERE", "PASSWORD_HERE") or die("could not connect to the database because: " . mysql_error()); //change to the database we want to use mysql_select_db("DATABASE_NAME_HERE") or die ('could not switch to using database because: " . mysql_error()); ?>
第一个函数mysql_connect启动与数据库的连接。如果您使用的是本地数据库(即您托管网站的位置),则localhost这个词永远不会改变。函数末尾的or die语句是帮助您调试mysql/php代码的好方法。如果mysql在尝试连接时出现问题,它会自动为您提供关于问题的相当描述性的错误消息。
第二个函数mysql_select_db切换到您将使用的数据库。通常,您在同一服务器上有多个数据库。例如,我有两台服务器。在每台服务器上,我都有2到15个数据库。当我运行PHP脚本时,它需要知道我正在使用哪个数据库,然后才能尝试访问我的任何表。
现在您已经看到了PHP内置的两个很棒的函数,它们使使用MySQL变得容易。既然我们可以连接到我们的数据库,让我们开始对其执行操作。
<?php include('dbconnect.php'); //we start off by setting the result of our query to a variable named $result $result = mysql_query("SELECT id, name FROM members WHERE id='1'") or die ('cannot select the member id because: ' . mysql_error()); //now we need particular information from that result put into our $row variable $row = mysql_fetch_assoc($result); //now we can access the values in our $row variable using the name of the field we want echo "Hello " . $row['name'] . "! Your member ID number is: " . $row['id']; ?>
这将打印:Hello Jade!您的会员ID号为:1
我不确定您是否和我一样,但我认为这太棒了。但在本例中,我们需要知道某人的ID号才能显示有关他们的信息。如果我们想根据某人输入文本字段的数字更改它会发生什么?看看下一个示例
<?php include('dbconnect.php'); if ($_POST['id']) //they've entered an ID number into the box { $id = $_POST['id']; //set this variable to what they entered $result = mysql_query("SELECT id, name FROM members WHERE id='$id'") or die ('cannot select the member id because: ' . mysql_error()); //now we need particular information from that result put into our $row variable $row = mysql_fetch_assoc($result); //now we can access the values in our $row variable using the name of the field we want echo "Hello " . $row['name'] . "! Your member ID number is: " . $row['id']; } ?> <form action="#" method="post"> Enter an ID number: <input type="text" name="id" value="<?php echo $_POST['id']; ?>" /> <center><input type="submit" name="submit" value="Click Me!" /></center> </form>
在本例中,我们的页面现在会提取有关您输入的任何成员ID号的正确信息。现在,如果有人使用数字并且小于4,这可以正常工作,但是如果他们输入其他内容会发生什么?您能否修复此问题,以便仅在数字有效时才显示有关成员的信息?这里有两个提示,您可以使用函数isNumeric($number)来确定某人输入的内容是否为数字,然后您可以检查$row['field_name']返回的值中是否有数据。
让我们显示所有成员的列表。我们该怎么做?看看这段代码
<?php include('dbconnect.php'); //I always change this variable to loop so it's easier to read $loop = mysql_query("SELECT id, name FROM members") or die ('cannot select the member id because: ' . mysql_error()); //now we want all the information that $row finds, not just the top value while ($row = mysql_fetch_assoc($loop)) { echo "Member ID: " . $row['id'] . " - " . $row['name'] . "<br/>"; } ?>
这段代码遍历并回显数据库中每个成员的ID号和姓名,只要$row有值。这意味着一旦我们不再从表中返回任何结果,循环将自动停止。
在继续创建SQL类之前,您还需要了解一件事,那就是如何更新行。
<?php include('dbconnect.php'); if ($_POST['password']) { //notice how we don't set this equal to a variable now mysql_query("UPDATE members SET password='" . $_POST['password'] . "' WHERE id='1'") or die ('cannot select the member id because: ' . mysql_error()); echo "You updated the password for Jade!"; } ?> <form action="#" method="post"> Enter an ID number: <input type="text" name="password" /> <center><input type="submit" name="submit" value="Update Jade's Password!" /></center> </form>
在本例中,我们只有一个主要区别。对于mysql update或delete语句,您不需要在它前面使用变量。更新要么成功,要么失败。删除要么成功,要么失败。没有要存储以供以后使用的东西。
哇!现在我们准备将这两种技能结合到我们的游戏中。与其在各处编写大量的查询,我们将创建一个SQL类来帮助我们。它将为我们完成大量工作,以便我们可以专注于更大的目标。
类是将许多较小的细节从更大的画面中抽象出来的好方法。我们将创建一个简单的自动售货机类。每个人以前都使用过自动售货机,所以这是一个很好的例子。
自动售货机由许多不同的部件组成,但当所有部件组合在一起时,我们只将自动售货机视为一个对象。类使用相同的想法,许多较小的部件构成一个更大的对象。让我们考虑一下水果
多种类型的水果
但都具有共同的特征
名称
颜色
大小(小、中、大、特大)
甜度(是或否)
我们可以对水果执行多个操作
清洗
食用
擦亮
接管世界——开玩笑的
使用这种非常简单的分解,让我们创建一个水果类
<?php class fruit { //class variables, these are variables //that belong specifically to this class var $name; var $color; var $size; var $sweet; var $clean; var $washed; function fruit($name) { //this is a class constructor. It always has the same name //as the class and the same parameters. Whenever we //make a fruit class this is called automatically $this->name = $name; //we automatically give this fruit its name $this->clean = False; //our fruit always needs to be washed first $this->washed = 0; //we haven't washed it any times yet } //but we want to be able to set other things about the fruit function setColor($color) { $this->color = $color; } function setSize($size) { $this->size = $size; } function setSweet($sweet) { $this->sweet = $sweet; } //lets make a way to wash our fruit function wash() { $this->clean = True; //our fruit is clean now $this->washed++; //we've washed our fruit one more time } //we want to eat our fruit now function eat() { if (!$this->clean) echo "You should always wash your $this->color $this->name first!!! "; if ($this->clean && $this->washed < 2) echo "You're eating a dull looking piece of $this->name... "; if ($this->clean && $this->washed >= 2) echo "You're eating a shiny piece of $this->color $this->name! "; if (!$this->clean && $this->washed >= 2) echo "Your $this->name is shiny but you probably should wash it first. " if ($this->sweet) echo "This fruit is sweet."; else echo "This fruit is classified as a vegetable!"; } //we can make a shine function, that washes the surface of the fruit as well function shine() { $this->washed++; } } //end of our class //now that we have our class, let's make some fruit!! $orange = new fruit("Orange"); $orange->setSize("small"); $orange->setColor("orange"); $orange->setSweet(True); $fruit = new fruit("Watermelon"); $fruit->setSize("large"); $fruit->setColor("green"); $fruit->setSweet(True); $veggie = new fruit("Tomato"); $veggie->setSize("medium"); $veggie->setColor("red"); $veggie->setSweet(False); echo "Washing my $orange->name. "; $orange->wash(); echo "<br>Eating my $veggie->size $veggie->name. "; $veggie->eat(); echo "<br/>Washing my $orange->name again. "; $orange->wash(); echo "<br/>Shining my $fruit->size $fruit->name. "; $fruit->shine(); echo "<br/>Eating my $fruit->name. "; $fruit->eat(); echo "<br/>Eating my $orange->size $orange->name. "; $orange->eat(); ?>
尝试运行这段脚本。发生了什么?类最棒的一点在于,你在类中创建的所有函数都可以应用于该类的任何对象。在上面的示例中,我们创建了三个不同的水果对象。即使它们都是不同的变量,它们也都以不同的方式使用了水果类的相同函数。你还会注意到,我们可以使用 -> 箭头访问我们在类中创建的变量。尝试向这个类添加更多函数。尝试创建 $veggie = $fruit。当您执行 $veggie->name 时会发生什么?尝试向类中添加一个函数,使您可以同时设置所有属性(颜色、甜度、大小)。
那么,让我们开始吧
<?php /************** * File: mysqlobj.php * Purpose: database class **************/ class database{ //variables for this class var $database; var $host; var $username; var $password; var $classerror; var $connected; /************** * Purpose: default constructor, is called every time we create an object of this class * Precondition: host, username & password for the database, database we're using **************/ function database($host, $username, $password, $database) { if (!$username) return errorMsg("You must enter a username"); if ($username != "root" && !$password) return errorMsg("You must enter a password"); if (!$database) return errorMsg("You must enter a database"); if (!$host) $this->host = "localhost"; else $this->host = $host; $this->username = $username; $this->password = $password; $this->database = $database; $this->classerror = "Database Error: "; //automatically connect to the database $this->connect(); } /************** * Purpose: connect to the database * Precondition: none * Postcondition: connected to the database **************/ function connect() { mysql_connect($this->host, $this->username, $this->password) or die ($this->classerror . mysql_error()); mysql_select_db($this->database) or die ($this->classerror . mysql_error()); $this->connected = true; } /************** * Purpose: end connection to the database * Precondition: none * Postcondition: close database connection **************/ function disconnect() { mysql_close(); $this->connected = false; } /************** * Purpose: check for connected to database * Precondition: none * Postcondition: connected to the database **************/ function checkconnection() { if (!$this->connected) $this->connect(); } /************** * Purpose: query the database * Precondition: query to run * Postcondition: returns query data **************/ function query($sql) { if (!$sql) return errorMsg("You must enter a query"); $this->checkconnection(); $result = mysql_query($sql) or die ($this->classerror . mysql_error()); return $result; } /************** * Purpose: selection query * Precondition: fields, table, where * Postcondition: returns query data **************/ function select($fields, $table, $where) { if (!$fields) return errorMsg("You must enter a field"); if (!$table) return errorMsg("You must enter a table"); $this->checkconnection(); $result = mysql_query("SELECT $fields FROM $table $where") or die ($this->classerror . mysql_error()); $row = mysql_fetch_assoc($result); return $row; } /************** * Purpose: update query * Precondition: table, fields, where * Postcondition: field has been updated **************/ function update($table, $fields, $where) { if (!$fields) return errorMsg("You must enter a field"); if (!$table) return errorMsg("You must enter a table"); $this->checkconnection(); mysql_query("UPDATE $table SET $fields $where") or die ($this->classerror . mysql_error()); } /************** * Purpose: delete query * Precondition: table, where * Postcondition: row in table has been deleted **************/ function delete($table, $where) { if (!$table) return errorMsg("You must enter a table"); if (!$where) return errorMsg("You must enter a where condition"); $this->checkconnection(); mysql_query("DELETE FROM $table $where") or die ($this->classerror . mysql_error()); } /************** * Purpose: insert query * Precondition: table, values * Postcondition: row in table has been deleted **************/ function insert($table, $fields, $values) { if (!$table) return errorMsg("You must enter a table"); if (!$values) return errorMsg("You must enter values in the table"); $this->checkconnection(); mysql_query("INSERT INTO $table ($fields) VALUES ($values)") or die ($this->classerror . mysql_error()); //id of the row just inserted return mysql_insert_id(); } /************** * Purpose: find objects in the database then load them into an array * Precondition: field, table, and object * Postcondition: returns query data **************/ function loadArray($field, $table, $where, $object) { $loop = mysql_query("SELECT $field FROM $table $where") or die ('cannot load object data from table $table: ' . mysql_error()); $customarray = array(); while ($row = mysql_fetch_array($loop)) array_push($customarray, new $object($row[$field])); return $customarray; } /************** * Purpose: delete everything in a table * Precondition: table * Postcondition: all fields in table have been deleted **************/ function truncate($table) { if (!$table) return errorMsg("You must enter a table"); $this->checkconnection(); mysql_query("TRUNCATE $table") or die ($this->classerror . mysql_error()); }} //end of class /************** * Purpose: show a formatted error message **************/ function errorMsg($message) { echo "<center>Error: $message.</center><br/>"; } /************** * Purpose: show a formatted success message **************/ function successMsg($message) { echo "<center>Success! $message.</center><br/>"; } ?>
简而言之,我们可以使用这个类来完成数据库所需的所有操作。看看我创建的这个测试文件,看看类是否正常工作。尝试创建一个名为 attributes 的表,其中包含 ID 号和名称。在表中输入一些值,然后运行此脚本
<?php include("mysqlobj.php"); //testing connectionecho "<b>Testing connection:</b> ";$database = new database("localhost", "username_here", "password_here", "databasename_here");echo "success!<br/>"; //testing query functionecho "<b>Testing query function:</b> ";$loop = $database->query("SELECT * FROM attributes");while ($row = mysql_fetch_assoc($loop)){ print_r($row); echo "<br/>";} echo "<br/><br/><b>Testing select function:</b> ";//testing select function$result = $database->select("name", "attributes", "WHERE id='3'");echo $result['name']; echo "<br/><br/><b>Testing update function:</b> ";$database->update("attributes", "name='test field'", "WHERE id='12'");$result = $database->select("name", "attributes", "WHERE id='12'");echo $result['name']; echo "<br/><br/><b>Changing Name Back:</b> ";$database->update("attributes", "name='flexibility'", "WHERE id='12'");$result = $database->select("name", "attributes", "WHERE id='12'");echo $result['name']; echo "<br/><br/><b>Testing Insert:</b> ";$id = $database->insert("attributes", "name", "name='test'");echo $id; echo "<br/><br/><b>Testing Delete:</b> ";$database->delete("attributes", "WHERE id='$id'");echo "success!"; echo "<br/><br/><b>Testing disconnect:</b> ";$database->disconnect();echo "success!"; echo "<br/><br/><b>Testing Insert:</b> ";$id = $database->insert("attributes", "name", "name='test2'");echo $id; echo "<br/><br/><b>Testing Insert:</b> ";$id = $database->insert("attributes", "name", "name='test3'");echo $id; //testing query functionecho "<br/><br/><b>Listing all values in the database:</b> ";$loop = $database->query("SELECT * FROM attributes");while ($row = mysql_fetch_assoc($loop)){ print_r($row); echo "<br/>";} echo "<br/><br/><b>Testing Truncation:</b> ";$id = $database->truncate("attributes");echo $id; //testing query functionecho "<br/><br/><b>Listing all values in the database:</b> ";$loop = $database->query("SELECT * FROM attributes");while ($row = mysql_fetch_assoc($loop)){ print_r($row); echo "<br/>";} echo "<br/><br/><b>Disconnecting:</b> ";$database->disconnect();echo "success!";?>
当你查看此页面时会发生什么?你能看到它如何影响数据库中的内容吗?太棒了!现在我们准备将游戏中的所有内容转换为数据库。
没有一种简单的方法可以将我们到目前为止所做的内容转换为使用数据库。我的建议是,以你最舒适的方式来处理它。就我个人而言,我会从地图编辑器开始,这样一旦它转换完成,你就可以在数据库中拥有地图来修复角色页面。
一旦有人要保存地图,我们需要
1. check to see if a map with that name already exists in the map table 2. if the map already exists we want to load the existing values for that map 3. if the map doesn't exist we can show what we did before 4. when someone clicks on the save button we need to 1. update the map values in the database if it already exists OR 2. add those new values to our mapdata table 5. that's it!
本课内容很多。如果所有内容都无法理解,请不要担心。尝试创建一个数据库并使用它进行操作,使用 SQL 或我上面提供的数据库类添加、删除和更新内容。一旦你对此感到自信,尝试将数据库值分配给变量,创建一个小的表单来更新数据库中的值。然后,当你厌倦了这些操作后,继续将 character.php 和 mapeditor.php 文件转换为使用数据库。
如果你遇到困难,不用担心!所有可用的代码都在下面。尽情享受。
工作版本
角色文件:character.php
地图编辑器:mapeditor.php 我把它留给你,以便你实际上可以将地图添加到数据库中,所以请尊重我的数据库!!谢谢 :)
源文件
角色文件:character.php
地图编辑器:mapeditor.php
数据库表:database.sql(包含地图文件数据)
数据库表:database_empty.sql(不包含地图数据)
地图文件数据库导入器:mapfile_importer.php 这将把我们之前创建的地图文件直接导入到你的数据库中!!
Mysql 数据库类:mysqlobj.php
现在,我们已经将我们简单的单键点击游戏变成了一个功能完善的数据库驱动游戏!!我们不仅可以使用地图编辑器创建地图并将其直接存储到数据库中,还可以在地图中上下移动层级,使用梯子,掉入陷阱,并确保我们不会撞到墙壁。
但是我们的游戏远未完成。在下一课中,我们将讨论创建成员类和角色类以及它们如何相互交互。然后,我们将在数据库中创建成员表和角色表。最后,我们将编写一个登录脚本,以便只有拥有角色的成员才能访问我们简单的游戏地图并进行游戏。
阅读下一章