AJAX Tutorial: 2 Player Tic-Tac-Toe Game (no database required)

Comments 7 Standard

If you haven’t read the first tutorial, the PHP version of this game without AJAX, then you should start there. This tutorial assumes you’ve already read the first one so I’m not going to explain how I actually go about programming the game. Instead this will focus on how you modify the original game so it works with AJAX. That means you won’t need to refresh the page between each player’s turn.

Download the Working Source Code
.zip archive

Getting jQuery

First thing is first we’ll need to get the jQuery library before we start updating any code. For those of you that don’t know, jQuery is code library that makes doing JavaScript quick and pretty painless. You can download or link to a copy offered on a Content Delivery Network (CDN) like Google Code. Personally I recommend downloading a copy if you’re going to post this game on a high traffic/visibility website. Sometimes if you link to a copy of jQuery on a CDN your site can experience lag and/or delays if the CDN is slow and your game won’t work at all if the CDN is down. On the other hand if you have a small website or limited space to store your files then there’s no need to download a copy of jQuery, linking to it is a better option. In this tutorial I’ve downloaded and included the jQuery file in the js folder of the .zip archive.

Setting Up For AJAX

Because we want our game to display using AJAX we need to create a new JavaScript file called hangman.js. This is what we’ll use to make all of our AJAX calls and respond to the player’s input.

Now that we have two JavaScript files we have to update our index.php file so it knows both of those JavaScript files are necessary to run the game. In the <head> tag, under the link to our stylesheet, we add two lines of code that tell our browser to load our JavaScript files:

<head>
        <title>Tic Tac Toe</title>
        <link rel="stylesheet" type="text/css" href="inc/style.css" />
        <script language="Javascript" src="js/jquery-1.7.1.min.js"></script>
        <script language="Javascript" src="js/tic-tac-toe.js"></script>
</head>

We also need to remove our $_SESSION[‘game’][‘tictactoe’] check from the top of our index file. Our AJAX calls will be running the game so it’s no longer necessary here. However we leave the session_start() at the top of the page so that if the player accidentally refreshes the page they don’t loose the game they had in progress.

Next we remove the code inside of our <div id=”content”> and set that aside for later because we’ll need to use parts of it in our AJAX. In it’s place we’re going to enter a loading message. This is what the page will display before the AJAX calls have finished processing.

<body>
        <div id="content">
        <center>Loading Tic-Tac-Toe.... please wait.</center>
        </div>
</body>

Writing the Tic-tac-toe.js File

Now it’s time to jump into jQuery and AJAX.

$(document).ready(function() {

    //start the game when the page loads
    playGame();

});

jQuery uses a special function to check when the page has finished loading. Anything you put inside of this function will run as soon as the page is loaded, or in response to something someone has done on the page, like mouse clicks or using the keyboard. For this tutorial all we need it to do is call our AJAX function that will load and display the game to the content div on our index.php file.

/***
* Purpose: play tic-tac-toe
* Preconditions: none
* Postconditions: new game has started or existing game is in play
***/
function playGame()
{
    $.ajax({
        url: 'ajax/index.php',
        data: {type: 'playGame'},
        success: function( data ) {
            $("#content").html(data);
        }
    });
}

Inside of our playGame() function we use AJAX to tell the browser to load our ajax file and send it some data (the type of action we’re doing, whether or not to start a new game, the player taking their turn). Then we use a success callback function to load the results of our ajax call onto the page. A callback function is a function that runs as a result of being called by another process. In this case our callback function, success, is loading the data we’ve retrieved through AJAX and putting it into the content div’s HTML property.

/***
* Purpose: place an X or O on the board
* Preconditions: none
* Postconditions: game status updated
***/
function makeMove()
{    
    var selected_spot = null;

    //find the first spot on the board they have an X or O inside of
    $(".board_spot").each(function() {
        if ($(this).val()) {
            //they have a value in this spot, break out of the loop
            selected_spot = $(this);
            return false;
        }
    });

    //make sure they've selected a spot
    if (selected_spot == null) {
        alert("You must select a spot on the board first.");
        return false;
    }

    //make sure we only get an X or O value
    if ($(selected_spot).val() != "X" && $(selected_spot).val() != "O") {
        alert("Invalid selection made. Please try again.");
        return false;
    }

    //pass the spot and the value they selected to our ajax file
    $.ajax({
        url: 'ajax/index.php',
        data: {type: 'playGame', spot:$(selected_spot).attr("name"), value:$(selected_spot).val()},
        success: function( data ) {
            $("#content").html(data); 
        }
    });
}

If we want to respond to someone trying to pick a spot we use a fairly similar process. First we loop through all of the input boxes on the page (we’ve added a call called board_spot to them in our displayBoard class function) and save the first one that has a value into our selected_spot variable. Then we check to make sure they’ve selected a spot and that the value in the spot is either an X or an O. Finally we send the spot they selected and the value to our ajax file.

/***
* Purpose: start a brand new game
* Preconditions: none
* Postconditions: new game has started
***/
function newGame()
{
    $.ajax({
        url: 'ajax/index.php',
        data: {type: 'playGame', newgame: true},
        success: function( data ) {
            $("#content").html(data);
        }
    });
}

The last piece of our ajax file is the newGame function. When the game is over we want to make sure we use AJAX to update the game state and then refresh the page to a new game.

Writing the AJAX File

Now that our JavaScript file will send AJAX requests we need to write the file on the other end of the request — the file that responds to the data we’re sending it. Create a new folder and name is ajax. Inside of it make an index.php file. Inside of the file put the following:

<?php
/***
* File: ajax/index.php
* Author: design1online.com, LLC
* Created: 4.26.2012
* License: Public GNU
* Description: respond to ajax calls
***/

//include the required files
require_once('../oop/class.game.php');
require_once('../oop/class.tictactoe.php');

//this will keep the game data as they make a new ajax request
session_start();

//respond to AJAX requests
echo doAction($_GET);

function doAction($getdata)
{
    switch ($getdata['type'])
    {
        case "playGame":
            return playGame($getdata['spot'], $getdata['value']);
        default:
            return "Invalid option selected.";
    }
}

/***
* Purpose: Display and play the game
* Preconditions: a game exists
* Postconditions: the current game is displayed to the screen
***/
function playGame($spot, $value)
{    
    //if they haven't started a game yet let's load one
    if (!$_SESSION['game']['tictactoe'])
        $_SESSION['game']['tictactoe'] = new tictactoe();

    echo "<h2>Let's Play Tic Tac Toe!</h2>";
    $_SESSION['game']['tictactoe']->playGame($spot, $value);
}

In this file we have two functions, doAction and playGame. Both functions take the $_GET data sent by our AJAX calls and do various things depending on the data sent to them. doAction is run every time this ajax file loads. It decides which function it needs to call, depending on the type we’ve sent it, and then returns the result to the screen.

Now pull up that code I had you set aside earlier. We’re going to move that into our playGame function with a few adjustments. We no longer need the <form> tags around our game data. In addition instead of sending $_POST data to our hangman object we’re now sending $_GET data. The $_GET data contains the information we were previously posting from the <form> tags. Since AJAX is refreshing what appears inside of our content div there’s no reason to use our <form> and $_POST variables anymore.

Last But Not Least

We’re almost done! Before we can view our handy work we need to open our tic tac toe OOP file. Anywhere we had a $_POST statement we need to change that to a $_GET since we’re no longer using the $_POST variable. We also need to adjust the move() function so it accepts both the spot and the value of that spot. Our new move function looks like this:

/**
    * Purpose: trying to place an X or O on the board
    * Preconditions: the position they want to make their move, the X or O value
    * Postconditions: the game data is updated
    **/
    function move($spot, $value)
    {            

        if ($this->isOver())
            return;

        if ($value == $this->player)
        {    
            //update the board in that position with the player's X or O 
            $coords = explode("_", $spot);
            $this->board[$coords[0]][$coords[1]] = $this->player;

            //change the turn to the next player
            if ($this->player == "X")
                $this->player = "O";
            else
                $this->player = "X";

            $this->totalMoves++;
        }

        if ($this->isOver())
            return;
    }

Finally, we need to update our new game and take turn buttons so they run the newGame and playGame javascript functions we wrote earlier:

<input type=\"submit\" name=\"move\" value=\"Take Turn\" onClick=\"makeMove();\" /><br/>

<div id=\"start_game\"><input type=\"submit\" name=\"newgame\" value=\"New Game\" onClick=\"newGame()\" /></div>"

Conclusion

Well, that wasn’t so hard now was it? Try the working version to see what it’s like! In this tutorial we took our existing PHP Tic Tac Toe game and modified it to use AJAX. If you play the game you’ll see the page no longer has to refresh each time you click the take turn button or when you hit the new game button. To accomplish this we first downloaded jQuery, created a JavaScript file to make AJAX requests, wrote a file to return a response to our AJAX requests, and then updated our tic tac toe class to use $_GET and our new JavaScript functions.

Advertisements

Pits Of Doom Lesson 7: Join, Login & Lost Password

Comments 16 Standard

In the last lesson we created a database class to make doing queries quick and easy to handle. Then we converted over the current character file and map editor to use the database when storing/retrieving information. Finally, I added an additional file so you could import your map.txt files into your database from any you made in the previous lessons.

Now it’s time to make our game start to feel like a real game. In this lesson we’ll create two new classes, a member’s class and a character’s class. Then we’ll create two new tables, a member’s table and a character’s table. Then we’ll create a join, login and lost password page so members can join, login, and access their own personal account and personal character. Last but not least, we’ll load characters that belong only to the member whose logged in and show those in the game map.

Lesson Concepts

Database Tables

In order to figure out if someone is a member of our game or not we have to store all the information in the database. This way we can pull it out any time someone tries to play the game using PHP. Just like we did with the map tables, we need to plan out the member and character tables. Think of the essential things we need to know about members and characters then draft it out like this:

Members

ID (number) – a unique number assigned to all members

Username (string) – must be at least 3 characters long, no longer then 30
cannot be changed by member

Password (string) – must be at least 5 characters long, no longer then 15
can be changed by member

Use both their username and password to login to the game

Email (string) – so we can send them their account info if they can’t remember it

Last Login (date & time) – we can keep track of the last time they logged in

Online (true or false) – we set this once they login and unset it once they logout

Money (number) – how much money they have in the game, start off with 500G

Current Character (number id of the character) – the character they’re playing right now

