建立你自己的模擬遊戲/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 jade@design1online.com Y 2 John Doe Jdoe imadope jdoe@gmail.com N 3 Jane Doe Jdoe howdy jane.doe@gmail.com N
我們的資料庫中有三個成員。假設John Doe正在嘗試使用他的電子郵件地址和密碼登入。在我們允許他訪問任何僅限成員的區域之前,我們需要驗證此使用者名稱和密碼是否正確,然後確定他的顯示電子郵件狀態。
mysql > SELECT id, name, show_email FROM members WHERE email='jdoe@gmail.com' 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 jdoe@gmail.com N 3 Jane Doe Jdoe howdy jane.doe@gmail.com N
在此示例中,我們使用星號告訴MySQL我們想要表中所有使用者名稱等於Jdoe的成員的所有列欄位。現在您返回了多個記錄。檢視下面的一些查詢,您能否確定如果執行它們將生成什麼表?
mysql > SELECT id FROM members WHERE show_email='N'; mysql > SELECT * FROM members WHERE email='jane.doe@gmail.com' OR email='jdoe@gmail.com'; 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='john.doe@gmail.com';
如果您立即意識到這會導致問題,那麼您的思維方式是正確的。如果您沒有立即注意到錯誤,請再看看。計算機真的很笨,它們會完全按照您的指示去做。如果您執行此查詢,您將更改遊戲中所有人的密碼為John Doe的新電子郵件地址。多麼糟糕的災難!
這就是鍵變得很重要的原因。為了識別我們的資料庫中屬於John的哪條記錄,並且只更改屬於John的資訊的資料,我們可以使用成員表的鍵:ID。
mysql > UPDATE members SET email='john.doe@gmail.com' WHERE id='2';
當我們執行此查詢時,只有John的電子郵件地址受到影響。完美!
更新語句可以像您想要的那麼簡單或複雜。我們可以透過確定id號是奇數還是偶數來更新每隔一行,我們可以根據show_email欄位更改密碼,等等。但是您必須小心使用更新語句。如果我們這樣做會發生什麼
mysql > UPDATE members SET password='heya', email='john.doe@gmail.com' WHERE username='jdoe';
現在我們再次遇到更改多條記錄的問題。在我們的members表中,John和Jane Doe都使用相同的使用者名稱。如果我們執行此查詢,我們將重置他們的兩個密碼為heya,並將他們的兩個電子郵件地址重置為john.doe@gmail.com。
檢視一些其他更新查詢。你能弄清楚它們會做什麼嗎?
mysql > UPDATE members SET password='test' WHERE id <= 1; mysql > UPDATE members SET username='Jade2', password='newpass' WHERE email='jade@design1online.com' 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
現在,我們已經將我們簡單的單鍵點選遊戲變成了一個功能完善的資料庫驅動遊戲!!我們不僅可以使用地圖編輯器建立地圖並將其直接儲存到資料庫中,還可以在地圖中上下移動層級,使用梯子,掉入陷阱,並確保我們不會撞到牆壁。
但是我們的遊戲遠未完成。在下一課中,我們將討論建立成員類和角色類以及它們如何相互互動。然後,我們將在資料庫中建立成員表和角色表。最後,我們將編寫一個登入指令碼,以便只有擁有角色的成員才能訪問我們簡單的遊戲地圖並進行遊戲。
閱讀下一章