Last Good Quote: Son's are the seasoning on our lives. - Someone on Facebook

Monday, November 24

Server and Client Communications (Sort Of)

In a typical gaming environment there is a "game server" which is responsible for tracking all the communications between players (clients) within the game. Communications can be considered anything from the chat function, to the location of bullets within the game. Pretty much any piece of data that one player needs to send to another goes through the game server.

(That was in its simplest form, it is more complicated than that...go google it)

With a PBBG it gets a little tricky because there is no game server in play, its all cron jobs and reactions to players. (This is due to web development being "stateless"....again go google it, its why web programming is "different")

I use the following code to send interactions between two or more players. Pretty much you have a table that translates the game commands to each player...however the client code (javascript) has to be a bit smarter to handle the "statelessness" of the content)

See it in Action (note, you will have to enable popups)

If you want to implement it, you will need to create the following two tables.

User Table: Hopefully you allready have one of these, if so just add lastCommID to it.

CREATE TABLE `lab_user` (
`userID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`userName` VARCHAR( 20 ) NOT NULL ,
`lastCommID` INT NOT NULL
) ENGINE = MYISAM ;

Command Table: "Meat of the code"

CREATE TABLE `lab_command` (
`commID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`userID` INT NOT NULL ,
`command` VARCHAR( 20 ) NOT NULL ,
`commandOptions` VARCHAR( 255 ) NOT NULL
) ENGINE = MYISAM ;
You can download the source here.

Please keep in mind...USER IDs are HARD CODED in the source...you will need to config/play with that yourself.


For those that just like to "look". Here is some javascript....

var xmlHttpDivID = "";
var ajaxInUse = false;
var readyToSend = true;

function getXmlHttpObject(handler)
{
var objXMLHttp=null;
if (window.XMLHttpRequest)
{
objXMLHttp=new XMLHttpRequest()
}
else if (window.ActiveXObject)
{
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
}

if(objXMLHttp == null)
{
alert("Your browser is not AJAX/Web 2.0 enabled");
}

return objXMLHttp;
}

//////////////////////////////////////////////////////////////////////////
//
//
// Sending the commands to the server
//
//
//
//////////////////////////////////////////////////////////////////////////
function mouseClicked(e)
{
if(readyToSend)
{
pos = getMousePos(e);
sendCommand("move", "player_|" + pos[0] + "," + pos[1]);
}
else
{
log("Waiting for a listener!");
}
}

function sendCommand(command, options)
{
if(!ajaxInUse)
{
ajaxInUse = true;

xmlHttp=getXmlHttpObject();
xmlHttp.onreadystatechange=commandSent;

url="commandHandler.php?action=sendComm";
url+="&userID="; //very bad, change this for testing...
url+="&command=" + command;
url+="&options=" + options;
url+="&cache_killer=" + Math.random();
xmlHttp.open("GET",url,true)
xmlHttp.send(null);
log("Command Sent");
}
else
{
log("Ajax is in use...try later");
}
}

function commandSent()
{
if (xmlHttp.readyState==4)
{
log("Command Sent and Done");
ajaxInUse = false;
}
}



//////////////////////////////////////////////////////////////////////////
//
//
// Reading Commands from the server
//
//
//
//////////////////////////////////////////////////////////////////////////
var commTimerID = "";

function startListening()
{
requestNextHttp=getXmlHttpObject();

url="commandHandler.php?action=start";
url+="&userID="; //very bad, change this for testing...
url+="&cache_killer=" + Math.random();
requestNextHttp.open("GET",url,true)
requestNextHttp.send(null);
//log("Ask for next command");
requestNextCommand();

}



function requestNextCommand()
{
requestNextHttp=getXmlHttpObject();
requestNextHttp.onreadystatechange=processCommand;

url="commandHandler.php?action=getComm";
url+="&userID="; //very bad, change this for testing...
url+="&cache_killer=" + Math.random();
requestNextHttp.open("GET",url,true)
requestNextHttp.send(null);
//log("Ask for next command");
clearTimeout(commTimerID);
}

function processCommand()
{
if (requestNextHttp.readyState==4)
{
str = requestNextHttp.responseText;

if(str != "")
{
log2(requestNextHttp.responseText);
performCommand(str);
}

commTimerID = setTimeout("requestNextCommand()", 3000);
}
}

function performCommand(str)
{
data = str.split("|");

if(data.length > 2)
{
commID = data[0];
sentByUserID = data[1];
command = data[2];

if(command == "move")
{
objID = data[3];
pos = data[4].split(",");
destX = pos[0];
destY = pos[1];
log("Moving " + objID + " to " + destX + "," + destY);
setDest(objID, destX, destY);
}
}
}



//
//add the event to the document
//
document.onclick = mouseClicked;
document.onload = startListening();


Javascript - Move that Image

Another Code Report,

How to move an image to another place on the screen. The user picks the location by clicking the mouse somewhere within the window.

This builds on the last code base, which featured the mouse Position finder code.

Watch It In Action (View source to get the code)

A couple of notes to keep in mind:
  • You can only click once, then you have to wait for it to get to it's destination
  • log() - Puts a message in the div, a cheap debugging technique
  • move() - The meat! What we call a re-cursive function, is called again and again until the object reaches its destination
  • findPos() - returns the position of an object, this is actual a cheater function as it does not get the true position of an object. (see mobLib for the full function)