Banned (true or false) – if they’re banned we can make sure they can’t login and play

If we think of anything else we can add it later. If you can think of something you want on your game that is specifically for members go ahead and add it here now.

Characters

ID (number) – each character has a unique number

Member ID (number) – the ID of the member this character belongs to

First Name – must be at least 3 letters long, no longer then 15
cannot be changed after being set by member

Last Name – must be at least 5 letters long, no longer then 15
cannot be changed after being set by member

*NO 2 CHARACTERS CAN HAVE THE SAME FIRST & LAST NAME!!

Type (id of a type) – human, dragon, elf, ogre, dwarf, vampire, mage, whatever, we want to add lots of these so it’d be best to make another table and pull in the ID of the type from there.

Monster (true or false) – if this is set to true, the game automatically plays this character otherwise the character will be played by whoever it belongs to (member id).

Money (number) – characters will pickup money as they play

Health (number) – 0 to 100, when a character’s health is 0 they’re dead

Speed (number) – 0 to 100 how fast the character moves

Intelligence (number) – 0 to 100 how smart the character is

Strength (number) – 0 to 100 how powerful the character’s blows are

Agility (number) – 0 to 100 how evasive the character is

Magic (number) – 0 to 100 strength of their magic

Fighting Level (number) – starts at 0, increases after every character they kill above or equal to their fighting level

Magic Level (number) – starts at 0, increases every time they defeat someone using magic of the same or higher magic level

Magic Amount (number) – starts at 100, how much magic they have they can currently used

Weapon Equipped (id of a item) – the weapon in they’re using

Spell Equipped (id of a item) – the spell they’re using

Armor Equipped (id of item) – the armor they’re wearing

Shield Equipped (id of a item) – the shield they’re using

Map (id of a map) – the map they’re currently on

X (number) – their x position on the current map

Y (number) – their y position on the current map

Z (number) – their level on the current map

Active (true or false) – this automatically turns on when the player logs into the game and off when they logout and the character isn’t fighting

Attacking (number) – ID of the character or monster they’re attacking

Character Types

Sometimes you’ll find as you make a game adding an additional table is a HUGE help. In this case, we can easily add as many different character types to the game as we want and set the default range values they should have when they’re created. By giving each random statistics as soon as they’re made, no two will be the same.

ID (number) – a unique ID of the type of character

Name (string) – the name of this character type

To make things easier for monster creation, we can setup the minimum/maximum values each of these types should have when they’re created in the game. For instance, an Elf type would be faster then a Dwarf type.

MinHealth (number)

MaxHealth (number)

MinSpeed (number)

MaxSpeed (number)

MinIntelligence (number)

MaxIntelligence (number)

MinStrength (number)

MaxStrength (number)

MinAgility (number)

MaxAgility (number)

MinMagic (number)

MaxMagic (number)

Now that we have our three tables sketched out we can go ahead and generate the SQL for them. That would look like this:

mysql > CREATE TABLE members (
   id integer NOT NULL AUTO_INCREMENT,
   username varchar(30) NOT NULL,
   password varchar(15) NOT NULL,
   email varchar(50) NOT NULL,
   lastlogin datetime,
   online bool,
   money integer DEFAULT 500,
   curcharacter integer,
   banned bool,
   UNIQUE KEY(id)
);

mysql > CREATE TABLE characters (
   id integer NOT NULL AUTO_INCREMENT,
   memberid integer NOT NULL,
   firstname varchar(15) NOT NULL,
   lastname varchar(15) NOT NULL,
   type integer NOT NULL,
   monster bool NOT NULL,
   money integer NOT NULL,
   health integer NOT NULL,
   speed integer NOT NULL,
   intelligence integer NOT NULL,
   strength integer NOT NULL,
   agility integer NOT NULL,
   magic integer NOT NULL,
   fightlvl integer NOT NULL,
   magiclvl integer NOT NULL,
   magicamount integer NOT NULL,
   weapon integer NOT NULL,
   spell integer NOT NULL,
   armor integer NOT NULL,
   shield integer NOT NULL,
   mapid integer NOT NULL,
   x integer NOT NULL,
   y integer NOT NULL,
   z integer NOT NULL,
   active bool NOT NULL,
   attacking integer NOT NULL,
   UNIQUE KEY(id)
);

mysql > CREATE TABLE character_types (
   id integer NOT NULL AUTO_INCREMENT,
   name varchar(50) NOT NULL,
   minhealth integer NOT NULL,
   maxhealth integer NOT NULL,
   minspeed integer NOT NULL,
   maxspeed integer NOT NULL,
   minintelligence integer NOT NULL,
   maxintelligence integer NOT NULL,
   minstrength integer NOT NULL,
   maxstrength integer NOT NULL,
   minagility integer NOT NULL,
   maxagility integer NOT NULL,
   minmagic integer NOT NULL,
   maxmagic integer NOT NULL,
   UNIQUE KEY(id)
);

Creating The Classes

Now that we have our tables I find it easiest to create classes for them. This way, once we start programming, we don’t even have to worry about any of the database stuff that’s going on in the back end. I find it easier to see the big picture and put the smaller things out of mind as much as possible. So that’s what we’ll do now. In order to use these classes, we must have already established a connection to the database.

For the members class, the easiest thing to do is think of all the things you DO as a member. You join, login, change your password, pick a character to play as, and so forth. These are all things we’ll need to incorporate into our members class. For right now we’ll only do implement the things we need to join, login, and send for a lost password but you’ll see a lot more of this class as the game progresses.

I have several rules of thumb for my classes. I’ve found following these basic tips takes a lot of stress out of making a game:

1) Always comment!! If you look at your code later and don’t understand what’s going on, or why you did what you did, sometimes it takes hours — or days even — to retrace your steps. Give yourself clear cut comments on what a function does and why it does it. No, you don’t have to write a book but you should have enough information there so you can come back later and figure it out in under 5 minutes.

2) Name your class variables the same as your database field names. This may seem like a “duh” kind of comment but there are two reasons this is helpful. First, you’ll know what the field name is when you write queries in a class because all the fields are right at the top of the page. Second, we can do some really nifty database queries and assign the values right back into the variables because they both have the same name.

3) When in doubt think it out. The reason we’re making classes for our game is to help separate things out and join things together (a contradiction, I know!!). Don’t make a class do something do something that seems awkward. For example, the member doesn’t fight a monster, the character does. A character doesn’t have pits or walls, the map does. It wouldn’t make sense to give the member class a fight() function or the character class a hasPit(x, y, z) kind of function.

Member Class

<?php
/**************
* File: memberobj.php
* Purpose: member class
**************/

class member
{

    //these are named exactly the same as in the database
    //to make it easier when we use the $database class later
    var $id;
    var $username;
    var $password;
    var $email;
    var $lastlogin;
    var $online;
    var $money;
    var $curcharacter;
    var $banned;
    var $database;

   //these values are for our database queries
   var $table;
   var $where;

   //these are arrays we keep for this member
   var $characters = array(); //a list of all characters they own
   
   /**************
   * Default constructor, load this member's information
   * Remember, this always has to match the name of the class
   **************/
   function member($id)
   {
    //we need to get access to the database class
    global $_SESSION;

      if (!$id || !isNumeric($id)) //don't try to do any of this if there's no id number
         return null;

      $this->id = $id;
      $this->database = $_SESSION['database'];
      $this->table = "members"; //the name of the table we're using in our database when we
                                //run any queries on members
      $this->where = "WHERE id='$this->id'"; //we always want records from members with this ID

      //now we use the database class we made to pull in all the information about this member
      $this->username = $this->database->select("username", $this->table, $this->where);
      $this->password = $this->database->select("password", $this->table, $this->where);
      $this->email = $this->database->select("email", $this->table, $this->where);
      $this->lastlogin = $this->database->select("lastlogin", $this->table, $this->where);
      $this->online = $this->database->select("online", $this->table, $this->where);
      $this->money = $this->database->select("money", $this->table, $this->where);
      $this->curcharacter = $this->database->select("curcharacter", $this->table, $this->where);
      $this->banned = $this->database->select("banned", $this->table, $this->where);

     //last but not least, we have to load any characters they have
     //this uses a function in the database class I never talked about before
     //it goes through the database and finds the ID number of every character they own
     //then it creates a character object for each of those characters they own and puts
     //them into an array. Finally, it returns that array to the character class so we can
     //view all of the players characters.
     $this->characters = $this->database->loadArray("id", "characters", "WHERE memberid='$this->id'", "character");

     //!!!!! To really get an understanding of what this does, I suggest you uncomment the line
     //below and see what happens. It will print out all the information on each character the
     //member owns.

     //print_r($this->characters);

   } //end default constructor

   /**************
   * The member has supplied the correct login information, log them into the game
   **************/
   function login()
   {

       //remember to update the object value
       $this->lastlogin = time();

       //and the database value for the field
       $this->database->update($this->table, "lastlogin", $this->lastlogin);

       $this->online = true;
       $this->database->update($this->table, "online", $this->online);

       //make all their character's active now that they're online
       $this->database->update("characters", "active=true", "WHERE memberid='$this->id'");
   }

   /**************
   * The member is leaving the game
   **************/
   function logout()
   {

       $this->online = false;
       $this->database->update($this->table, "online", $this->online);

       //make all their character's active now that they're online
       $this->database->update("characters", "active=false", "WHERE memberid='$this->id'");
   }
} //end the members class
?>

Character Class

<?php
/**************
* File: characterobj.php
* Purpose: character class
**************/

class character
{

    //my rule of thumb is, always have variables
    //for every field in your database so you can access them
    //quickly and easily
    var $id;
    var $memberid;
    var $firstname;
    var $lastname;
    var $type;
    var $monster;
    var $money;
    var $health;
    var $speed;
    var $intelligence;
    var $strength;
    var $agility;
    var $magic;
    var $fightlvl;
    var $magiclvl;
    var $magicamount;
    var $weapon;
    var $spell;
    var $armor;
    var $shield;
    var $mapid;
    var $x;
    var $y;
    var $z;
    var $active;
    var $attacking;
    var $database;


   //these values are for our database queries
   var $table;
   var $where;
   
