Tile mods in PHP with the GD Library

This post will explain how to do some dynamic manipulation of transparent png images with the GD Library, which can be used within JavaScript and other applications.

The GD library is an image creation and manipulation tool that is part of the PHP package. It is enabled on most web hosting sites, however you may want to check by uploading and running a php document with the following:

phpinfo();

If there is a GD Library section, it will be installed.

The Tiles – Edges

As a working example, I will use the tiles for the Isometric game world that I am working on.

Each zone of the map is made up of a 20×20 grid of x,y coordinates, rendered isometric by layering tile images in the document. Refer to this article for further details on this process.

But what if we could soften edges to reduce some of the box feel of the lands? Have a look at the image below to see the modified tiles (1,2,3).

 isoTileMod1

In my original illustration of the map editor, shown at the end of the article linked above, the same effect was achieved by slicing a new tile skin in photoshop and inputting the details into the database as a new tile entry.

With the GD library this same effect can be achieved with a single tool in the editor, on any tile skins.

The Tiles – Color

What if we could go even further than shape, and adjust the color of the tile dynamically, depending on a value in a database. The GD library is capable of that also. Below is an image of the same scene as above, but with a single value “color” changed in the database for each tile.

 isoTileMod2

I’ll post the script below, and then pick it apart after that.

The Script: tileMod.php

$tileID=$_GET['tileID'];
$tilePath=$tileID.".png";
$edgeID=$_GET['edgeID'];
$color=$_GET['color'];
$imageHeight=22;
$imageWidth=40;
$imageSrc = imageCreateFromPNG ($tilePath); // transparent PNG
if ($tileID==4){
	//the tileID denoting blank tiles
	$edgeID=0;
	$color="";
}
if ($edgeID==0){
	//no edge modification, color only
	$imageDest=imagecreate($imageWidth,$imageHeight);
	$safeCoX=20;
	$safeCoY=10;
	imagecopy($imageDest,$imageSrc,0,0,0,0,$imageWidth,$imageHeight);
	imagesavealpha($imageDest,true);
	imagedestroy($imageSrc);
} else if ($edgeID==1){
	//edge 1 is right side cut off
 
	$imageDest=imagecreate($imageWidth,$imageHeight);
	$safeCoX=15;
	$safeCoY=10;
	$startX=0;
	$startY=0;
	$chunkWidth=$imageWidth/2;
	$chunkHeight=$imageHeight;
	imagecopy($imageDest,$imageSrc,$startX,$startY,$startX,$startY,$chunkWidth,$chunkHeight);
	imagesavealpha($imageDest,true);
	imagedestroy($imageSrc);
} else if ($edgeID==2){
	//edge 2 is left cut off
 
	$imageDest=imagecreate($imageWidth,$imageHeight);
	$safeCoX=25;
	$safeCoY=10;
	$startX=20;
	$startY=0;
	$chunkWidth=$imageWidth/2;
	$chunkHeight=$imageHeight;
	imagecopy($imageDest,$imageSrc,$startX,$startY,$startX,$startY,$chunkWidth,$chunkHeight);
	imagesavealpha($imageDest,true);
	imagedestroy($imageSrc);
} else if ($edgeID==3){
	//edge 3 is top cut off
 
	$imageDest=imagecreate($imageWidth,$imageHeight);
	$safeCoX=20;
	$safeCoY=15;
	$startX=0;
	$startY=($imageHeight-2)/2;
	$chunkWidth=$imageWidth;
	$chunkHeight=(($imageHeight-2)/2)+2;
	imagecopy($imageDest,$imageSrc,$startX,$startY,$startX,$startY,$chunkWidth,$chunkHeight);
	imagesavealpha($imageDest,true);
	imagedestroy($imageSrc);
} else if ($edgeID==4){
	//edge 4 is bomttom cut off
 
	$imageDest=imagecreate($imageWidth,$imageHeight);
	$safeCoX=20;
	$safeCoY=5;
	$startX=0;
	$startY=0;
	$chunkWidth=$imageWidth;
	$chunkHeight=($imageHeight-2)/2;
	imagecopy($imageDest,$imageSrc,0,0,$startX,$startY,$chunkWidth,$chunkHeight);
	imagesavealpha($imageDest,true);
	imagedestroy($imageSrc);
 
} else {
	exit();
}
if ($color!=""){
	$rgb2 = imagecolorallocate ($imageDest, hexdec($color{0}.$color{1}), hexdec($color{2}.$color{3}), hexdec($color{4}.$color{5}));
	imagefill($imageDest, $safeCoX, $safeCoY, $rgb2); //rgb fill
}
Header("Content-type: image/png");
imagePNG ($imageDest);
imagedestroy ($imageDest);

The script takes a parameter “edgeID”, which can be 0 (no modification), 1 (the right side of the diamond tile is cut away), 2 (the left side of the tile is cut away), 3 (The top of the tile is cut away), 4 (the bottom of the tile is cut away)

The second parameter is “color”, which contains a hex color value (eg. FFF000)

The last parameter is “tileID”, which tells the script which tile skin to modify.

The modification process is started by opening a new image stream at $tilePath, like this:

$tilePath=$tileID.".png";
$imageSrc = imageCreateFromPNG ($tilePath);

To start an image stream using other file types, there are functions such as imageCreateFromGIF, imageCreateFromJPG, etc.

Let’s dissect the code within condition edgeID=1 (right side cut off):

Note: While the tiles are 20hx40w, the images themselves are 2pixels higher, due to a footer effect, this is taken into account in the script (edgeID 3,4) and may need to be modified in other applications.

The first line of the edgeID triggered code creates a new image to be the destination of our slice, it is given the same dimensions as the original image:

$imageDest=imagecreate($imageWidth,$imageHeight);

This next section creates the necessary variables for the next steps:

$safeCoX=15;
$safeCoY=10;
$startX=0;
$startY=0;
$chunkWidth=$imageWidth/2;
$chunkHeight=$imageHeight;

$safeCoX and $safeCoY are coordinates of a point within the tile slice that can be filled. This is important to note, as this pixel coordinate should be attached to any area that you wish to be filled using the Auto Fill color value. (it operates similar to a paint bucket fill in photoshop or ms paint)

$startX and $startY are the starting coordinates of the slice area (the part of the image being copied from the original image, and being pasted into the new blank image) – since we wish to remove the right hand side of the image, this should be the left hand side, beginning at 0,0.

$chunkWidth and $chunkHeight are the dimensions of the slice area to be copied. We want half of the tile width, and the full tile height.

Page 1 of 2 | Next page