Loading Monsters From the Database

It's time to add our monsters to the real-world. We are going to make some significant changes to the code that we already have, so that so that the games searches for and displays any monsters within range of the player.

Changes to Main File

In our main file we are going to add another include statement.

include 'dbinfo.php';
include 'monsters.php';

In the echo:

Where the description of the hotspots normally goes, we're going to call a function findMonsters. This function is defined in the monsters.php file that we included above.

echo '{
    "layer": "mmodemo",
	"actions": [
		{
			"uri": "http://www.thoughtfulmonkey.com/layar-mmo/display-stats.php",
			"label": "ST:'.$userST.' T:'.$userT.' HP:'.$userHP.'",
			"contentType": "text/html"
		}
	],
    "hotspots": [';
 
findMonsters($latitude, $longitude, $db, $userID);
 
echo'],
    "errorCode": 0,
    "errorString": "ok"
}';

Process for Loading Monsters

Now we'll start looking at what to put in the monsters.php file. The basic process that we're going to follow is outlined below:

Search database for monsters within range
Loop through all of the ones that were found
    Load their specific details
    Output the details in JSON format
Next monster

Code for Loading Monsters

Shown below is the actual code. Copy it, paste it, and save the file as monsters.php. This will search the database for any monsters in range, and output them as 'hotspots' (or 'points of interest', or some other terminology that just means something with a location).

<?php
 
function findMonsters ($latitude, $longitude, $db){
 
	// Find monsters in range
	$sql = $db->prepare( "SELECT *, ( 6371000 * ACOS( COS( RADIANS(:lat) ) * COS( RADIANS( lat ) ) * cos( RADIANS( lon ) - RADIANS(:lon) ) + SIN(RADIANS(:lat) ) * SIN( RADIANS( lat ) ) ) ) AS distance FROM monster ORDER BY distance LIMIT 0 , 20;" );
	$sql->bindParam( ':lat', $latitude, PDO::PARAM_STR);
	$sql->bindParam( ':lon', $longitude, PDO::PARAM_STR);
	$sql->execute();
 
	// If any were found, then convert to array
	$count = $sql->rowCount();
	if ($count > 0) $results = $sql->fetchAll(PDO::FETCH_ASSOC);
 
	// Loop through array, and output required data in JSON format
	for ($loop=0; $loop < $count; $loop++)
	{
		$monsterLat = $results[$loop]['lat'];
		$monsterLon = $results[$loop]['lon'];
 
		// Find specific monster details, including some details from besitary
		$mdet = $db->prepare( "SELECT `name`, `desc`, `image` FROM `bestiary` WHERE `id`=:montype" );
		$mdet->bindParam( ':montype', $results[$loop]['type'], PDO::PARAM_INT);
		$mdet->execute();
		$mvals = $mdet->fetchAll(PDO::FETCH_ASSOC);
 
		// Risky, but assume that data is always returned
 
		echo '{
				"id": '.$loop.',
				"anchor":{
					"geolocation":{
						"lat": '.$monsterLat.',
						"lon": '.$monsterLon.'
					}
				},
				"text":{
					"title": "'.$mvals[0]['name'].'",
					"description": "'.$mvals[0]['desc'].'"
				},
				"object":{
					"contentType": "image/png",
					"url": "'.$mvals[0]['image'].'",
					"size": 1.8
				},
				"transform":{
					"rotate": { 
						"axis": { 
							"x": 0, 
							"y": 0, 
							"z": 1
						}, 
						"angle": 0, 
						"rel": true 
					}
				}
			}';
	}
}
 
?>

Explanation of Code

Almost the first line is something that probably makes no sense to you - the call to the database.

        // Find monsters in range
	$sql = $db->prepare( "SELECT *, ( 6371000 * ACOS( COS( RADIANS(:lat) ) * COS( RADIANS( lat ) ) * cos( RADIANS( lon ) - RADIANS(:lon) ) + SIN(RADIANS(:lat) ) * SIN( RADIANS( lat ) ) ) ) AS distance FROM monster ORDER BY distance LIMIT 0 , 20;" );

The main part is a distance calculation, and if that is removed, you should find it less daunting.

        // Find monsters in range
	$sql = $db->prepare( "SELECT *, calculate_distance FROM monster ORDER BY distance LIMIT 0 , 20;" );

As all but the medieval-minded amongst us are aware, the Earth is roughly a sphere. This makes distance calculations quite complicated, since latitude is actually a measure of your angle around the Earth, and is a longer distance at the equator than near the pole. I just used the code from one of Layar's examples, but you can look into it further on Wikipedia: Great-circle distances.

The main bulk of the function should be fairly familiar. It is just outputting any monsters that are found in the JSON format for Layar.