   /**************
   * Default constructor, load this characters's information
   **************/
   function character($id)
   {
    //we need to get access to the database class
    global $_SESSION;

      if (!$id || !isNumeric($id)) //don't try to do any of this if there's no id number
         return null;

      $this->id = $id;
      $this->database = $_SESSION['database'];
      $this->table = "characters";
      $this->where = "WHERE id='$this->id'";

      //now we use the database class we made to pull in all the information about this member
      $this->id = $this->database->select("id", $this->table, $this->where);
      $this->firstname = $this->database->select("firstname", $this->table, $this->where);
      $this->lastname = $this->database->select("lastname", $this->table, $this->where);
      $this->type = $this->database->select("type", $this->table, $this->where);
      $this->monster = $this->database->select("monster", $this->table, $this->where);
      $this->money = $this->database->select("money", $this->table, $this->where);
      $this->health = $this->database->select("health", $this->table, $this->where);
      $this->speed = $this->database->select("speed", $this->table, $this->where);
      $this->intelligence = $this->database->select("intelligence", $this->table, $this->where);
      $this->strength = $this->database->select("strength", $this->table, $this->where);
      $this->agility = $this->database->select("agility", $this->table, $this->where);
      $this->fightlvl = $this->database->select("fightlvl", $this->table, $this->where);
      $this->magiclvl = $this->database->select("magiclvl", $this->table, $this->where);
      $this->magicamount = $this->database->select("magicamount", $this->table, $this->where);
      $this->weapon = $this->database->select("weapon", $this->table, $this->where);
      $this->spell = $this->database->select("spell", $this->table, $this->where);
      $this->armor = $this->database->select("armor", $this->table, $this->where);
      $this->shield = $this->database->select("shield", $this->table, $this->where);
      $this->mapid = $this->database->select("mapid", $this->table, $this->where);
      $this->x = $this->database->select("x", $this->table, $this->where);
      $this->y = $this->database->select("y", $this->table, $this->where);
      $this->z = $this->database->select("z", $this->table, $this->where);
      $this->active = $this->database->select("active", $this->table, $this->where);
      $this->attacking = $this->database->select("attacking", $this->table, $this->where);

   } //end default constructor

   /**************
   * Move around the map (does this look familiar?!?)
   **************/
   function move($direction)
   {

        //we need to get the character's current location
	$newx = $this->x;
	$newy = $this->y;

	switch($direction) //we want to change what we're checking
			   //depending on the direction the character is moving
	{
		case "right": $newy++; //add one to the y value
			break;
		case "left": $newy--; //subtract one from the y value
			break;
		case "back": $newx++; //add one to x value
			break;
		case "forward": $newx--; //subtract one from the x value
			break;
	}

	if (getValue($newx, $newy, $this->mapid, $this->z) == "L")
	{
		//they are currently ON a ladder position
		//if they hit the up direction, move them up a level (if not at level 1)
		if ($direction == "forward" && $this->z != 1)
		{
			echo "You moved up the ladder!";

			//move them up a level
			$this->z = $this->z - 1;

			//set the character's starting position in the map
			$this->x = startPositionX($this->mapid, $this->z);
			$this->y = startPositionY($this->mapid, $this->z);

			//now we save their position to the database so if they log off
			//or leave the game the character is still in this position when
			//they come back and play later
			$this->database->update("character", "x=$this->x, y=$this->y, z=$this->z", $this->where);

		}
		else if ($direction != "back")
		{
				//let them move some other direction
				if (getValue($newx, $newy, $this->mapid, $this->z) == "T")
				{
					//the treasure is in this direction
					echo "You found the treasure!";
					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->z) == "W")
				{
					//don't update their position, they can't move here
					echo "You hit a wall!";
				}

				else if (getValue($newx, $newy, $this->mapid, $this->level) == "E")
				{
					//empty space, move them to this new location
					echo "You moved $direction one space.";

					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->level) == "S")
				{
					//starting location, move them to this new location
					echo "You moved $direction one space.";

					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->level) == "X")
				{
					//they found a pit
					echo "You fell into a pit and dropped down a level!";

					//move them down a level
					$this->z = $this->z + 1;

					$this->x = startPositionX($this->mapid, $this->z);
					$this->y = startPositionY($this->mapid, $this->z);

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y, z=$this->z", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->z) == "L")
				{
					//they found a ladder
					echo "You found a ladder. Move up or down?";

					//move them to the position on the map that has the ladder
					//but don't change which level they're on
					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}
		}

		//if they hit the down direction, move them down a level (if not at level 5)
		if ($direction == "back" && $this->z != 5)
		{
			echo "You moved down the ladder!";

			//move them down a level
			$this->z = $this->z + 1;

			//set the character's starting position in the NEW map
			$this->x = startPositionX($this->mapid, $this->z);
			$this->y = startPositionY($this->mapid, $this->z);

			//update their position
			$this->database->update("character", "x=$this->x, y=$this->y, z=$this->z", $this->where);
		}
		else if ($direction != "forward")
		{
			//let them move some other direction
				if (getValue($newx, $newy, $this->mapid, $this->z) == "T")
				{
					//the treasure is in this direction
					echo "You found the treasure!";

					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);

				}

				else if (getValue($newx, $newy, $this->mapid, $this->level) == "W")
				{
					//don't update their position, they can't move here
					echo "You hit a wall!";
				}

				else if (getValue($newx, $newy, $this->mapid, $this->level) == "E")
				{
					//empty space, move them to this new location
					echo "You moved $direction one space.";
					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->z) == "S")
				{
					//starting location, move them to this new location
					echo "You moved $direction one space.";
					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->z) == "X")
				{
					//they found a pit
					echo "You fell into a pit and dropped down a level!";

					//move them down a level
					$this->z = $this->z + 1;

					$this->x = startPositionX($this->mapid, $this->z);
					$this->y = startPositionY($this->mapid, $this->z);

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y, z=$this->z", $this->where);
				}

				else if (getValue($newx, $newy, $this->mapid, $this->z) == "L")
				{
					//they found a ladder
					echo "You found a ladder. Move up or down?";

					//move them to the position on the map that has the ladder
					//but don't change which level they're on
					$this->x = $newx;
					$this->y = $newy;

					//update their position
					$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
				}
		}
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z) == "T")
	{
		//the treasure is in this direction
		echo "You found the treasure!";

		$this->x = $newx;
		$this->y = $newy;

		//update their position
		$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z) == "W")
	{
		//don't update their position, they can't move here
		echo "You hit a wall!";
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z)== "E")
	{
		//empty space, move them to this new location
		echo "You moved $direction one space.";

		$this->x = $newx;
		$this->y = $newy;

		//update their position
		$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z) == "S")
	{
		//starting location, move them to this new location
		echo "You moved $direction one space.";

		$this->x = $newx;
		$this->y = $newy;

		//update their position
		$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z) == "X")
	{
		//they found a pit
		echo "You fell into a pit and dropped down a level!";

		//move them down a level
		$this->z = $this->z + 1;

		//set the character's starting position in the map
		$this->x = startPositionX($this->mapid, $this->z);
		$this->y = startPositionY($this->mapid, $this->z);

		//update their position
		$this->database->update("character", "x=$this->x, y=$this->y, z=$this->z", $this->where);
	}

	else if (getValue($newx, $newy, $this->mapid, $this->z) == "L")
	{
		//they found a ladder
		echo "You found a ladder. Move up or down?";

		//move them to the position on the map that has the ladder
		//but don't change which level they're on
		$this->x = $newx;
		$this->y = $newy;

		//update their position
		$this->database->update("character", "x=$this->x, y=$this->y", $this->where);
	}

} //end the character class
?>

Character Types Class

<?php
/**************
* File: charactertypeobj.php
* Purpose: character types
**************/

class charactertype
{

    var $id;
    var $name;
    var $minhealth;
    var $maxhealth;
    var $minspeed;
    var $maxspeed;
    var $minintelligence;
    var $maxintelligence;
    var $minstrength;
    var $maxstrength;
    var $minagility;
    var $maxagility;
    var $minmagic;
    var $maxmagic;
    var $database;

   //these values are for our database queries
   var $table;
   var $where;
   
   /**************
   * Default constructor, load character type
   **************/
   function charactertype($id)
   {
    //we need to get access to the database class
    global $_SESSION;

      if (!$id || !isNumeric($id)) //don't try to do any of this if there's no id number
         return null;

      $this->id = $id;
      $this->database = $_SESSION['database'];
      $this->table = "character_types"; //the name of the table we're using in our database when we
                                //run any queries on members
      $this->where = "WHERE id='$this->id'"; //we always want records from members with this ID

      //now we use the database class we made to pull in all the information about this member
      $this->name = $this->database->select("name", $this->table, $this->where);
      $this->minhealth = $this->database->select("minhealth", $this->table, $this->where);
      $this->maxhealth = $this->database->select("maxhealth", $this->table, $this->where);
      $this->minspeed = $this->database->select("minspeed", $this->table, $this->where);
      $this->maxspeed = $this->database->select("maxspeed", $this->table, $this->where);
      $this->minintelligence = $this->database->select("minintelligence", $this->table, $this->where);
      $this->maxintelligence = $this->database->select("maxintelligence", $this->table, $this->where);
      $this->minstrength = $this->database->select("minstrength", $this->table, $this->where);
      $this->maxstrength = $this->database->select("maxstrength", $this->table, $this->where);
      $this->minagility = $this->database->select("minagility", $this->table, $this->where);
      $this->maxagility = $this->database->select("maxagility", $this->table, $this->where);
      $this->minmagic = $this->database->select("minmagic", $this->table, $this->where);
      $this->maxmagic = $this->database->select("maxmagic", $this->table, $this->where);

   } //end default constructor

} //end the character type class
?>

Join Script

We don’t want just anyone to be able to access characters and maps in the game, they should only see things that belong to them. In order to do this we’ll have them make an account in our database and automatically create a character for them to start playing with. When we do this we’ll generate random statistics for the character based on the data we have in our character types data.

Lost Password Script

It’s inevitable, eventually you’ll forget the information you entered when you joined the site. Creating a lost password script will remedy this situation. Now your members can have their login & password sent directly to their email address instead of bogging down your inbox with pointless password requests!

Login Script

Time to verify, are you who you say you are? The biggest downfall of a login is that anyone who has the correct login/password combination will be able to access the information for the account, but that’s something we’ve come to accept as unavoidable with online account security. However, we can make things as secure as possible by only allowing members who have logged in to view certain parts of the website. We’ll enhance that even further by only giving them access to records they own or created themselves.

$database = & new database($host, $username, $password, $db);