I purposely did not comment well, if you need to have comments for these simple functions, you may want to get something a bit easier to work with. (my 2 cents)


var speed = 1;
var moving = false;
function mouseClicked(e)
{
if(!moving)
{
pos = getMousePos(e); //from included js file
moving = true;
move("player", pos[0],pos[1]);
log("Clicked: " + pos[0] + "," + pos[1]);
}
else
{
log("Object is in the process of moving.");
log("Click refresh to start over.");
}
}

function log(msg)
{
document.getElementById("log").innerHTML = msg + "
" + document.getElementById("log").innerHTML;
}


function move(objID, destX, destY)
{
var obj = document.getElementById(objID);
var pos = findPos(objID);

currentX = pos[0];
currentY = pos[1];
newX = currentX;
newY = currentY;



if(destX > currentX)
{
//log("X:" + destX + " vs CurrentX: " + currentX);
newX+=speed;
}

if(destX <> currentY)
{
newY+=speed;
}

if(destY < top =" newY;" left =" newX;" t =" setTimeout(" moving =" false;" posx =" 0;" posy =" 0;" e =" window.event;" posx =" e.pageX;" posy =" e.pageY;" posx =" e.clientX" posy =" e.clientY" out =" new" obj =" document.getElementById(objectID);" curleft =" curtop" curleft =" obj.offsetLeft" curtop =" obj.offsetTop" onclick =" mouseClicked;">
Some things to try and play with:
  • Can you speed up the movement to the destination?
  • Can you add more images and allow the user to control more than 1?
  • Can you make the image move so that it's center ends up on the destination point? (right now the top left corner ends up there)



Javascript - Finding that mouse position

I seem to constantly need this bit of code. Hope it helps someone else.

The following javascript code, finds the mouse position and returns it in an array.


function getMousePos(e) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;

if (e.pageX || e.pageY)
{
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY)
{
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
var out = new Array(2);
out[0] = posx;
out[1] = posy;
return out;
}


Demo - You can see it in action here.

Credits - I got the basics of this script from here.

Monday, November 3

Tool - Popup builder

An very old bit of code, written before popups were considered a curse.

This tool will allow a user to build their own popup screen and handler.

Again bit old, but I thought I'd put it out there.

View the Tool

Tool - Creating Drop Down Menus

Another experiment for the lab. I got a bit tired of creating those drop down menus by hand, so I built this page to help me create them.

Looking back, I could have built a code snippet or macro to do the same thing, but this was more fun to build.

All HTML and javascript.

Feel free to use and modify for your own use.

Right click and "View Source" to get code.

Drop Down Builder

Code - Javascript Animation

Many moons ago, I wrote this small library package. It handles a number of interactive functions that one might use on a Web 2.0 site.

It's not fully tested but I use parts and pieces of it quite often.

I figure that if anyone else finds it useful they might like to look at it. Especially those new to programming.

The most interesting is an animation function which allows you to set the velocity of a div tag and then watch it zoom around the screen.

Most functions are multi-browser compatible, I think one if IE only though.

Feel free to use for any of your projects. A link would be nice but not mandatory.

Source Available

Thursday, October 30

Path Finding in Javascript

I went back to the Lab (cause I needed to get my mind off the job). I decided to write a path finding algorithm in javascript.

I used my typical map setup. I found some pseudo-code for the A* path finder. I did the best I could (there was a heuristic in that pseudo code that I could not quite duplicate)

Anyway, it seems to work nicely. It does not find the shortest path, but it does find a path.


Feel free to use it for your own usage.

One Note: It uses a recurring function, I limited it to 40 loops. If you have a large map, you may need to up this a bit.

Take a Look

Source Code

Tuesday, September 9

Display All Images in a Directory

The following php code will allow you to display/show all images in a folder. Be careful as if there is an executable file in this folder it will get executed.

(Just cause I'm tired of searching for it every time I want to do it)

$dir=dir("./images/.");
while($filename=$dir->read())
{
if($filename != "."
&& $filename != ".."
&& $filename != ".."
&& $filename != "Thumbs.db" )
{
print $filename . " - ";
}

Tuesday, July 29

Future Books and Dreams

I'm interesting in writing and think that I have a lot to share. (Although my wife and brothers would tell you differently.) Here is a list of books I would like to write and why:

Programming for High School Kids
I currently volunteer time teaching kids in grades 9 - 12 how to build basic web pages in ASP and .Net. I've done that for about 4 years now. I really enjoy doing it and I learn a lot about my development processes each year that I teach. The kids that I teach walk into my class with no computer programming or web design skills and 8 months later they are able to build full scale web applications.

This is done through the BDPA organization with the HSCC program.

Game Building with PHP
A book about how to build web based php game. This would cover some of the newer techniques like AJAX and map display, movement and stats. I also have read a lot of interesting things on game modeling and building addictive games. I think writing this book would be a great learning experience for myself.

Pseudo Auto-biography
I've always wanted to write about my family and my past. I have pretty interesting background, I have 3 brothers and 2 sisters, a white mother, a black father who spent 20+ years in the military, is a vet and a Buddhist. I also was raised in a very religious environment which I broke out of when I got older. I never watched TV or listened to music till I turned about 16. Because of this I can read a 300+ page book in about 2 hours. I've a collection of over 1000 sci-fi books and can remember almost every chapter of all of them. All of this gives me, what I think is a unique view on race, religion, ethics and life in general.

Why I raised my Sons the way I did
I really want to write this one just for my boys. I have a 2 and 9 year old and I think that they would appreciate some insights on why and how I made the choices I am now making in regard to how they are raised. Again I think this book would be educational both for myself and for them, but the most interested reader of this book would be my wife. *grin* Love ya Babe!

Anyway, just a few things that were on my mind. If you feel like it leave me a comment on which one I should start first.

Friday, July 11

Cleaning out the Code Closet

I was going through my PC backups and looking at all those old projects I have out there. It's interesting how much stuff I've worked on "Just for Fun"

I figured I'd list them here so, if you are interested in any of the code let me know. I'm usually happy to share. But keep in mind, these are all projects that I did just to see what can be done, so they are mostly proto-types.

  1. myAI - A php based neural net project, gives a visual display of how an AI neural net works. 95% completed.
  2. Great Browser Based Games - An engine to allow people to post their PBBG games, I did this in an interesting AJAXy way. 75% completed
  3. Card - An RPG card game, wrote in PHP, browser based, currently in Alpha. 99% complete. (No I won't share source on this one)
  4. RPG Game Template - A template that will allow other novice developers to build a web based RPG. 50% completed
  5. mobLIB - My library of javascript functions for moving things around, doing AJAX and other funky stuff.
  6. Monster Football League - A php and javascript based american football game. This was kind of neat, but I ran into some processing problems, evidently trying to calculate the position of 24 players and a football on a 100 yard field is a bit more then javascript can handle. But it was fun to try.
  7. Horse Racing VR - I was collobarating with someone to do a Horse Racing VR game, sadly I got caught up in real life stuff that pulled me off that project and my partner disappeared.
  8. Stock Analyzer - A program that analyzes 3000 stocks and gives you the top 3 - 5 potentials each day. 90% complete, working towards a release. (No source code available on this one)
  9. Blade of a Mage - Another browser based PHP game, I used to run a long time ago. Took it offline because I didn't have the time to manage it...looking at putting it back online.
  10. Star Fighter - A flash game, simple top down plane game. Graphics are ugly as hell, so I didn't deploy it.
  11. Tactics - A flash game, imagine chess, but with RPG characters that have stats and abilities. Completed but took too much effort to maintain code wise (I don't enjoy working with flash). It had a php backend.
  12. Ships - A flash game, this was based on all the PBBG space games out there, except with this one you could see the movement of your ships and what not. Ran it online for a while but it ended up, hogging some server resources.
  13. Worlds of War - An isometric Mech battling game, I loved this game. But some moron hacked it and crippled my server. I fixed the hack but I worry about putting the game back online. (irrational fear, but look at what number it ended up being on the list...13...its a sign I tell you!)
  14. Battle Forces Online - Fully deployed operation game, RPG isometric top down view. I like it but I think it needs a lot of tender love and care to turn it into the real thing.
Well that is my list...of course that's just on this PC, who know what I have on my other one.

Thursday, July 3

Dominating Keyboard Controll in Javascript

A great blogger at Lost Garden, setup a development challenge. The challenge was to build a game incorporating shadows.

While not exactly in line with his rules, I wrote a javascript game. While building this I had to figure out how to move a character around the screen using javascript.

For those who just like to look at code, here is the source and a demo.


I started by placing a div tag which had absolute positioning. This allowed me to move the div around the screen.


<div id="unit"
style="position:absolute;
top:0px; left:0px;
height:20px;width:20px;
margin:0px;padding:0px;"><img src=man.gif width=30 height=30></div>


The next step was to capture any key presses for that div, there are a number of ways to do this but I did it with the following javascript:

controlledObj = document.getElementById("unit");
document.onkeydown = keypressed;


The first line let's me know which div I am controlling, the second line captures all key events to the keypressed function.

The key pressed function watches for arrow keys and moves the controlledObject in the appropriate direction:
function keypressed(event)
{
if(event.type == 'keydown' && event.keyCode == 38)
{
//up
dir="N";
pos = findPosOfObject(controlledObj);
controlledObj.style.top=pos[1]-5;
}

if(event.type == 'keydown' && event.keyCode == 40)
{
//down
dir="S";
pos = findPosOfObject(controlledObj);
controlledObj.style.top=pos[1]+5;
}


if(event.type == 'keydown' && event.keyCode == 37)
{
//west
dir="W";
pos = findPosOfObject(controlledObj);
controlledObj.style.left=pos[0]-5;
}

if(event.type == 'keydown' && event.keyCode == 39)
{
//east
dir="E";
pos = findPosOfObject(controlledObj);
controlledObj.style.left=pos[0]+5;


}
}

There is a special function, findPosOfObject(), used in that bit of code, that gives me the precise location of a div tag. This is something I googled, I'm not sure where it came from but it's a pretty simple piece of code. It looks at an object, goes up the DOM tree to find all its parents and finds the exact top and left of the object. It then returns those values in an array.

function findPosOfObject(obj)
{
var curleft = curtop = 0;
if (obj.offsetParent)
{
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent)
{
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
}

return [curleft,curtop];
}




And that is how I moved an object around on the screen.

You can see the end results Shrooms
and the code can be downloaded here.

Enjoy!

Thursday, June 26

Gaming with a Guest Account

You've got 10 min...you know of this great game, you want to test it but as you visit the site you realize you have to register.

*sigh* you walk away, telling yourself you'll come back tomorrow.

As a game builder that's an expierence I don't want to give my potential players. Thus I've started creating a guest account feature for all my new games.

The guest account gives a player a quick easy way to evaluate the game.

For the time being the guest accounts on my games are not persistant, they stick around for a few hours or days then disappear. As a matter of fact, once you logout the game, you can not log back into the guest account.

Remember the goal is to convert the user to a player, thus if they play as guest but don't feel emotionally attached enough to create their own account. They won't be playing the game for very long.

Wednesday, June 25

A Quest to Find Intelligence

A Quest to Find Intelligence

I've decided that if I'm going to research and explore Artificial Intelligence (A.I.) it would be wise to define in my words what I am trying to find.

I am searching for a computer program that has the following capabilities:
  1. It must be able to create tools.
  2. It must be able to identify the usefulness of a tool.
  3. It must be able to set its own goals.
  4. It must be able to determine when a specific goal has been met.
  5. It must be able to be acted upon by its environment.
  6. It must be able to act upon its environment.
If a program is able to accomplish these things I would consider it intelligent and useful. In addition to this, the more complex it's environment the more intelligent I would find the Agent.

What's a tool?

A tool, to my AI, would be any function or program which accepts a number of inputs and delivers a number of outputs.

For example, an add function might take 2 numeric inputs and output one numeric number. In this case a single function acts as both the input and the output.

add(1,2) -> 3

This would be a simple tool. A more complex tool might be a map object which has a number of functions (inputs) that allow you to modify the appearance of the map (output)

map.createMap() - sending inputs
map.viewMap() - getting outputs
0 0 0
0 1 0
0 0 0

map.moveUp() - sending inputs
map.viewMap() - getting outputs
0 1 0
0 0 0
0 0 0

Identifying the usefulness of a tool

In order for the AI to understand the usefulness of the tool, it must be able to make an accurate prediction of the output of the tool.

For example, after examining and testing the add function mentioned above, the AI will be able to identify that if it puts 3 and 5 as inputs it will get back 8.

This is NOT the same as saying that the AI knows the implementation of the add function, rather it can anticipate the response of the tool.

This will allow the AI, when given a goal, to choose one specific tool to use from a variety of tools.

Note to self: This means that the AI must maintain some type of meta-data about tools. IE: When a goal using the word "addition" this should key the AI to consider the add function as part of it's procedures.

Setting a goal

As stated before one of the requirements is that the AI be able to set its own goals. This is needed because as more and more difficult tasks are requested of the AI it will have to set a sequence of steps together to achieve the tasks. I consider each of these sub steps as a goal that the AI must recognize and achieve before completing the final tasks.

For example if AI is asked to provide the tasks of moving itself 5 spaces up on a map, it must understand that it's first goal is to move a single space. It must then choose a tool that will do that and execute that tool 5 times.

This may result in the AI creating a new tool which moves it 5 spaces. Which brings us to our next point...

Creating tools

At some point the AI will need to build its own set of tools, as a tool may not exists (or be at its disposal) that will accomplish the overall goal.

In a simplistic sense, since tools are functions or objects, as the AI builds more tools it becomes "smarter"

Again the AI will need some method for determine when and how to create a tool.

Acting within the Environment

Finally and most importantly, the environment that the AI "lives" in will have to interact with the AI. And vice versa the AI will have to be able to interact with the environment.

This is most important as the "richness" of the environment that the AI can interact with will dictate the "intelligence" of the application.

For example:
Let's say an AI, agent's, environment consists of a label, text box and submit button. This is the agents environment. It is what the agent can act on and it is how the agent will be acted upon.

An agent can enter text into the text box and submit the text using the submit button. This would be the agent acting on the environment.

The environment would act upon the agent by placing text into the label.

Certain characters in the label, "That is correct" would affect the agent in some manner.

This is a simple environment and the agent behind it would be considered to have "lesser intelligence"


A More Complex Example

The environment consists of a 3d world, like "Worlds of Warcraft". The agent (AI) would be a character in that environment.

As the agent performs actions in this environment, attributes of the agent would respond accordingly. IE: health, level, skills, etc...

The next few post will go into each of these functions in more detail.

Tuesday, June 17

Online Game Programming Book

I have not posted in ages, however I ran across this link and thought it was a good resource.

This book is about programming games in Python. Seems to be a good starting place for all those new to game programming.

It's available as a PDF download.

http://pythonbook.coffeeghost.net/book1/index.html

Wednesday, March 19

2005 Table Partition - Optimization Test

On the job we decided to implement table partitioning with SQL Server 2005. I wanted to get an understanding of the increases and decreases that we would see with a partitioned table. Below is documentation of my tests.

Tables Involved
Step 1:
Create Table called 'nonPartitioned'
No Primary Key
16 varchar(50) fields
1 bit field called 'activeFlag'

Step 2:
Populated table with random text
Created 250,000 rows

Step 3:
Mark a sizeable portion of the table as active.
I took 50,000 rows and marked them as active.
I took rows that cotained an 'a' in 'fieldG'

Step 4:
This table is partitioned on the activeFlag, 1 or 0
Create Partition Function
Create Partition Schema
Create Partition Table

Step 5:
Copy Data from 'nonPartitioned' to 'partitioned'

Step 6:
Create table called 'smallTable'
This holds only active records
Populate with active records only

Step 7:
Create table 'selected'
This will hold data that we select from either partition

Some important metrics to note at this point:

52,689 where ActiveFlag =1
197,311 where ActiveFlag =0

35.51 MB - Partitioned Table Size
36.17 MB - Non Partitioned Table Size
7.45 MB - Small Table

First Test - Selecting from Small Partition
The first test is to select data and see if we have a speed increase.
  • Truncate the 'selected' table
  • Perform the following 1,000 times
  • Select 10 random records from the nonPartitioned Table where activeFlag = 1
  • Insert it into the selected table
4:53 (4 min, 53 seconds) - NonPartitioned Table
3:39 (3 min, 39 seconds) - Partitioned Table
3:55 (3 min, 55 seconds) - Small Table

Second Test - Selecting from Large Partition
The first test is to select data and see if we have a speed increase.
  • Truncate the 'selected' table
  • Perform the following 1,000 times
  • Select 10 random records from the nonPartitioned Table where activeFlag = 0
  • Insert it into the selected table
13:23 - Partitioned Table
12:59 - NonPartitioned Table
00:00 - Small Table (no select available of large set)

The following code was used for those tests:
truncate table selected
declare @count int
set @count = 0
while @count < activeflag="0" count="@count+1">
Third Test - Updating 1,000 rows
I now want to test the update statements to these partitions. I used the following logic
  • Truncate the 'selected' table
  • Perform the following 1,000 times
  • Select 1 random records from the nonPartitioned Table where activeFlag = 1
  • Update one field (fieldB) for this record
5:03 - Partitioned Table
9:56 - NonPartitioned Table
4:57 - Small Table


Third Test - Updating 5,000 rows
I now want to test the update statements to these partitions. I used the following logic
  • Truncate the 'selected' table
  • Perform the following 5,000 times
  • Select 1 random records from the nonPartitioned Table where activeFlag = 1
  • Update one field (fieldB) for this record
33:17 - Partitioned Table
49:25 - NonPartitioned Table
24:27 - Small Table

Conclusion

If you must have all the data in one table, then partitioning the table will greatly increase your performance in all areas.

However if you can pull the data out of the table into a smaller table, this will give you the greatest performance during transactional processing.

Caveat

This is my own home grown test, as always perform your own test before making production relavant decisions. Your data may give you different results.

Friday, March 14

Battle Forces Online: Bounce Rates and Visits

Battle Forces Online: Bounce Rates and Visits

Interesting .... Between Feb 15, 2008 and Mar 14, 2008.

Low Bounce Rates:
* freegames.au - 39 visits, 20% bounce rate
* internetgames.org - 1 visits (prev 7)
* onlinegamesinn.com - 10 visits (prev 19), 30% bounce rate
* pbbgblog - 42 visits, 40% bounce rate
* onrpg.com - 133 visits (prev 37), 27% bounce rate (prev 30%)
* forums.indiegamer.com - 13 visits (prev 97), 30% bounce rate (prev 62%)

Most Visits From
* onrpg.com - 133 visits (prev 37), 27% bounce rate (prev 30%)
* community.bbgamezone.com - 49 visits (prev 59), 35% bounce rate (prev 45%)
* forums.indiegamer.com - 13 visits (prev 97), 30% bounce rate (prev 62%)
* pbbgblog - 42 visits, 40% bounce rate

I know that this past month I have posted a lot of entries on pbbgblog.com....evidently they have been working. The bounce rate is a bit high but it seems worth while.

Mental Note: Check out onrpg.com, it may be worth while to post a few things over there as it seems, they have a great bounce rate for my visitors.

Tuesday, March 11

Code: Merge Gif Images to create one image

The following code will take an array of gif images and merge them into one and save the resulting image to file.

I use it to create a unit images on the fly. As users buy different equipment, the unit's look changes.


function mergeImages($imgPathArray, $dest)
{
$imgArray = array();
for($i=0;$i < sizeOf($imgPathArray);$i++)
{
array_push($imgArray, imageCreateFromGif($imgPathArray[$i]));
}

$src = $imgArray[0];
$background = ImageColorClosest($src, 0, 0, 0);

for($i=1;$i<sizeOf($imgArray);$i++)
{
//ImageColorTransparent($imgNew, $background);

ImageCopyMerge( $src ,
$imgArray[$i],
0, //dest x
0, //dest y
0, //src x
0, //src y
74,//width
100,//height
100 //alpha
);

imagedestroy($imgArray[$i]);
}

return ImageGif($src, $dest);
}





Usage:

$dest = "images/custImage.gif";
$imgPathArray = array("images/builder/blueBase.gif","images/builder/body.gif","images/builder/legs.gif");
array_push($imgPathArray, "images/builder/body.gif");
array_push($imgPathArray, "images/builder/legs.gif");
array_push($imgPathArray, "images/builder/sword.gif");
mergeImages($imgPathArray, $dest);

Notes and Caveats:

All of my gif images were the same size, 74 X 100.
They also have transparent backgrounds.
If your images are different sizes, just change the width and height lines.
Note: Your array must contain at least 2 images otherwise you get an error.

Thursday, March 6

Battle Forces Online - Upgrade Time

Battle Forces Online has gone through a revision.

New Features
  • Added Destinations - Inns, Gates and visiting spots
  • More boards to play
  • Fight Pits - Small maps that once clear earn you loot
  • Optimizations in the response time to action requests
  • You can now buy more Blades (units) and weapons
  • Healing Spell added for Mages
  • 2 New Blades added, Earth Mage and Fire Mage
  • More spells and items
  • No more random spawning, everyone enters the board at the same time.
  • Alter your party
StoryLine

The story line is a bit weak at the moment, but I wanted to build the ability to give each map a storyline.

Destinations
There are now a number of places you can visit on each board, these places allow you to heal up, buy stuff and chat with NPCs.

More Boards to Play
Currently the game consists of the following boards/maps
  • Awakening - All new users enter here, there are very few enemies. This board allows users to get used to moving and attacking.
  • Dark Forest - Central location, allows you to move around and fight other players. There is a forest theme to it.
  • Gorjin's Bridge - A control point, you're going to need to level up and have a party of 2 Blades to clear this map. There is a bridge theme to it.
  • Gorjin's Lair - This board was built to test a user. Try to get to the castle at the far end.
  • Small Fight Pit - Very small fight pit, good for users with low stats or low party counts.
  • Medium Fight Pit - A medium sized pit
  • Large Fight Pit - Lots of enemies, lots of space...bring your whole party!
Optimizations
Due to the nature of the engine, when you tell a Blade to move or attack, the request is routed to the server, the server then responds with an OK or Not OK. This was causing a delay to occur between when you clicked and when a Blade actually performed the action.

I made some optimizations to the server handling as well as providing a visual cue (The blades says OK and fades a bit) when you give an action command.

Spells
If a spell is not an attack spell, a mage will cast it upon all members of the party. So a heal spell will heal all members by 10 HP. You do not have to target a member to do this.

In addition to this some spells now have a duration, these spell affects will last for a certain length of time. For example: Magic Shield last for 2 min and gives all members in the party +5 defense.

New Blades
I took the old mage and re-named it to "Fire Mage", this mage can cast fire spells.

I created a new mage called "War Mage", this mage cast lighting spells.

I created a new mage called "Earth Mage", this mage cast healing and defensive spells.

Mages can be killed by any warrior pretty easily so protect them.

Spawning
The old system used to randomly place your Blade on a map. The new system has a spawning point and your entire party will spawn around this point every time you join a map.

Editing the Party
You can now edit how your party spawns, so if you want the mage in the back and the Lord in the front you can do this.

Additional editing features are coming.

In the Future

Some things I'd like to develop in the near future:

* Guilds
* Challenges

Friday, February 29

Question from Bill Gates

I used LinkedIn (a social networking application)

On it Bill Gates had asked a general question; What can we do to encourage young people to pursue careers in science and technology?

My response is below:

It boils down to Respect and Reputation. One of the reasons that young people admire and purse careers is that they see the position as one of respect and authority in the community.

For example, the big time lawyer, the life saving doctor, the helping policeman; these are all positions which come with a large degree of respect and reputation.

Currently I believe that youths tend to view technology jobs as high paying white collar jobs. Reputable well paying positions but not very "exciting".

I think we, the technology group, have done ourselves a dis-service by marketting technology as easy to learn and any one can learn it. This takes away from the respect that one can get for having this job. We may be making it look too easy. I say look because I am well of aware just how hard it is to do things correctly and succeed in our industry, but I wonder how many young adults are aware of this.

Now this is counter to what a lot of folks and groups are doing to encourage technology in our youths. And I certainly would not stop any of these efforts. This might be considered a different tact.

An action that could be taken is to either create another title or pick one that is out there , I believe we have enough, and work at creating an image of that title. An image which will stand beside and out "shine" the Lawyer, Doctor, Buisess Exec career choices that young adults face.

I mean no disrespect to all the great technology leaders out there. I am awed and very respectful of your reputations.

These thoughts come after volunteering teaching young minority kids in the 9 – 12th graders .NET web development for the past 4 years. This is through a community driven organization. I have found the childgrens thoughts and actions very insightful and for anyone that has not taken the time to give back to the community in this well.

I am no author but these are some things that I thought I should share.

Friday, February 22

Simplest of Template Systems

I've looked at a number of templating engines over the years. Some are very nice, however they all seem a bit large for what I usually am trying to build. I've used the follow technique which is dead simple.

I put two include statements in each file, one at the top and one at the bottom. Like so:



Main contents and code



That's it. I create my layout and then I look for the large part of the layout where the main content would go, this gives me my "dividing" line. All code above this goes in the templateTop, all code below it goes into templateBottom.

For Example

I have a page, with a menu across the top, some content and a footer. This is how my html might look.




Hello and welcome to the grand site of ....




This goes into the top
templateTop.php





This goes into the bottom:

templateBottom.php





Draw Backs

There is one drawback to this method, if you use images or have referential links within your template files, they could have the wrong url because your base will always be the file that did the include.

For example, if you have the following line in your template file.


The root of the file included the template will be included with this:

When the file index.php has the include:
But when the file /actions/buyItem.php has the include:

To fix this you must always use fully qualified paths or refer to the root by have a "/" in the front of all referential urls.

Wednesday, February 20

Link: Why we banned Lego

A very informative view on how a Lego Town built by kids, leads to a deeper understanding of communities and power structures.

http://www.rethinkingschools.org/archive/21_02/lego212.shtml

Tuesday, February 19

Defeating SQL Injection

Your code is the walls which protect your intellectual ideas. The best attack your enemy has is SQL injection. Are your walls providing a suitable defense? (*groan* That was a horrible opening but it was the best I could do)

A few comments on this blog were made on SQL Injection, so I thought I'd post some thoughts. There are many articles about how to prevent SQL injection, I am going to cover just a few techniques.

The Problem
If you don't know what SQL Injection is Google it, but quite simply it is a way for external forces to execute SQL statements on your database. Statements like:
delete from user (scary)
update user set money= 100000000 (hacker)
Most of these types of hacks happen when a user types specific things into a text box or address bar. This being the case you want to "clean" all incoming input. Rule of Thumb: Very rarely trust and always verify. (Trust but verify?)

The reason this hack works is because when you use a variable in a sql statement it can contain malicious code. For example the following piece of codes is suspect to SQL Injection:
$sql = "Select * from user where username = '$username' and password = '$password';"
mysql_execute_query($sql);

If the user uses the following as their username ';delete from user; it will delete all users from your tables.

The Solution

Clean all your variables. I run all variables, regardless of how I use them through a clean function. The clean function is responsible for removing quotes and cleaning up odd characters.

The function takes a variable, cleans it and returns it. If you use this code, please add your own steps to ensure protection of your data, this is a simplistic clean function. Below is some of the function:

function clean($value)
{
$value = trim($value);

$value = strip_tags($value);

$value = mysql_real_escape_string($value);

if (!get_magic_quotes_gpc())
{
$value = addslashes($value);
}

$value = rtrim($value);

return $value;
}
I use this function like so:

$sql = "Select * from user where username = '" . clean($username) . "' and password = '" . clean($password) . "';"
mysql_execute_query($sql);

Another Solution
The other step I take is that I have overwritten the mysql_query function so that it replaces my table names. I wanted to make it difficult for people to guess my table names, so I have the following function:
function executeQuery($sql)
{
$sql = str_replace("s_", "game_", $sql);
$q = mysql_query($sql) or die("SQL Error on $PHP_SELF: " . $sql);

return $q;
}
This replaces any s_ with game_, I might name my table "game_user" however my sql would be select * from s_user.

Hopefully this helps those who have questions about SQL Injection.

Friday, February 15

Battle Forces Online: Bounce Rates and Visits

Interesting .... Between Jan 15, 2008 and Feb 15, 2008.

Low Bounce Rates:
  • internetgames.org - 7 hits, 15% bounce rate
  • onlinegamesinn.com - 19 hits, 27% bounce rate
  • pbbblog.com - 7 hits, 29% bounce rate
  • onrpg.com - 37 hits, 30% bounce rate
  • forums.indiegamer.com - 97 hit, 62% bounce rate
Most Visits From

SQL Select Statements Kept Simple

This is a quick article on writing simple and complex select SQL statements. This primer can be used for mySQL and many other database systems. Please keep in mind this is a primer, please research and read other materials to enhance your knowledge.

For those of you who are wondering, mySQL is used in browser based game design quite often. However from some of the question I see posted in forums some developers don't quite understand the intracity of SQL.

Select Statement

The select statement is used to get information from the database. It consists of 3 parts. The Fields the tables and the where clause.
SELECT [TABLE].[FIELDS]
FROM [TABLE]
WHERE [TABLE].[FIELD] = [VALUE]
select user.email
from user
where user.username = 'mobeamer'
  • Fields - Can contain a list of fields that you want to select.
  • Table - will contain one, possibly more tables that hold the fields
  • Where - This will allow you to restrict the information you receive.
Notice that I surrounded mobeamer with quotes, this is needed for strings and is good practice for other data types. A good rule of thumb is when in doubt add quotes.

Notice that I fully qualified the fields by putting the table name in front of the field name. This is not needed when writing a simple select but it is considered good form AND it will come in handy when you decide to "upgrade" your SQL statement (see joins).

Inner Join


An inner join will allow you to pull information from multiple tables with one query. The syntax for an inner join is as follows:
SELECT [TABLE].[FIELDS]
FROM [TABLE]
INNER JOIN [TABLE] ON [TABLE].[FIELD] = [TABLE].[FIELD]
WHERE [TABLE].[FIELD] = [VALUE]
Let's say you have a user table which contains all the player's information. You also have a units table that contains all the units that a player can have. You need a select statement which will get the player's name and the unit's name. In this instance my unit table has a column called ownerID which holds the userID of the owner.
select user.username, unit.unitname
from user
inner join unit on unit.ownerID = user.userID
where user.username='mobeamer'
Another example:
select user.username, unit.unitname
from user
inner join unit on unit.ownerID = user.userID
where unit.class = 'Warrior'
In most cases your joining field will be named the same in both tables, but I wanted to show how this was not necessary.

Notice, that you must fully qualify fields that exists in both tables. You should be aware when using an inner join, as in the first example, if the user does NOT have any units they will NOT appear in the result set.

Be very careful with inner joins as they ALWAYS restrict the result set. (See outer joins)

Outer Join

An outer join works in the same fashion as an inner join with one exception. The join will NOT restrict the returned set For example, in the example above, a player may not have a unit. In this case, an inner join would not pick up that player's name. An outer join on the other hand would pickup this player.
select user.username, unit.unitname
from user
outer join unit on unit.ownerID = user.userID
where user.username='mobeamer'
This will get all user, regardless of how many units they have.

Notice, the first table in the select statment begins the result set. Every outer join from there on can only add rows or columns to the recordset.

A good rule of thumb is to always use an outer join as you will never lose data with an outer join.

How I do It

This is how I write a complicated sql statement, this may not be best practices but I think it may add some context.

I wanted to create a page, which displays a player's profile. I knew I needed a number of fields from the player's table, unit's table and item's table. (Items are things that the unit holds)

I knew I wanted to display all players that had registered, so I started there.
Select user.username, user.numKills
from user
where user.isRegistered = 'Y'
I then wanted to display the unit's name, class and life
Select user.username
, user.numKills
, unit.unitName
, unit.class
, unit.life
from user
left outer join unit on unit.ownerID = user.userID
where user.isRegistered = 'Y'
I then wanted to display all the items that the unit held, and the item's description
Select user.username
, user.numKills
, unit.unitName
, unit.class
, unit.life
, item.itemName
, item.itemDescription
from user
left outer join unit on unit.ownerID = user.userID
left outer join item on item.unitID = unit.unitID
where user.isRegistered = 'Y'

This was the sql that I ended with.

Further Articles
Good ideas to follow this up with:
  • Updates, Inserts and Deletes
  • Restricting an inner or outer join
  • Links and Resources

Wednesday, February 13

Conversions...

Why won't they Play my Game?

I've been researching how to convert users for my browser based game Battle Forces Online. Well the first thing I had to do was to deiced what a "conversion" meant. After much labor and hard thought (30 to 40 seconds) I came to the brilliant conclusion that there are 3 different things I want from players.

Players
I want players to hit my landing page and start playing the game. I consider a user who creates an account and adds a Blade to the battle field. I consider these my players.

Voters
In order to generate more players, I need players to vote on one or more listing sites. This seems to drive more users then any other action that I can do. This is a sort of secondary conversion as this can not be done by a user, but can be done by a player (person with an account).

Buyers
The hardest sell. There is/will be an upgrade feature which will allow players to purchase items within the game. A conversion would be getting a player to buy this item.

In my next post, I will follow up with how I can make modifications to my landing page to facilitate these conversions.

So How can I optimize the Landing Page

Large Images
Large images placed in the center of the page that contrast with the background draw the eye. Currently I have a large image that spans 75% of the landing page, I am going to restrucutre this to have the "Play Now" button in the middle of the page.

Contact Information
Potential players are much more comfortable when they know they can contact the developer or support team for the game. Since this is the case, I will add a send message form where users can send me a message and I get it via email.

Screenshots

Potential players love screenshots as do reviewers. I have screenshots on the page so I will keep them, however I must remember to not let them overshadow the "Play Now" button.

Registering
Registration should be as simple and as accessible as possible. I think I will add both a login and a register form to the entrance page.

Headline

Users will read the first headline on your page 90% of the time...what is mine?

Tracking
In order to test these changes, I plan on creating a folder called "Landing", I will then figure out which of the landing pages convert the best.

KISS
Keep it as simple as possible, classy but simple.

Interesting Items to Follow Up With:
  • How to convert players to payers


Tuesday, February 12

Development Environment

A lot of people ask how they can start/learn to develop browser based game, hopefully this article will help get them started. This article may be helpful to developers who are struggling to make changes / develop games without disturbing the production version.

The development environment comes into play for both these circumstances. There are a number of ways to setup your development environment. The solution is both short and sweet.

Please keep in mind this is only good for development teams of 1 or 2 individuals, you will need to do much more if your team consists of 3+ developers/coders.

I tend to use Uniform Server (http://www.uniformserver.com) as my environment. It’s a simple download you unzip and click a “start” executable. Yes, this is a Windows solution however, there are a number of alternative solutions, just search for LAMP on google.

It runs Apache, mySQL and PHP with a number of utilities. The great part is it’s less then 2GB so it fits on a flash drive, this means you can work on any windows, anywhere.

I use that to develop on my local machine. Once I am ready, I ftp my changed files to the site. (After making the database changes)

Every so often I will download the entire site from production and over write my development file. This helps keep my local version from getting to far from the production version.

Battle Forces Online - Major Re-vision

Battle Forces Online has gone through a large change.

I decided to keep the "game" a bit simpler and see what happened. I'd like to outline what I am thinking at this point.

I wanted to address the fact that a lot of users would enter the game and not know what to do. In the old system, you had to deploy and setup an army, this allows you to join a battle in progress.

Players now join the game and see a map, which all players share. They then can add their own units (Blades) by starting a "New Adventure". I also added a Tutorial hopefully this will help.

Players have the ability to add as many of their Blades to the board as they would like. However, once added a Blade can not be removed from the board.

The goal of the game is pretty simple, as you gain more coins you can hire more Blades which allows you to further control the board.

Some things I'd like to develop in the near future:
  • Multiple Worlds
  • Ability to buy items for Blades
  • Guilds
  • Challenges
  • Towns

Followers