if ($_POST['submit'])
{

	//check to see if this login is in the members table
	//by retrieving their member id if their username and password matches
	$id = $database->single("id", "members", "WHERE username='" . $_POST['username'] . "' AND
							password='" . $_POST['password'] . "'");

	//we found the member, let's create a session with this member's information
	if ($id)
	{
		$_SESSION['database'] = $database;
		$_SESSION['member'] = & new member($id);

		//log them into the game
		$_SESSION['member']->login();

		//now let's redirect them to the map and their character
		header("Location: character_v6.php");
		exit;
	}

	//we didn't find the login, we won't let them login
	$error = errorMsg("Incorrect login information");
}

The logic behind this script is fairly straightforward. First we connect to the database, then if they’ve hit the submit button we pass the username and password they entered into the form to our member object. If we find a member ID that matches that information we give them access to the game by storing the member object into a session. Otherwise their login information was incorrect and they need to try again.

Summary

Try the working version! In this lesson we added a huge backbone to what is going to quickly become a working, running game. Now we’ve restricted access to the map view to people who have logged in. In order to be logged in you must have an account in our database — thus we created a join script people can use to create a default character and setup their own unique login and password. Finally, to top it off, we made a lost password form so anyone who forgets their login information can have it emailed to them.

Game Files

Working Version:

Pits of Doom, use the login below or sign up and create your own account!

Login: test

Password: test

Source Files:

Class Files:

classfiles.php
functions.php

Object Files:

mysqlobj.php
memberobj.php
characterobj.php
charactertypeobj.php

Game Files

login.php
join.php
lostpassword.php
character.php

SQL Data:

pitsofdoom.sql — includes character types and default map

Lesson Reasoning

This lessons is all about planning out the underlying structure of members and characters and how they interact with the game map. Each member can have multiple characters. In order to do that we have to prompt the user for their login information: this way we can verify they are who they say they are. Once we know who the member is, we load all the information from the database about the characters they have. Finally, we display their character’s information in the map depending on the information we have about the character in our database.

In the next lesson we’ll create a way for members to create their own characters, instead of automatically creating one for them when they join. We’ll also start working on monsters (!!!!) and letting character’s battle them in the map.

Go Back to Lesson 6 or Continue to Lesson 8

Pits of Doom Lesson 6: MySQL Database Class

Comment 1 Standard

In the last lesson I introduced you to functions, reading & writing to a file, some simple javascript and adding features to the game so we could swap in/out maps and move up/down map levels. Now this is all fine and dandy, but we live in the age of databases so it’s time to pull out your thinking caps. Let’s get busy converting everything we’ve done so far to a database.

Lesson Concepts

MySQL Basics

There are several big database software companies out there but I’m a particular fan on MySQL (especially since it’s free…). SQL is a standardized query language that’s not so standard. Most of the basic operations and ideas are available in the different kinds of database software but not all of them. All the SQL here will is put together assuming your using MySQL 4.0 or later.

So, what is a database? If you think you’ve never used a database before you’re wrong. Are you online right now reading this post?? Guess what, you’re reading information from a database. You can be almost 90% certain most any big website you visit they use a database for their online content.

What to compare it to? If you’ve ever used Microsoft Excel or Microsoft Access you have a step up in the basics I’m going to teach you. So, here it is.

Terminology – Database, Tables, Rows, Columns & Keys

A lot of people get confused with some of these terms so I’m going to go over them before I start officially using them.

Database – this can refer to two things. People often use it to refer to the database software (MySQL, Oracle) but it also refers to a repository, or large collection of data that consists of several tables. When I use the term database I am referring to the large collection of data, not to the actual software. If I want to refer to the software, I’ll call it by it’s name: MySQL. Think of a database as a workbook in Excel, where it contains multiple spreadsheets yet they’re all a part of the same file.

Table – a database consists of many tables. Tables help you gather similar data together, form relationships, and setup constraints/limits to the data you insert into it. In this lesson we’ll be creating and working with several tables that make up all of our map data. Think of tables as a single spreadsheet in excel.

Row – a row is a horizontal line of data in a table.

Column – a column is a vertical line of data in a table.

Keys – in SQL things are identified by keys. Think of a key as a way to distinguish one record from another. In the United States everyone has a unique social security number, that way the government can distinguish one John Smith from another. Sometimes keys can be made up of multiple things. For instance, if you knew one John Smith lived in Florida and the other lived in New Jersey you’d be able to tell the two apart. Keys can work the same way. Falling back on my earlier excel references, think of a Key as one of the column or row headers on the spreadsheet file (A-Z at across the top and down the side).

Creating A Database

For the sake of learning I’m going to walk you through some basic SQL before I introduce combine PHP into the mix. The first thing we need to do is make a database for Pits of Doom. To help you distinguish between when I’m writing SQL code versus PHP code I’m going to precede all my SQL statements with mysql> like you’d see the mysql command prompt screen.

mysql> CREATE DATABASE pitsofdoom

A lot less painful looking thing you thought it would be huh? Most people have a general rule with SQL where they capitalize SQL command words and put their own text in lowercase letters. I believe in some database software the capitalization is required, but it’s not required for MySQL. Choose whichever way you prefer.

Creating A Table

This is nearly as easy as creating a database with a few exceptions. When we create a table we have to give it all the row values we’ll be using and a type for each of those values. However, before we do that we’ll need to think about the design of these tables, the game map tables.

Let’s think about it this way:

Each map has 1 name and multiple levels — we’ll need to know what’s the deepest level you can go in each map.

Each map has lots of data for each level — it’s probably a good idea to separate this data from the map name and level data because there’s so much of it. Also, since we have so much map data we don’t want to repeat things like the map name over and over again (we don’t really need to know the map name more then once)

So, the maps in our game should have at least two tables. One table with the map name and level, the other table with all the data for that particular map. If we draw out a rough sketch of our tables they’d look like this:

Table Name: Map

Fields:

ID: a unique number for this map (number)

Name: the name of this map (string)

MaxDepth: the maximum depth level for this map (number)

Table Name: MapData

Fields:

Id: a unique number for this map data information (number)

MapId: the id of the map this data belongs to (number)

X: the x coordinate for this map value (number)

Y: the y coordinate for this map value (number)

Z: the depth of this place on the map (number)

Value: the value of the field in the map ie X, T, W, E (single character)

Now that we have our tables laid out we’ll convert them into SQL.

mysql> CREATE TABLE map (       id integer NOT NULL AUTO_INCREMENT,       name varchar(100) NOT NULL,       maxdepth integer NOT NULL,       UNIQUE KEY(id))

In this first table we’ve created our map information. We’ve set it up so the ID number must be unique, and so that it’ll automatically increment for us as we add records (so we don’t have to do that ourselves!). You’ll notice anything we wanted to put a number into has a type of INTEGER. Anything we wanted to put text into has the type of VARCHAR and then we specified the maximum number of characters for that field. So in this case the name of our map can’t be more then 100 character’s long.

A visual representation of the table we made would look something like this:

ID Name MaxDepth

These three fields combined make up our map table. Now let’s make our map data table:

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))

Visually, this would look something like this:

ID MapID X Y Z Value

All of these fields combined make up the mapdata table. However, our tables need a lot more information then just the columns for the data we’re going to add. Let’s see what it would look like visually if we added some information from the map we made for Round Hill.

ID Name MaxDepth
1 Round Hill 5

The first map in our game starts out with the ID number 1. If you remember, we setup our map table to auto-increment the ID field. That means it will always add 1 to the value of the ID number. The max depth of the first entry in our table is 5 because there are five levels in our map. Now let’s see what our map data table would look like with some of the first level’s information inserted into it:

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

Does any of this look familiar? It should! This is the information from the first level of the map for Round Hill. It’s actually the first two top rows in the map file we exported. This brings us to our next topic, how in the heck do you add this information to the database using MySQL?

Inserting Values Into A Table

First, let’s try to insert the map information for Round Hill into our map table:

mysql > INSERT INTO map (name, maxdepth) VALUES ('Round Hill', '5')

The insert statement in SQL is comprised of the table you want to insert into, the fields you’re inserting data into, and then the data. The sequence of the data should match the order of the column names you put in. So if we reversed our values to ‘5’, ‘Round Hill’ we’d end up with an error when we tried to insert the text value Round Hill into a number value.

Now let’s insert some of our map information into the mapdata table.

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')

In this case, I’ve actually inserted three rows using one insert statement. Each entry is surrounded by parenthesis. When you insert something, you can use either of these formats, whichever works best for you.

Selecting Values From A Table

Once you have data in a table of your database you’re ready to start working with it. Let’s pretend we a table called members with the following data in it:

ID Name Username Password Email Show_Email
1 Jade Krafsig JadenDreamer ilovehorses jade@design1online.com Y
2 John Doe Jdoe imadope jdoe@gmail.com N
3 Jane Doe Jdoe howdy jane.doe@gmail.com N

We have three members in our database. Let’s pretend John Doe is trying to login using his email address and password. Before we can let him access any member’s only area we need to verify that this username and password are correct, then figure out what his show email status is.

mysql > SELECT id, name, show_email FROM members WHERE email='jdoe@gmail.com' AND password='imadope'

The select statement is broken into several parts, only a few of the basics which I’m going to show you right now. After the word SELECT, you list the name of the columns you want to view. After the word FROM you list the name of the table. The WHERE section is pretty self explanatory. If we ran this query we would get back the following table:

ID Name Show_Email
2 John Doe N

One thing to notice right off the bat, when we select something we always get back a TABLE. That means we can get more then one row of data from a select statement. For instance, take this query:

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

In this example, we used an asterisk to tell MySQL we want all the column fields in the table where members have a username that equals Jdoe. Now you have multiple records returned. Take a look at some of the queries below, can you figure out what table would be generated if you ran them?

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

Think you’ve figured them out? Good! Let’s go over them. The first one finds all members who have the show_email field set to N. The second one selects all columns where the email address is one value OR where the email address is another value. The third query will select everything in the entire database, as will the query after it. The next query shows all the usernames and passwords where the username field and the password field don’t have the same values in them, and the last query finds all members with an ID greater than or equal to the number 2.

Updating Values In A Table

Data doesn’t usually stay static, especially data for a multiplayer online game. People change passwords, write messages, go on quests, and more. In order for the game to reflect that we’ll need to update the data as people play. That’s were update statements come in. Let’s use the same members table we had before. Pretend that John Doe has logged into his account and wants to change his email address:

mysql > UPDATE members SET email='john.doe@gmail.com'

If you realized immediately that this will cause a problem you’ve got the right mindset. If you didn’t notice an error right away look again. Computers are really dumb, they do exactly what you tell them to. If you ran this query, you would change everyone’s password in the game to John Doe’s new email address. What a disaster!

This is where keys become important. In order to identify which record in our database belongs to John and only change data for information that belongs to John we can use the key for our member’s table: ID.

mysql > UPDATE members SET email='john.doe@gmail.com' WHERE id='2'

When we run this query only the email address for John is affected. Perfect!

Update statements can be as easy and as complicated as you want. We could update every other row by figuring out if the id number was odd or even, we could change passwords according to the show_email field, and more. However you have to be careful with update statements. What happens if we did this:

mysql > UPDATE members SET password='heya', email='john.doe@gmail.com' WHERE username='jdoe'

Now we run into the problem of changing multiple records again. In our members table both John and Jane Doe use the same username. If we ran this query, we’d reset both of their passwords to heya and both their email addresses to john.doe@gmail.com.

Take a look at some of these other update queries. Can you figure out what they’d do?

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'

The first query sets all member’s passwords to test if their ID number is less than 1. The second query sets both the username and password for all members whose email matches AND have the username John. The third and final query fails, there is no column called showing_emails. If it instead said show_email it would set everyone’s show_email value to Y.

Deleting Values From A Table

Taking things out of your database is sometimes almost as important as putting things in. I run pretty small servers with a lot of active people who play. In order to make queries faster I delete old data. There are other reasons to delete data as well and I’m sure you can think of a few.

So you know, there is no way to delete a certain field in one file. Deletion in mysql is an all or nothing, it either removes the whole row or it doesn’t.

mysql > DELETE FROM members WHERE id='3'

This removes Jane Doe from the members database. Again, you can end up with the same problems deleting as you did updating. Pay careful attention to any delete statement so you don’t delete everything in your database!

MySQL & PHP Working Together

In order to access our database information from mysql in our php files we have to open a connection to the database. I usually make this a file called dbconnect.php and include it at the top of every page I need database access to. Your file will vary based on the username, password, and name of the database you’re using so you’ll need to change this file to work for you:

<?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());
?>

The first function mysql_connect starts the connection to the database. If you’re using a database that’s local to where you host your website then the words localhost will never change. The or die statement at the end of the function is a great way to help you debug your mysql/php code. If something goes wrong while mysql is trying to connect it’ll automatically give you a fairly descriptive error message about the problem.

The second function mysql_select_db switches to the database you’ll be using. Often times you have multiple databases on the same server. For instance, I have two servers. On each server I have anywhere from 2-15 databases. When I run a PHP script, it needs to know which of those databases I’m using before it can try to access any of my tables.

Now you’ve seen two of the great functions PHP has built in to make it easy working with MySQL. Since we can connect to our database let’s start performing operations on it.

<?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’];

?>

This prints, Hello Jade! Your member ID number is: 1

I’m not sure about you but I think that’s totally awesome. But in this example we need to know someone’s ID number before we display information about them. What happens if we want to change that based on a number someone’s entered into a text field? Take a look at this next example:

<?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>

In this example our page now pulls the correct information about whichever member’s ID number you enter. Now this works fine if someone uses a number and its less then 4, but what happens if they enter something else? Can you fix this so it only displays information about the member if the number is valid? Here’s two hints, you can use the function isNumeric($number) to find out if what someone entered is a number, then you should can check to see if the value returned by $row[‘field_name’] has data in it.

Let’s display a list of all of our members. How do we do that? Take a look at this code:

<?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/>”;

}
?>

This goes through and echo’s the ID number and name of every member in our database as long as $row has a value. That means as soon as we no longer have any results returned from our table the loop will stop automatically.

There’s one more thing you need to know before we go on to making an SQL class, and that’s how to update a row.

<?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>

In this example we have only one major difference. With the mysql update or delete statement, you don’t need a variable in front of it. Either the update works, or fails. Either a delete works or fails. There’s nothing to store for later use.

Whooo!! Now we’re ready to combine the two skill sets for our game. Instead of writing tons of queries all over the place we’re going to create a SQL class to help us out. It’ll do a ton of the work for us so we can focus on the bigger picture.

Class Basics

A class is a good way to abstract lots of smaller details from a bigger picture. We’re going to create a simple vending machine class. Everyone has used a vending machine before so it’s a great example.

There are lots of different parts that make up a vending machine, but all combined together we only think of the vending machine as one object. A class uses the same kind of idea, lots of smaller parts making a bigger object. Let’s think about fruit:

Fruit Class

Multiple Types of Fruit

But all have common characteristics:

Name

Color

Size (small, medium, large, and extra-large)

Sweet (yes or no)

We can take several actions with fruit:

Wash

Eat

Shine

Take over the world — just kidding

Using this really simple break down, let’s make a fruit class:

<?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();

?>

Try running this script. What happens? One of the neatest things about a class is that all of the functions you make inside of a class can be applied to any object of that class. In the example above we had three different fruit objects. Even though they were all different variables they all used the same functions of the fruit class in a different way. You’ll also notice we can access the variables we made in the class using the -> arrow. Try adding more functions to this class. Try making $veggie = $fruit. What happens when you do $veggie->name now? Try adding a function to the class that lets you set all properties (color, sweet, size) at the same time.

Creating A MySQL Class

So, here goes nothing:

<?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/>";}?>

I know everything’s not color coded but this is such a big class it’ll take me forever. So the short of it is we can use this class to do everything we need to do with our database. Take a look at this test file I made to see if the class was working. Try creating a table named attributes with an ID number and a name. Enter a few values into the table, then run this script:

<?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!";?>

What happens when you view this page? Can you see how it’s effecting things in the database? Great!! Now we’re ready to convert everything over to a database in our game.

Converting Everything Over

There is no cut and paste way to convert what we’ve done so far to use the database. My advice to you is to approach it however you most feel comfortable. Personally, the way I’d approach it would be to start with the map editor so once it’s converted over you’ll have maps in the database to fix the character page.

Once someone goes to save a map we need to:

  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!

With our character page we only have to do one thing:

1. Change the loadMap function to load data from the database

Summary

There is a lot to digest in this lesson. Don’t worry if it all doesn’t make sense. Try making a database and playing around with it, add things, delete things and update things using SQL or the database class I provided above. Once you feel confident there try assigning database values into variables, make a small form to update values in the database. Then once you’re tired of that move on to converting the character.php and mapeditor.php files to use the database.

If you get stuck there’s nothing to worry about! All the working code is below. Enjoy.

Game Files

Working Version:

Character File: character.php

Map Editor: mapeditor.php
I’ve left it so you can actually add maps to the database so PLEASE RESPECT MY DATABASE!! Thank you 🙂

Source Files:

Character File: character.php

Map Editor: mapeditor.php

Database Tables: database.sql (map file data included)

Database Tables: database_empty.sql (no map data included)

Map File Database Importer: mapfile_importer.php
this will import the map files we made before right into your database!!

Mysql Database Class: mysqlobj.php

Functions: functions.php

Lesson Reasoning

Now we’ve taken our simple 1-click button game and turned it into a decently functional database driven game!! Not only can we create maps with our map editor and store them directly into the database, we can move up and down levels in a map, use ladders, fall into pits, and make sure we don’t run into walls.

But our game is far from complete. In the next lesson we’ll discuss creating a member class and a character class and how they interact between each other. Then we’ll create a members table and a character table in our database. Finally we’ll write a login script so only members with a character can access our simple game map and play it.

Return to Lesson 5 or Continue to Lesson 7

Pits of Doom Lesson 5: Easy Map Editor

Comments 3 Standard

In the last lesson we made some real progress. Now, instead of having a boring page with a click of one button before the game is over, we have a character that can move around a much larger area, be blocked by walls, fall into pits and die, and then win if they find the treasure.

That’s all fine and dandy but our game needs more substance. It’s time to add more maps, map levels, and our very own easy map editor so we can quickly make maps, generate map files, and play our game with a whole new level of complexity.

Lesson Concepts

Including Files

One of the best things about programming is being able to break bigger, more complex problems down into smaller more manageable pieces. Include files are one way to do that. Let’s take our custom function we wrote last lesson to display the map on the screen. Did you notice that our character.php file is becoming a bit crowded and hard to read? Wouldn’t it be nice if we could take the displayMap() function out off of the code in that page but still use it on there?

That’s what an include file does. Using an include file is easy. First you create a new file. I like to call files where I keep a lot of functions something really generic: functions.php. That way when you go back looking for things later and you find a function being used that’s not in the file you have a good idea of where to check to find it.

The next thing you do is put some code inside of functions.php. In our case, the display map function. So all we do is cut/paste the function from our character.php file to the functions.php file.

Last but not least, we go back to character.php and at the top of the page we write:

<?php

session_start();
include(‘functions.php’);

//rest of the code here like normal….

?>

What does this do? It literally takes the contents of the functions.php file and dumps it onto the character.php page. That way any piece of code you have inside of functions.php is now accessible to the page just like if we’d written the displayMap() function directly inside the character.php page. How neat is that?

I’m sure you can already see the benefits of doing this like this. It makes everything much easier to read.

Question: When is it a good time to make a function?

Functions are great things. My rule of thumb is, if you have a piece of code, or even some kind of page formatting that you plan on using again and again, make it into a function. That way, instead of having to type the same thing over and over and over again all you do is call your function and pass it unique parameters.

Take our character movement for example. Every time someone clicks on a button we have to check to see which button they pressed, what’s in the direction they’re moving, and how to respond to what’s in that direction. Do you notice the similarities in the code for EVERY direction?? If you run into situations like this, it’s a good time to stop and think function.

Give it a try! Can you convert the character movement into a function? Here’s a hint: Every time the player moves all you really need to know is what direction it’s moving in. Then, according to that direction, you can check the x and y values of the map to see what’s there.

Automatic File Downloads

In this lesson we’re creating a map editor we can use to create map files fairly quickly. In our map editor, we want to take the map file we created and automatically download it, or export it, once we’re done. In order to do that you’ll need to know some information about files and http headers. Despite how hard these seems like it should be, it’s only a few lines of code.

Let’s talk about HTTP headers. HTTP is Hypertext Transfer Protocol, or one way we use to view files online. You may be familiar with other things like FTP, file transfer protocol or TCP/IP, Transfer Control Protocol/Internet Protocol. But we’re only concerned about the one.

Every time you request a file from someplace on the internet a lot of different things go on. If you’re interested in how everything works I highly suggest going to wikipedia’s networking section. However, the more important thing you need to know is that for any file you view online, it starts with header information that describes the type of file it is, the length of the file, and the content of the file.

PHP, since it’s a server side programming language, can be used to setup the headers on any file you create before someone else sees the file online. In this way, we can use PHP to tell the browser anything we write on a HTML file should be treated like it’s a music file, or an application, a PDF, or a text file. Whatever we want!

Create a file and call it testdownload.php. Now put this in it:

<?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 :)”;

?>

That’s it! See, with only a few lines of code you can create a file that automatically downloads anything you echo on the page with the name, and extension you want it to have. We can use this concept with our map editor, to echo all the options someone selects to the page after we’ve set the headers and create automatically downloads for the map files.

Reading From A File

Reading from a file is a bit trickier. Instead of going over the concept I’m going to put the actual code I wrote specifically for the map editor I made with a ton of comments explaining what I’ve done and why. Please note that I wrote this file reader for the format generated by the map editor. It probably won’t work for any map file you’ve made yourself so you’ll need to re-create it using the map editor first.

Another thing I’ll warn you about. I keep my map files in another directory called maps. If you keep your map files in a different location you’ll need to change the $directory variable to reflect that. If you keep the map files in the same place as the game and map editor files then uncomment the first $directory line and comment out the second $directory line.

<?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!";
}

?>

This function does three major things. First, it checks to see if the file exists and if it doesn’t it gives us an error message. Otherwise it opens the file, searches through it until if finds the first line of the map. We know when we find the first line of the map because it’ll be a W character, the wall that runs all around the outside of the map. Once it finds a line in the file from the map it inserts it into the array and increments the array variables by 1. That way each row and column of the map are read in until it doesn’t find any more.

We know that we’ve reached the end of a line (or the end of a row in the map) when we reach a \n character. This is the same thing as a carriage return in the file, or an end of line character. This tells us there’s nothing else left to read on the line, so we increment the array to start reading from the next row.

If this seems like it’s a bit out of your understanding don’t worry. This is actually much easier to do when you’re reading or inserting values into a database that we’ll cover next lesson.

Some Simple Javascript

I know I said I wouldn’t go into AJAX and Javascript but in creating the map editor I realized it would be easier to use visually if I added some Javascript for automatic color coding. So I’ll go over both functions I wrote and how they work below.

Javascript starts with different tags then what you see in PHP but it has both a start and end tag.

<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>

The very first function is simple. It takes the color of the option in the select box and changes the select box to match that color.

The second function is a little more complicated. When we call it we pass it a form, or all of the things between the <form> and </form> tags in our map editor file. This includes all of the select boxes we’re using to let you create the map. Then it goes through all of those select boxes and calls the setColor function.

The reason we use this second function has to do with first loading the editor. The first time the editor is loaded we run a PHP script so that the borders of the map are automatically walls. When we do this, we still want to update the color of the walls we set. That’s what the resetColors function is for, it goes through every select box on the page and sets it to the appropriate color. You’ll notice when you first start the editor it appears with all white select boxes after a few seconds the borders of the map changes to gray. That change is caused by the javascript call to reset the colors. Try removing the resetColors call from the map editor. Do you see the difference when you try to run it now?

Pits of Doom Map Editor

I know I haven’t done this before, but I feel like we’re at a point where more explanation is necessary. Now I’m going to talk about the map editor, some of it’s features, and how you use it.

The map editor is a great, useful tool we can use to build this game quickly and efficiently. It has three major features to it. The first page you see when you open it is setting up the name and the level of the map. If you’re making multiple levels on the same map then they all need the same name. Then you can enter a width and height for the map. I suggest using a size 15 x 15 or smaller, otherwise you’ll have to do a lot of back and forth scrolling, but any size you pick will work.

Once you’ve filled out the map details click on the start map editor. The screen you’ll see next has several neat features.

  • To help make building a map faster, all the edges are automatically turned into a wall. For the sake of the map file loader make sure you always have walls around the edge of your map.
  • The map editor is also color coded, to make everything more visually pleasing.
  • S is the starting position of the character. You can have more then one, but the files I’ve included always pick the starting position closest to the top of the board. If you’d like to add in functionality to randomly pick the starting position by all means go ahead.
  • An addition to the map editor is the L, or ladder. Ladders will allow the character to move up or down a level if they land on one. A character cannot move up a level if they’re on the top map level, or level 1. In the other direction, a character cannot move down a level if they’re on the bottom level of the map. Right now we’ll assume all maps have 5 levels.
  • The last (and best) function of the map editor is the export file button. This lets you automatically download your map as a .txt file. Then you can use these .txt files to load maps into your game and play them!

Ladders, Pits & Level Changes

In this version of Pits of Doom we need to add the functionality of moving up and down ladders and falling down pits. The easiest thing to do first is create a function for all of our movement in the game.

Once you’ve done that, we need to make our $_SESSION variable global to our function. That means the function can access the values we already have inside of the $_SESSION variable. By setting the map name and level in a session we’ll always know which map we’re on and which level we’re on. If we apply this same concept to the map array values, we’ll always know what’s in the map once we’ve loaded it.

Any time we’re on a pit we now need to change the level the character is on so they fall down a level (unless they’re not on the last level of the map!). To make things easier for ourselves, we’ll make sure the map at level 5 doesn’t have any pits in it.

Once the character’s level has been dropped to the map file below, we load the map for that new level. Before the character can start playing this level again we need to find the starting position on this new map. To do that I’ve written two simple functions:

<?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;
}

?>

One of these finds the X position of the starting position and the other finds the Y position. Using these we can reset the character’s default position on the new map we loaded. Note that height and width are additional functions I’ve written to find the height and width of the two-dimensional array.

Ladders use a similar concept with one difference. If someone is on a ladder they now have the option of moving up or down instead. To do that, I’ve written a special if statement for ladders. When someone is on a ladder they can use the up and down buttons to move up or down the ladder instead of moving backwards or forwards on the map. If the character is on the bottom level, we allow them to move back instead of moving down the ladder, and if they’re on the top level we let them move forward instead of moving up a level.

Summary

Our game is really coming along! I’m quite pleased with what I have right now. Not only can I move up and down ladders, fall into pits, and find the treasure, I’m having fun doing it. Right now I feel like we have a really solid foundation for how character movement is going to work. I think it’s time to take things to a new level of complexity by adding in the database.

Game Files

Working Version:

character.php

mapeditor.php

Source Code:

character.txt

functions.txt

mapeditor.txt

mapsymbols.txt

Map Files

Round Hill_1.txt

Round Hill_2.txt

Round Hill_3.txt

Round Hill_4.txt

Round Hill_5.txt

Try it Yourself:

character.php

functions.php

Lesson Reasoning

In this lesson we’re really starting to tie a lot more things together. Now we know how to load a map from an outside data source and swap those maps as they get to certain points on the map. We now have a fairly decent skeleton of what our map/character movement functionality is going to be like once the game is finished.

But this still isn’t what we want!! We need everything to be done from the database, loaded and ready to go so we can change it as and how we see fit. In our next lesson we’ll work on an introduction to SQL, setting up and connecting to a database, creating tables, and changing over everything we’ve done so far (including our easy map editor) to pull from and save to the database.

Look at that! Only 5 lessons and we’re already moving on to interacting with a database.

Return to Lesson 4 or Continue to Lesson 6

Pits of Doom Lesson 4: And Array We Go

Comment 1 Standard

In the last lesson we covered how to create a function, how to use some of php’s built in functions, and how to deal with sessions. Now we’ll take it even a step further.

If you’ve tried the little game we have setup right now you’ll agree with me that’s its not only boring, it’s really REALLY boring. Right now you can click one button and either win or loose the game. In the big scheme of things we want our character to walk around different maps, moving from place to place as well as fighting or falling into pits before they die.

But frankly you’re not at that point yet. So again we’ll take a step back and go at from an easier approach — letting the character move around a larger area before they run into the possibility of either finding the treasure or falling into a pit. So let’s say we have a map like this:

Map Name: Tutorial Map

Map Level: 1 (lower numbers are closer to the surface, higher numbers are deeper down)

W    W    W    W    W    W    W
W    S    E    E    E    E    W
W    W    E    X    E    E    W
W    E    E    E    T    X    W
W    W    W    W    W    W    W

S marks the starting place of our character on the map. The number E is an empty space, meaning the character can move there. The number W is a wall, the character can’t move onto that spot. X is a pit and T is our treasure. Now we already have a much more interesting game already. In order to give our character more movement we can use a database or an array. Since a database is in a way a really huge array we’re going to start with an array so you don’t have to worry about all the finicky problems that pop up with the database and then move on to the database later.

Lesson Concepts

Arrays

In short an array is a way to hold lots information at one place. There are two types of arrays, single dimension arrays and multi-dimension arrays. We’ll cover single dimensional arrays first.

The easiest way to think of an array is a list of items. The list always starts at zero and grows up in it’s number. Let’s take a look at a simple array I’ve made called path. In each of the fields in the path I’ve stored information about what kind of item you might find there (treasure, walls or empty spaces)

<?php

$path[0] = “S”;
$path[1] = “E”;
$path[2] = “E”;
$path[3] = “E”;
$path[4] = “W”;

?>

As you can see, out path has a starting position of a character, three empty spaces, and then a wall. If we were to try and build any kind of character movement using this array it would be pretty difficult. The character would start at position zero, be able to move up to 3 spaces forward, and then get stuck when it hits the wall at position 4. The only other option this character would have would be to turn around and go back to it’s starting position. How boring would something like this be? We want our character to be able to move in multiple directions, not just forward and back. That’s where multi-dimensional arrays come in. Take a look at this…

<?php

$path[0][0] = “W”; $path[0][1] = “W”; $path[0][2] = “W”; $path[0][3] = “W”;

$path[1][0] = “W”; $path[1][1] = “S”; $path[1][2] = “E”; $path[1][3] = “W”;

$path[2][0] = “W”; $path[2][1] = “E”; $path[2][2] = “E”; $path[1][3] = “W”;

$path[3][0] = “W”; $path[3][1] = “E”; $path[3][2] = “T”; $path[3][3] = “W”;

$path[4][0] = “W”; $path[4][1] = “W”; $path[4][2] = “W”; $path[4][3] = “W”;

?>

Does this look familiar? Good! It should! This is a multi-dimensional array. I’ve tried to write it out so it looks similar to the map we have planned out above, only this is a much smaller version. With a multi-dimensional array you can store more then 1 coordinate at a time. Now we can have a left and a right direction along with an up and a down.

In the multi-dimensional array our character starts out where we’ve marked it with an S, at (1,1). This notation (1,1) is what we’ll call a coordinate. It notes the x and y location (x,y) of the character.

If this character were to move up, we’d subtract one from the x coordinate. If they want to move down we add 1 to the x coordinate. If they want to move left or right, we add or subtract one to the y coordinate. Now what happens if the character starts at (1,1) and they move to the right? They are given the position (1,(1+1)) or (1,2). Scroll back up and look at the array. Is there a free space at (1,2)? If there is, then we’d want to allow this move. If there’s a wall in position (1,2) then we’d give the character an error message.

Now it’s your turn to try. Write out the coordinates you’d need to get from the character’s starting position to the treasure. There are actually several ways to do it, can you find more then one way?

Once we have a larger array we have to always test both coordinates when the character moves from place to place, otherwise we won’t be pulling accurate information from the maze. Here’s how you’d test to see what value is in an array at a certain position.

<?php

$x = 0; //first coordinate

$y = 0; //second coordinate

echo $path[$x][$y]; //now we show the value of the path for the given coordinates

?>

I’m sure you can see where this is going. You can test an array for a value just like you can test any other variable.

<?php

$x = 0;

$y = 0;

if ($path[$x][$y] == “E“)

{

echoYou’re on an empty space!“;

}

else if ($path[$x][$y] == “W“)

{

echoHow did you get stuck in a wall?!?“;

}

?>

That’s it! Seems pretty easy doesn’t it?

Summary

In this lesson we covered single and multi-dimensional arrays. In order to complete this lesson you’ll need to know how to assign values to a multi-dimensional array, access the values in the array, display the values in an array, and then write if-else statements to respond differently based on what’s in the given position in the array.

To make this lesson easier I’ve included a custom function that draws the map to the screen and shows you the character’s position as it moves around. The character is drawn in red until you find the treasure, then it turns green!

Game Files

Working Version: character.php — we have enough of a functioning game that you can start playing it for yourself!

Source Code: character.txt

Try it yourself: character2.txt

Lesson Reasoning

This lesson helps us work up to getting character movement based off of values from another data source. Right now we’re using data we’ve entered ourselves, but pretty soon we’ll be pulling this information from our database. This is only one level below reading from a database and it’ll help you understand character movement on a baser level before we add the complication that is SQL.

Now comes the question, can we change the map as we play? Let’s say, instead of the game being over when the character finds the treasure, we instead want them to move onto a new map. Sounds easy, but the more maps you have the more difficult this becomes!

And did you notice how much time it took to make your own custom map? Pff, we don’t want to do that for all the levels in the game. We need something much faster and more powerful, which brings us to the next lesson.

In the next lesson you’ll learn how to dynamically load different map files into the map array from a file instead of having to have it typed on the character’s page. That way we can relocate the character to another map once they’ve found the treasure. Also, we’ll create a map editor so we can quickly and easily make map files.

Once we have those two things done we’ll be ready to move on to putting all the character movement into a database table, creating maps and saving them directly to the database, and letting our character move up and down in the map levels using ladders.

Return to Lesson 3 or you can Go to Lesson 5

Pits of Doom Lesson 3: Mixing Things Up

Comments 3 Standard

In the last lesson we covered how to make a form, check to see if a button has been pressed, and display a message according to whether the user found the treasure or not. Now it’s time to take our very simple navigation page to the next level: random treasure location.

In our final game, the position of the treasure will be pre-determined by data in our database. However, we won’t know what position the treasure is in as the user is navigating their character around the game because this information will be loaded as they play.

In our next lesson we’re going to apply a more advanced concept to figuring out if the treasure is in the correct location. Instead of always knowing where the treasure is, we’re going to make the treasure start in a random direction each time the page is loaded. That way we have to check every time to figure out where the treasure is, and if the player will fall into a pit or not.

Lesson Concepts

Functions

In programming, a function is a great way to break bigger tasks into smaller more manageable pieces, or reduce the need of having to write the same piece of code over and over again. In PHP the syntax for a function is very simple:

<?php

function myfunction ($parameter1, $parameter2)

{

echo $parameter1 . ” ” . $parameter2;
}

?>

This is a really simple function called myfunction. It takes two parameters and simply echoes them on the screen whenever you call it. The periods you see in the echo statement are a way to concatenate or join the two variables together with a space in between them.

Calling a function is just as easy as making one. Anywhere you want myfunction to print something on the screen all you have to do is:

<?php

echo “Hey there, here is what myfunction has to say: “;

myfunction(“Hello”, “World!”);

?>

If you were to run this you’d see: Hey there, here is what myfunction has to say: Hello World! Not only can a function print to the screen, it can return values you can then store into variables. Let’s take a look at this function:

<?php

function Mod5 ($number)

{

return $number % 5;
}

?>

This function takes any number you give it and mods it by 5. If you aren’t familiar with the modulus operator, all you need to know is that it returns the remainder from the division, and not the number you’d get if you divided $number by 5.

Now let’s see what how we’d use a function that returns a value instead of printing it on the screen:

<?php

//declare our function
function Mod5 ($number)

{
return
$number % 5;
}

if ($_POST[‘number’]) //they’ve entered a number
{

echo “Your number is: ” . $_POST[‘number’] . “<br/>”;

$number = myfunction($_POST[‘number’]); //we store the modulous of what they entered back into the number variable

echo “Your number % 5 is: $number”;
}
else //show them a form to enter a number

{
?>

<form action=”#” method=”post”>

Please Enter a Number: <input type=”text” name=”number”><br/>

<center><input type=”submit” name=”submit” value=”submit” /></center>
</form>
<?php
} //don’t forget to close our ELSE statement
?>

In this example we’ve taken the number a user enters into a text box and then display the number back to them along with the remainder of that number when it’s divided by 5.

One of the great things about PHP is that it comes with a huge collection of pre-defined functions you can use when you program. You can take a look at all the functions by going to php.net. The one function I want to touch on in this lesson is the random function.

As you can probably tell, you don’t always need to know all the little specifics that go on inside of a function as long as it always gives you the results you’re expecting. The same goes with the random function. I could go into details on how it takes the current time on your computer and does a bunch of mathematical stuff to it — but that’s just plain boring!

The short of it is, the rand function takes 2 parameters. The first parameter is the lowest number you want it to generate when it runs. The second number is the highest number you want it to generate when it runs. So, if you wanted a random number between 1 and 4, including the numbers 1 and 4 you’d do this:

<?php

echo “My random number is: “ . rand(1, 4);

?>

View the page with this php code. Now refresh the page. You’ll notice the number is constantly changing.

One other function you’ll need to know is the unset() function. This function is great, you pass it a variable or an object (don’t worry, we’ll get to those later) and it sets the value of that function to null. Think of it as taking a jar of cookies, opening the lid, and dumping all the cookies on the ground. That’s essentially what the unset() function does.

Congratulations, you now know how the rand and unset functions work. You’ll need both of these for this lesson!

Sessions

Now one of the biggest problems we run into is how to keep track of a user’s past responses. Or how to keep track of anything about the user from one page to another. That’s where sessions come in. Sessions are a way to track information about the user as they go from one page to another. Eventually we’ll be using information from the database to track a lot of the moves a user is making with their characters, but we’ll still need to know who the member is as they go from page to page. For right now, we’ll use sessions to keep track of the direction the user picked. And now, instead of letting the user continue to pick a direction after they’ve fallen into the pit we’re going to give them a game over message until they decide to reset the game and try again.

Sessions are very easy to use. They work almost exactly like the $_POST and $_GET variables you can use to access information about what someone has entered on to a page. However, there’s a few major differences:

  1. You can set the values of the $_SESSION variable
  2. Session variables remain with the user until you tell them to expire, they don’t change page by page.
  3. Session variables can be set to expire so they don’t last forever, or you can set them so they never expire and DO last forever.

Using sessions now will get you familiar with them before the programming becomes more complicated.

If you’ve done anything with cookies before then sessions will be a breeze for you. Sessions are a good alternative to cookies because if a browser has cookie functionality turned off you will still be able to keep information about a user from one page to another. If that went right over your head don’t worry, it’s not essential to this lesson.

There’s one thing you have to keep in mind about sessions. In order to use a session you have to call a special function at the top of every php page, BEFORE YOU DO ANY KIND OF OUTPUT!! This last is important. If you try to output anything before calling the session_start() function you will get an error.

Now let’s setup a simple session. Create two pages, one called welcome.php and the other called main.php. Welcome.php is an example of a web page you might see that greets you and asks you what your name is. Main.php is an example of a page you might look at after you’ve visited the welcome.php page.

In welcome.php we have this:

<?php
session_start(); //the first thing we do is start our sessions

if ($_POST[‘name’]) //they entered their name in the form
{
$_SESSION[‘name’] = $_POST[‘name’];

//now we’re going automatically to redirect them our next page
//using a function called header() that’s built into PHP

header(“Location: main.php”);
exit;
}

?>
<form action=”#” method=”post”>

Enter your name for our first session variable! <input type=”text” name=”name” />
<center><input type=”submit” name=”submit” value=”All Done!”></center>
</form>

Now, inside of main.php we’re going to put this:

<?php
session_start(); //we have to start our session again to get the data we saved before

echo “Welcome to the main menu “ . $_SESSION[‘name’] . “!”;
?>

In the main.php file we pull out the information we stored in the session variable for name and print it back out on the screen. Nifty! Now we know, no matter which page this user goes to from now on, as long as we call session_start() we’ll be able to access their name from the variables $_SESSION[‘name’].

Congratulations! You should now understand the basic concept of sessions.

Summary

In this lesson we learned about how to make our own function and talked about how PHP has it’s own predefined functions we can use to make our life a whole lot easier. I talked about how to make a function print something on the screen versus a function that returns a value. Functions that return a value can also be printed on the screen, but you’d have to put an echo in front of the function call to do that.

Next we talked about sessions. Sessions are a way to store data as the user moves from page to page around your website. Without sessions we wouldn’t be able to tell who was who as multiple people will eventually load this game and try to play it. Right now we’ll be using sessions to keep track of a game being over or not, but eventually we’ll only use sessions to keep track of which user a person is as they play.

Game Files

character.php

character2.php (no source code)

Note: these are text files so you can copy/paste all the source code.

Lesson Reasoning

In this lesson character.php now has the treasure starting at a random location. If the user picks the incorrect location they get a game over message instead of being able to pick a direction again. In order to play again the user has to click on a reset button to start the game all over again. I’ve introduced functions, sessions, and a more abstract checking.

Once we start pulling information from the database we won’t know anything about the character’s current location at runtime other then their x,y,z coordinates and the map they’re on. Information about items in that position will all have to be tested each time the character tries to move somewhere. By introducing the treasure in random locations we start to get into the habit of checking information about our location as we select a particular direction.

Return to Lesson 2 or continue on to Lesson 4

Pits of Doom Lesson 2: Breaking It Down

Comments 3 Standard

One of the best things to do if you’ve never made a game before or you don’t have much programming experience is to break things down into their most basic parts. We’ll start off making this game by doing some really really simple programming and then adding functionality until the game is complete. It doesn’t look like much now, but at the end of this tutorial you’ll be able to download a fully working version with an installation file that you can use under the GNU public license to modify and edit as you wish.

The last thing I want to mention is the teaching style I’ll be using throughout all of the lessons in this tutorial. I’m big on letting people try things on their own before I give them the answer. Pretend you’re asked to take a history test. If I was to just hand you an answer sheet with all the right bubbles filled in you’d never learn anything from the test. This is a theory I hold to. In each of the lessons in this tutorial you’ll find two versions of every file I’ve made. One file will have no code in it. That way you can try to program this game from scratch by yourself. But if that’s too daunting don’t worry. The other version of the file will have all the working code inside of it.

Even if you’re not a programmer I encourage you to try your hand at programming each lesson. I’ll go over some of the basic concepts you’ll need to complete the programming before concluding with the reasoning behind what I’ve done so far.

Lesson Concepts

About PHP

PHP is a server side programming language. That means any code you write on any PHP file will never be visible to anyone who goes to a file with php code on it. The benefits of this are you don’t have to worry about people stealing any code you’ve written. When someone views a PHP page, all they see is the HTML or text you’ve generated with PHP or typed onto the page yourself.

PHP files have a .php extension. A lot of people I’ve talked to take that to mean PHP files cannot display HTML or Javascript. That’s incorrect. The .php extension is the server’s way of knowing it needs to evaluate any PHP code on the file before the person requesting the page sees it.

The biggest draw back with PHP is that it’s a server side programming language. That means any time you want to make a change to what the user sees on the page they either have to refresh it, or navigate to a new page. Websites where you see changes applied immediately (google mail, wordpress, to name a few) use something called AJAX. AJAX is an asynchronous relay between a server and a user’s browser. This means they don’t have to refresh the page to see changes. If you’re interested in something like that then this tutorial is still the one for you. PHP is often used in combination with AJAX to create more dynamic web pages. However, I won’t go over any AJAX in this tutorial, so once you’re done making this game you’ll need to find some AJAX tutorials.

Printing to the Screen

All PHP code is delimited by a start and end php tag that looks like this:

<?php
echo “Hello World!!”;
print “Hey there!”;
echo “<b>WOW!!</b><br>”;
print “This is sooooo neat…”;
?>

The PHP start and end tags are lot like matching HTML tags. If you don’t have any HTML experience I strongly recommend you take some of the tutorials on lissaexplains.com before you continue with the lessons here.

If you don’t have the correct start and end tags that would be one reason why someone could see your PHP code on the screen. Without the PHP tags the server doesn’t have any way to know what you’ve typed needs to be evaluated as PHP.

In the code above you’ll also see print and echo statements. It doesn’t really matter which one you use, but this is how you print something to the screen. Notice on the third print statement there is HTML in the quotation marks. There is nothing wrong with putting HTML inside of your PHP, in fact that’s one of the great things about it.

A few syntax things to keep in mind:
1. You always need matching start and end <?php ?> tags.
2. PHP statements always end with a semicolon ;
3. When you echo something to the screen it should be inside of single or double quotation marks
4. If you need to put quotes in your print statements then you should escape it like this:

<?php
echo “And he said \”Hi Mom, how are you today?\””;
?>

The backslash tells PHP to evaluate the quotation mark as text and not as the end of the string.

5. You won’t see an error in PHP until you go to view the page. That’s because php is only evaluated on runtime. Sometimes this is very frustrating, and you’ve probably seen error codes before. If you get an error message read it, it usually tells you what you did wrong in your code.

Common PHP Errors & Solutions

Parse error: syntax error, unexpected T_STRING in [file location] on line [#]
This means you forgot a ” or a ‘ somewhere. There should always be at the start and end of a string. If you have a matching pair, make sure you don’t have one too many. If you have quotes inside of your string then you need to escape them using a backslash like this: \” or \’

Parse error: syntax error, unexpected ‘}’ in [file location] on line [#]
This means you have some kind of multi-line statement and you either forgot a bracket or having too many brackets. Brackets always come in pairs. Sometimes it mean you’re missing a semicolon at the end of the previous statement.

Parse error: syntax error, unexpected ‘”‘ in [file location] on line [#]
This means you probably forgot a parentheses before of after the DOUBLE quote. Sometimes it could also mean that you forgot to escape the double quote.

Parse error: syntax error, unexpected “‘” in [file location] on line [#]
This means you probably forgot a parentheses before of after the SINGLE quote. Sometimes it could also mean that you forgot to escape the SINGLE quote.

Parse error: syntax error, unexpected ‘;’ in [file location] on line [#]
This means that you’re missing something before the semicolon at the end of your statement. Usually its a closing parentheses. However, it could also mean you have a semicolon in a position PHP is not expecting one to be in. That usually happens in loops.

Parse error: syntax error, unexpected T_EXIT in [file location] on line [#]
This means you forgot a semicolon before an exit; call

Parse error: syntax error, unexpected $end in [file location] on line [#]
This usually means you forgot a semicolon or your function isn’t returning like it should be.

Variables

In PHP a variable is defined by a $ dollar sign. That means any word with a dollar sign in front of it will usually be evaluated for some other kind of content. The easiest way to think of a variable is to think about a jar. You can put things into a jar and take things out. You can stick a name on a jar but then decide you want to change that name later. Variables also work this way.

<?php

//this is a comment, comments are for you
//they aren’t processed as code
//get into the habit of leaving comments for yourself so if you come back later
//you can remember what you did or what you were trying to do

$myvariable = “Hello”;
$mysecond = ” World!”;

echo $myvariable;
echo $mysecond;

print “<br>”;

echo “$myvariable $mysecond<br>”;

$myvariable = 2;

echo $myvariable;
?>

In this example I have two variables. You can assign them a value using the equal sign. Variables in PHP are dynamic. That means you can assign them to one type (a string) and then reassing them to another type (an integer) without any kind of conversion. If that just went right over your head, don’t worry. All you really need to know is the syntax to assign a variable.

If-Else Statements

Games are all about decision making and that’s the benefit of a programming language. In order for anything to work in this game we’ll have to set it up to follow the rules and logic I briefly outlined in Lesson 1. To do this we need to respond differently based upon the choice the user playing our game makes.

<?php

if ($_POST[‘button’]) //someone clicked a button
{

echo “You pressed a button!”;
}
else
{
echo “You haven’t pressed a button yet. Go ahead, try it!”;
}

?>
<form action=”#” method=”post”>

<input type=”submit” name=”button” value=”Press Me!”>

</form>

In this example you see a .php file that has a section of PHP code and then below that it has some regular HTML. The part to pay attention to is the if-else section. Here we display a different message to the user based upon if they’ve clicked on our button or not. IF the button has been pressed, the code between the brackets { } of the if section will execute. Otherwise the code between the else brackets will execute. I’m sure you can already see the power of PHP in this one example. If you’d like more help with If-else statements and some more examples of if-else statements read my tutorial here. This covers some PHP programming concepts more in depth and gives more examples.

Form Basics

A form is one way to get information on what the user is doing back and forth to the server and PHP. All forms must have a start and end <form></form> tags. In order to submit any information from a form to the server you MUST have a submit button. Without a submit button you won’t be able to tell the page that the user is trying to send you data about what he/she is doing. You can see a small form in the example above. It has both the start and end form tags, as well as a button. If that looks unfamiliar to you then you really should go back to lissaexplains.com and do some catching up on your HTML skills!

$_GET and $_POST Variables

In order to get data from a form PHP stores two special variables for us. The variables get data depending on the type of METHOD used in the form. If you look at our example above, we use a POST method. That means all the names and values of our form are sent to the server and stored inside of the $_POST variable. That way we can pull information from those variables to see if a user clicked a certain button or link. In the example above, we’re checking to see if someone has clicked on our submit button that we’ve named button (yay for generic names!). If we’d called our submit button BOB and didn’t change the if statement to check for $_POST[‘BOB’] then we’d never see the words telling us we’d pressed the button. As far as PHP is concerned, we no longer have a submit button called button so there’s no way it will ever be pressed.

Summary

There you have it. I’ve not covered in brief (and sorry if it’s not brief enough for you — or too brief!!) all of the major concepts in the first part of the tutorial files you can download below. Again, if you’re up for the challenge, try programming this file yourself by opening the character2.php file. At the top of the page it will outline everything I’m trying to accomplish in this particular file for this lesson. If you just want to see some working code then download character.php and jump right into the next lesson.

Game Files (click to view)

character.php

character2.php (no source code)

You’ll need to copy/paste the source from one of these files and give it a .php extension for the last part of the tutorial to make sense. All of these files are viewable as .txt files so you can see the PHP code inside of them. If they were .php files you wouldn’t ever be able to see the .php code. Do you remember why?

Lesson Reasoning

A lot of the logic behind the game we’re going to make has to do with movement of a character around the game world. Remember there is a difference between a member and a character. A member is an actual person who will login and play this game by the time we’re done. A character is something the member will use to navigate the game. Each member can have multiple characters.

Character.php is from the point of view of one character. Each character will be faced with the option of which direction they can move — left, right, forward or back. Every time a character moves we’ll need to evaluate the move and take some action depending upon the new location they’ve moved to.

Although this file only checks for a single direction and places the “treasure” in one specific location, it’s a step in the right direction. With this file we know which direction has been selected, we can compare that direction to the new position they’ve moved to, and we can print a message on the screen indicating if the character won or lost based upon finding the treasure.

Return to Lesson 1 or you can always Continue to Lesson 3