2014/08/01

Loading Animations and Staggering Asset Creation

Original article in the TGC Newsletter can be viewed here.
agk mastery
In our last game, Shape Time, I ended up deciding to load quite a few assets at launch time. I implemented a loading animation, but it seemed to actually slow down the loading process a bit. In our next game I wanted to optimize this as much as possible to improve loading time. The reason the loading animation was affecting the speed of loading assets was that I was calling Sync() as frequently as possible so that the animation would update. Here's an example how it was done (the loading animation in this case is a sprite with frames):

for num = 1 to 10
 fileName$ = “atlas” + str(num) + “.png”
 LoadImage(i , fileName$)
 Sync()
next num

Loading...
This would certainly animate the loading sprite just fine, but I knew there had to be a better, more universal way. The problem is that Sync() is limited by the frame rate of the device. So if you've got a device that is capable of only 30FPS (fairly common in with mobile devices) then you are limiting your loading sequence to one file every 30th of a second. This is not that bad for files, but if you want to display the animation while other, possibly faster processes take place, then you're likely slowing them down. 
Let's look at an example of a script that might be slowed by a Sync() call:

for num = 1 to 100
 if num = 1
  img = LoadImage(“yourImage.png”)
  CreateSprite(num , img)
  SetSpriteSize(num , 10 , -1)
  SetSpriteDepth(num , 100)
 else
  CloneSprite(num , 1)
 endif
 SetSpritePosition(random(0,90) , random(0,90))
next num

This script is pretty fast, but it might take up to a second or more on mobile devices. If we add a Sync() call to this routine so we can show a loading animation then the routine will be much slower because the Sync() call will render the screen and limit the engine to whatever the available FPS is. At 30FPS this script would require 3.33 seconds to run. Without Sync() it may take considerably less time, however, that would be dependent the device.
So how do we speed this up? The answer is to only call Sync() only when it is time that you expect to have a frame drawn to the screen. The example below uses a literal 1/60 of a second between Sync() calls. There are more advance ways to determine the expected time to call Sync(), but this is sufficient for showing a loading animation. The example simply rotates a loading image for simplicity.

global gLoading = 0
global gLoading_LastSync# = 0.0 
function ToggleLoadingAnim(iOnOff)
    if GetSpriteExists(gLoading) = 0
        gLoading = LoadSprite(“loading.png”)
        SetSpriteSize(gLoading , 10  , -1)
 SetSpriteDepth(gLoading , 1)
    endif
    if iOnOff = 1
        SetSpritePositionByOffset(gLoading , 50 , 50)
        gLoading_LastSync# = 0.0
    else
        SetSpritePositionByOffset(gLoading , -500 , -500)
    endif
endfunction 
function LoadingAnim_Sync()
    time_now# = timer()
    dT# = time_now# - gLoading_LastSync#
    if dT# > 0.017
        ft# = GetFrameTime()
        gLoading_LastSync# = time_now#
        t# = 3.0
        angle# = GetSpriteAngle(gLoading) + 360.0 * ft# / t#
        angle_int = round(angle#)
        angle_int = mod(angle_int , 360)
        SetSpriteAngle(gLoading , angle_int)
        Sync()
    endif
endfunction

The code consists of 2 globals and 2 simple functions. ToggleLoadingAnim() is used to set up the sprite and globals, position the sprite, and make it visible. This should be called before any loop that you want to overlay the loading animation on. You also call this to hide the animation. Inside of the loop you will use LoadingAnim_Sync() in place of a standard Sync() call. So our original code that loaded 100 sprites becomes this:

ToggleLoadingAnim(1)
for num = 1 to 100
 if num = 1
  img = LoadImage(“yourImage.png”)
  CreateSprite(num , img)
  SetSpriteSize(num , 10 , -1)
  SetSpriteDepth(num , 100)
 else
  CloneSprite(num , 1)
 endif
 SetSpritePosition(random(0,90) , random(0,90))
 LoadingAnim_Sync()
next num
ToggleLoadingAnim(0)

That's it! Now you can load up lots of assets and have a nice loading animation so that the user doesn't wonder what's going on. Remember, folks don't like to wait even a second for something to happen these days, so make sure to use a method like this to let them know your game is still running. Now if we could only thread the loading animation so that we can draw to the screen while loading large files. Another thing you might want to consider is that you might get large values out of GetFrameTime() while loading files. So you might want to limit the ft# variable when you're translating a sprite (moving or rotating). Either way you'll get a bit of jitter in your sprite's translation because Sync() just can't be called fast enough due to the time it took to load a file. 
Users don't want to wait long for your game to load, so it's important to only load at launch time the assets you need to display the title screen / main menu of your game. After that you can stagger the creation of assets by creating only a handful every frame and then if they aren't all loaded when they're actually needed, you can finish up loading them and show a loading animation. In our next game I did this for our level selection menu. 
The level selection menu needed 200 buttons, 3 star sprites for each button, and 2 text objects for each button – that's a total of 800 sprites and 400 text objects! This was just way too slow to load on demand. So what I did is create a handful of these objects every frame during the Sync() calls. This way the buttons could be loaded while the player is looking at the main menu which incorporates a short animation of about 2 seconds. Let's examine how we can do something like this.
Make an array that will hold the object IDs for the level buttons and a global to hold an image ID:

#constant LVL_BTN_COUNT 200
dim _lvl_btns[LVL_BTN_COUNT]
_lvl_btns[0] = 0
global gLvlBtnImg as integer

Create a new function that includes the Sync() command and will create a handful of objects each frame:

function LvlBtn_Sync()
 //we'll store the count of created objects here
 count = _lvl_btns[0]
 if count < LVL_BTN_COUNT
  skip_objects = 0
  if GetImageExists(gLvlBtnImg) = 0
   gLvlBtnImg = LoadImage(“mybutton.png”)
   //since we're loading an image this frame
   //let's not make any sprites or text
   skip_objects = 1
  endif
    if skip_objects = 0
   baseSprite = _lvl_btns[1]
   needBaseSprite = 0
   if GetSpriteExists(baseSprite) = 0
    needBaseSprite = 1
    endif
   for i = 1 to 10
      if needBaseSprite = 1
    needBaseSprite = 0
    thisSprite = CreateSprite(gLvlBtnImg)
    SetSpriteSize(thisSprite , 10 , 5)
    SetSpritePosition(thisSprite , -1000 , -1000)
    SetSpriteDepth(thisSprite , 10)
   else
    thisSprite = CloneSprite(baseSprite)
   endif
   _lvl_btns[count] = thisSprite
   inc _lvl_btns[0]
  next i 
  endif
 endif
 Sync()
endfunction

Now we're creating those 200 sprites in 20 frames. At 30FPS we'll have created them in less than 1 second! They should all be prepared by the time we need to show the level selection menu, but just in case, you should also have a catch that ensures they're all created when the user goes to access the level selection screen. If they aren't all made then you can show the loading animation to tell the user the app is working on something.
This method can be used in a variety of ways. For example, while the user is playing one level you can slowly start loading the assets for the next level in each frame. This should be done with care so that it doesn't drag down performance when the action of the game is happening. As long as the sprites are off-screen they won't be rendered and won't cause a drag on the engine.
Next time I'll discuss methods on how to “thread” animations in a loop so that you can easily contain different animations in separate functions. Oftentimes we need to have a lot of things going on simultaneously and they cannot interrupt each other or user input. Thanks for reading!

2014/07/04

App usage analytics and a postmortem of Shape Time

Originally published in the TGC Newsletter - July 1, 2014

agk mastery

App usage analytics and a postmortem of Shape Time

So, you've got what you think is a great idea for a game. You've put it together, people on your development team and beta testers have enjoyed it. Other than a simple download count, how do you know if others are enjoying it (or not)? Players don't often leave feedback unless they really like or really dislike your game. So how do we get information about the majority of people playing our game? Are people playing 10 levels and then hitting a wall which they aren't interested in attempting to pass? App usage analytics are key to finding this information. 

Analysis
With our most recent game, Shape Time, we thought we were doing so much right. We really liked the simple, minimalistic graphics (following in the style of Dots and Threes!, the gameplay was very challenging as we intended, the mechanics worked well, and the game tested very well with a small beta group (about a dozen people). 

After launch our very first review on the Play Store was bad. We implemented an “energy” mechanic where you only had 5 lives and after using them up would have to wait 15 minutes for a new one. This didn't go over well. Although we planned it out as best as possible, it just seemed the game didn't have enough flare to justify this mechanic. 

We watched our app data and saw that so many players were getting very low points. In beta testing we estimated that 75 points was low enough for the first badge reward. After launch most players were maxing out at about half of this. This indicates to us that the gameplay mechanic may be too challenging for users. Also we could tell that they only ran the game a handful of times. What this means is that the game just isn't compelling enough and when they run out of lives they just never come back.

We had a few professional reviews that were good, but didn't go into great depth. Eventually we received an in-depth review that was quite unfavorable. It pointed out many of the issues that the data was pointing to: The gameplay mechanic was too difficult, the graphics impressed low quality instead of minimalistic style, the in app purchases were too unfavorable. So we had to act and are now giving the game a fairly thorough overhaul to try and save what we think is a good game.

How did we get all of this data and what data did we track?

ShapeTime
We used simple HTTP commands in AGK to send off data to our server whenever certain conditions would happen in the game. In previous articles I've discussed how to set up leaderboards as well as send files from your app to a server. The same method for leaderboards is what is used to send app usage data to a server. There's just more data to send! With Shape Time we use two different database tables. One table contains data for each game session. The other table contains overall statistics for each user. Both tables share a user ID for each player so that they can easily be cross referenced in reports. Each time a player completes a game session or makes a purchase, we then send data off to the server. If you are not expecting feedback from the server then you can just send out the data with an async HTTP command (we did this with purchases). If you are waiting for data back then still use the async HTTP command, but wait for the data to return as was illustrated in the leaderboards tutorial. We do this for all the session data because we are also checking for a high score at the same time.

The data we tracked was straightforward. For sessions we wanted to know how long each game lasted, how many powerups were used, and what the score was. For users we wanted to know how many sessions they had played, their high score, their purchases, and their general geographic location (country and region). The information that can be inferred from just this simple data is great.  Geographic information lets us know if non-english speaking players are having a greater difficulty playing the game (this was not our case). Most importantly we could see that players on average were only getting a high score of around 25 points. Only 17% of our players were actually using the powerups (the game has explanations of these when they are first rewarded). We could see the average game session time was only about 2 minutes which was much lower than the beta test group.

The data was so disappointing that we were likely going to abandon the game and call it a loss. We tested it out well, we liked the mechanics, we knew that the high scores achieved in-house and by beta testers were achievable (my wife still has the all time high score of 182 points with very few players even coming close – my best is 129), we liked the music and graphics. Therefore we were ready to call it a loss until we received a brutally honest professional review. 

The review pointed out what the data was telling us and it also gave us hope. It made suggestions on how we could improve the game. After matching that information up to the data we feel that Shape Time could still possibly be a success. 

The gameplay mechanics were possibly too challenging: it is possible that the way the bar moves in the game (it snaps to the closest edge) is an extra challenge for players to overcome. Though beta testers were quite comfortable with it after a play or two we can understand how the snapping may actually feel more like a restriction and hindrance than assistance as it was meant to be. The snapping feature is now optional and we're allowing for more margin of error in matching the shapes up with the bar.
The minimalistic style was viewed as too basic and lacking depth. When designing the game we thought it would be best to keep it free of extra distractions. This meant we wanted things to look flat and simple and at the same time we didn't want a lot of special effects going on. Unfortunately this ended up being interpreted as plain and boring. We're now adding a lot more style to the game and are learning that we really need to spend a lot of time on making the graphics flashy. The graphics style will now be a crayon drawing style with the elements looking like construction paper cutouts. We're adding some characters to the game (the brush and clock powerup icons will now be cartoon characters) and giving them animations. We're also adding particle animations to give the game greater flare and interest.
The life restriction mechanic and power up rewarding were unfortunately too restrictive. We hoped the game was interesting and addictive enough to justify in app purchases to help lift these restrictions, but it is not. The game will no longer have any restriction on game play and powerups will be rewarded much more generously. We've removed all in-app purchases except for ad removal (we need some mechanic for monetization!).

Beyond challenging, but rewarding, gameplay

What is it that makes some games such a huge success? What makes a game addictive? We should have realized this sooner, but didn't. 


Games that have characters in them are much larger successes than ones that don't. Candy Crush Saga, Clash of Clans, Temple Run, Flappy Bird, and even Threes! (the tiles have little faces on them) all use characters in the games. Characters can be extremely important because they immediately evoke an emotional response. A smile on a character's face is immediately recognized by our brains and sets off endorphins. Make the characters cute and happy and most people will automatically have a good response to them. This puts them in the mood to have fun. The brain essentially says “There's something happy. I'm going to share in its good time.”

People are accustomed to high levels of stimulus. Watch any recent children's movies, the stimulus level is very high. The most successful movies like Godzilla, Iron Man, etc. also have a high level of stimulus. Play Candy Crush Saga for a bit, the stimulus level is also extremely high. There are a lot of very minor animations (flare effects, characters moving slightly) occurring alongside the major animations (candy movement, row/column clearing). When you perform a good action such as clearing a row of candy there is an explosion of stimuli on the screen.
Sparkle
This heightens the player's emotional state and leaves them wanting more. There is a difficult balance to achieve between stimulating animations and overload. I think the main key here is that you can actually have a lot of very minor animations like particle effects and animations that don't actually change the shape of sprites (Crayon Physics has a neat stop-motion style animation on a lot of things). Most of these things we don't actively pay attention to in games, but they heighten the brain's awareness which makes people more susceptible to rewards and punishments. Try tuning off the TV on a kid when they are watching a cartoon and you can see this effect in action. Make sure to reward players often and provide a lot of stimulus with rewards. Remember you're competing for their emotions.

Once your players have an emotional attachment to a game you can then start introducing mechanics that will force them to make a choice: keep playing or quit. If you're able to create a strong enough of an attachment so that they want (and feel they need) to keep playing then and only then do you have a chance at asking them for money. This is really difficult to do. Many players are immediately turned off by this mechanic and the reason is that they haven't attained enough of an attachment to make it worthwhile. So do this with extreme caution. Also keep in mind that the majority of your players will not purchase anything until they have played many times. So if you do have some restrictive element in your game you need to do a great job of making them want to return. Unfortunately we did not do this with Shape Time and we don't really see it as a possibility in the future with a game that has such short gameplay.

App usage analytics, even the most basic ones, can be a great learning tool to help you understand how to make better games when there is an absence of user feedback. Even successful games should make use of analytics (indeed the most successful do). Analytics provides us with a way to learn what our users are doing when the majority of them are silent. Games need to provide a high level of stimulus to be considered entertaining enough to get players to come back for more. Follow the leaders and don't just emulate their game mechanics, but also look closely at the little things they do in games. These are often unnoticeable, but aggregate into a great user experience. Don't be afraid of failure. No one succeeds on their first attempts. Success even on the 10th attempt is extremely good luck. Failure can be great because it gives you the opportunity to learn. Leverage it for all it is worth. 

I'd love to hear your feedback on the new version of Shape Time. We will announce the release in the Showcase forum as soon as it is ready. Thanks for reading!

2014/06/16

AGK Tutorial - App Data

Originally published in the TGC Newsletter - June 1, 2014
agk mastery

The question of transferring data from your mobile app to a server was brought up by Parry on the AGK forums and I thought I'd share my process for getting app data from a device. The problem is that Android and iOS put app data in a protected folder on the device. If you want to root or jailbreak the device it is easy to get at, but this process can be dangerous and complex. If you just need a peek at your app's data then there is an easier way: add all of the files to a ZIP file and send it to a server.

Setup

To start you'll need a server. You can use your hosted account or a server of your own. If you're on Windows I highly suggest using XAMPP. The setup is quick and they provide ample information on how to get things going (like allowing outside connections to your server). The next thing you'll want to do is set up some PHP code on the server to accept files as well as the code in AGK to send the files. 

AGK code for sending file:
fileID = OpenToWrite("test.txt" , 0)
WriteLine(fileID , "this is a test")
CloseFile(fileID)
cid = CreateHTTPConnection()
SetHTTPHost(cid, "1.1.1.1" , 0) 
SendHTTPFile(cid , "uploadfile.php" , "" , "test.txt")
SetPrintSize(1)
repeat
    if GetHTTPResponseReady( cid ) = 1
        print (GetHTTPResponse( cid ))
    else
        print ( GetHTTPFileProgress( cid ))
    endif
    Sync()
until done = 1
CloseHTTPConnection(cid)
DeleteHTTPConnection(cid)
END
Ensure that the IP Address 1.1.1.1 is replaced with your own IP address or domain (do not include HTTP://).

PHP code for receiving file:
<?PHP
if ($_FILES["myfile"]["error"] > 0){
        echo "Error: " . $_FILES["myfile"]["error"] . "\n";
}
else {
    echo "Upload: " . $_FILES["myfile"]["name"] . "\n";
    echo "Type: " . $_FILES["myfile"]["type"] . "\n";
    echo "Size: " . ($_FILES["myfile"]["size"] / 1024) . " Kb\n";
    echo "Stored in: " . $_FILES["myfile"]["tmp_name"] . " \n";  
    if (file_exists("upload/" . $_FILES["myfile"]["name"]))
    {
        echo $_FILES["myfile"]["name"] . " already exists. \n\n";
    }
    else
    {
        move_uploaded_file($_FILES["myfile"]["tmp_name"], "upload/" . $_FILES["myfile"]["name"]);
        echo "Stored in: " . "upload/" . $_FILES["myfile"]["name"] . " \n\n";
    }
}
?> 

It's as simple as that. Just make sure that the "upload" directory is created on your server before trying to send the file. Now that you have all of that set up and tested we're on to a simple set of code that will get all of the files out of your app's directory:

AGK Code:
function ZipDirectory(sZipFileName$)
 if GetFileExists(sZipFileName$) = 1
  DeleteFile(sZipFileName$)  endif
 doOnce = 0
 makeZip = 0
 repeat
  if doOnce = 0
   doOnce = 1
   thisFile$ = GetFirstFile()
  else
   thisFile$ = GetNextFile()
  endif
  if thisFile$ = “”
   done = 1
  else
   if makeZip = 0
    makeZip = 1
    zipFileID = CreateZip(sZipFileName$)
   endif
   if GetFileExists(thisFile$) = 1
    zipLocation$ = GetFolder() + “/” + thisFile$
    AddZipEntry( zipFileID , thisFile$ ,  zipLocation$)
   endif
  endif
 until done = 1
 if zipFileID > 0
  CloseZip(zipFileID)
 endif
endfunction
As you may imagine you can also do this for every directory and subdirectory for you app's media folder. It is important to note that the directory you are working with is the write directory for the AGK app and not the read directory. The read directory for apps is where all of the media files exist that you package in with your app. On Android and iOS you do not have access to this directory without rooting/jailbreaking the device. This shouldn't matter because these files are the same that you packed with the app and you already have those. The write directory is a “sandbox” area where the app is allowed to write data. This is where any file you create with the app will be stored such as data files, debug logs, etc. 
This method is extremely helpful when developing your app and when it is actually live. When developing your app you can use this to zip up any debug logs and quickly send them to yourself. When the app is live this can be used to send error reports to you when the user experiences issues. In Wordspionage we use this to send error logs whenever a fatal error occurs. This was extremely helpful in the first few months of our release because a few bugs appeared that did not appear in our extensive beta testing. It allowed us to receive data from our users automatically so they didn't need to be bothered or actually need to hit a button to send the report. When these error reports are sent to us they also include a screen shot of the game so we can see any visual clues to the issue. This method was paramount to smoothing out the flaws in the game.

2014/04/01

AGK Tutorial - Online High Score System

Originally published in the TGC Newsletter - April, 2014

In concert with the current competition to make an addictive game, we thought it might be a good idea to show how to set up an online scoring system. This tutorial will make use of AGK Tier 1 BASIC, PHP, and MySQL. You will need access to a server with PHP and MySQL capabilities.

To start, if you don't already have a server set up, you can install XAMPP (www.apachefriends.org) to your local PC. This could be used as your server, but you will need to allow access to outside networks which can be dangerous without the proper knowledge of security. I do suggest that you use XAMPP for testing before going to a live server. 

The database

After you have XAMPP set up you'll need to create a database and table for the highscores to be recorded in. For this tutorial let's call the database "high_scores" and the table will be "my_game". You'll also need to create a user for the database who has access to selecting (searching), and inserting the row. The table will need the following columns as a minimum:
  • PID - the primary index for the database and set to auto increment. 
  • NAME - this is where you'll store the user's name. I'd suggest limiting it to 12 characters or less and making this column a VARCHAR(13) type. The 13 is the maximum string length (12) plus 1.
  • SCORE - an integer
  • DATE - Type is TIMESTAMP and I like to use the "current date on update" feature so that whenever a new score is entered you know the date of entry.
Another thing about the database is that you might want to clean it up every so often to delete scores that are below the top 10 high scores. You can either automate this process or do it manually. The database should be fairly lightweight so it really won't need to be done often.

The PHP Scripts 

Now we've got the database all set up let's take a look at a simple PHP script that will allow your app to send data to the database. We'll call this script "scores.php". Because the code inthese examples is substantial, theyhave been extracted into text files for you to view and also to copy to your own implementation.

Note that this script checks that the score is a new high score and inserts it into the database at the same time. For a live application you might want to split this into two scripts: One that will initially check to see if the player's score is a high score and then report back to the app. The app will then ask for the player's name. Then finally you'd use the above script to insert the new high score. You'll also want to put scripts like this into a protected directory on your server so that they cannot be abused. You can also add other mechanisms to the script to check for unreasonable scores.

Sending the Data 

For the next part we'll examine how to send this data from your AGK app to the server. Here I'm assuming that you have placed the PHP script in a protected directory as I've suggested. For this example, the protected directory is called "myProtectedDirectory", the user for that directory is "myUserName" and the password is "myPassword".


The above function is a very basic framework and will need you to add in user interface elements and what to do when the different events (high score is good, not a high score, and error) occur. 

Retrieving the Scores 

Next let's take a look at how to get the high score data back to the application.
Create a PHP script called "getscores.php" with the following contents:



Back in AGK we will be able to fetch this string and output it with the following function. I used Chr(10) to separate each row by a new line which will allow it to be displayed easily in a Message() window. You may want to use something different and implement AGK's GetStringToken() function to parse the data to your needs.



Get your Game Scores Online
Notice that the function GetHighScores() is very similar to SendScore(). If you plan to use HTTP connections in your program, you'll likely want to separate out the first 21 lines of those two functions into their own function. The GetHighScore() function is very basic and needs a bit of polish before it is ready to be used in a game, but it serves its purpose for this tutorial. Another item you may want to consider is what to do when a player might have more than 1 high score in the top ten. On old arcade games this would likely just allow them to have multiple entries on the list which might allow them to dominate the list. Instead you might want to first check the database for that user's name and then only update their score if they beat their last high score. Another consideration to make is whether you want to censor user name entry. Since the list is public you probably don't want a bunch of vulgar names showing up on the list. Ban builder is a very simple and easy to set up filter that will allow you to censor name input. It takes less than 5 minutes to set up. Also make sure to look over the word list before making it live because there are words like "hell" in there that might be a part of someone's name like "shelly".

Although the easiest and safest way to maintain an online high score system is to use your own server, there is at least one free alternative that I know of: Google Docs. With Google Forms you can set up a form that will allow you to pass data to it via a post method which will store the data in a Google Spreadsheet. You can then turn around and query that spreadsheet via a URL. An example of querying by URL is given here. To send data to a Google Form via post you'll need to create a form and then determine the form's key and closely examine the source for it to to find the names of the post variables. The response from the query will be a json string which means that you'll need to do a bit of parsing to get at the data you need. While Google docs is an alternative to having your own server, it is likely a bit more work to get it up and going. It may also be subject to abuse by users if they are able to gain your spreadsheet's access key. 

There are also some cheap servers out there that you can get. Digital Awakening on the forums brought One.com to my attention. Right now it appears that they're offering one year free which includes a domain registration plus a small setup fee. Quite worth it if you're just looking for a small server to handle things like scoreboards. Phaelax from the forums has also made a free online high score system available to all here.

2014/03/01

The Making of a Word Game

Originally published in the TGC Newsletter March 2014

There are many grid-based word games on the market at present, with other popular titles such as Words With Friends,Word Feud, Wordz Up and many more. Sean Mann of Napland Games gives us an insight on the makings of such an application.

Word lists

Wordspionage
All word games need a qualified word list. There are many free lists out there and the best public domain list is ENABLE (Enhanced North American Benchmark LExicon) available from the Google Project site
This list contains some 170,000 words and is widely accepted as one of the best. It did need some minor modifications to be ready for use in a game. For example, we removed all single letter words since you have to play at least 2 letters and we removed all words longer than 15 letters since the board is 15x15 tiles. We also removed any words which have a purely vulgar meaning as we felt that they were inappropriate for a game designed for all ages. We also added all of the commonly accepted 2-letter words from other games. 


The list also had to go through some modification so that it could be accessed in an optimal way. A word list of 170,000 words can be a bit cumbersome to search. If the list was stored on the device it would be very slow. We stored the list in our MySQL database on our server which is very fast for searches, but still the list was split into multiple small tables so that search time would never take long (indeed it takes 0.0019 seconds to search our largest list). The way we split up the lists is straight-forward. There is a list for every letter and word length combination (i.e. all words beginning with A and 2 letters long, A and 3 letters, A and 4 letters, etc.). To accomplish this I created a simple program that parsed the big word list and simply saved it into smaller text files. It created quite a few text files (about 26 * 14) but they were easy to mass import to a MySQL database.

Protecting the data One thing to look out for when importing is that text files have characters for new lines and these can get stored in your database, which potentially can cause searching issues. Another major advantage of having the list stored on a server is we can add and remove words on demand. We've already had a number of users request additional words and have added some of them to our dictionary immediately. Leveraging an online database to control elements in your game is very useful. We can also send out news messages to our players from our online database and lock out obsolete versions of the game if we ever need to.


Since our word lists are stored in our protected database online, we didn't have to worry about users potentially modifying the files. If you plan to store your files within the app you should consider your own method of encryption and validation to ensure that users haven't modified the files. One of my favorite methods is simply storing a key in an array for your program and using that key along with XOR to encrypt/decrypt the bytes in a data file.
This method made the basics of verifying a word to our dictionary very quick and simple. The more difficult part was verifying the words on the board since you have to take into consideration the various possible crosswords. The idea behind the algorithm for doing this is quite simple, but implementation was a bit tricky. Simply determine the upper-most, left-most letter that has been placed on the board and look left, right, up, and down for other unplayed letters or played letters. 

I hope this gives a brief insight into Word Games and inspires you to think about making your own in the near future.

2013/04/29

Preparing for Game 2 - Learning PHP and MySQL

In order for my next game to be able to save user data and transfer data for turns and chat I'll need to set up a server and learn how to get data on and off it vial simple HTTP commands. I began my adventure today and will chronicle what I've done so others can easily set up a test system. I feel that what I'm trying to do is so basic (send data to be written to a database and retrieve that data)

First thing's first, set up Apache Server. This was pretty easy: download the ZIP for Apache 2.0, extract the files to the directory of your choice (I chose c:/Apache), make a few minor changes to its config file, and then just open up some ports on your router and unblock them from your firewall. That's it! I had this part of the project going before noon today and was pretty happy with the information I was able to find.

There are a ton of guides out there on how to set up Apache server (2.0 Win32) in Windows, so I'm not going into great detail here. One thing I should mention is that you should be careful with security. If you're just testing an app then shut down your server when not testing. Once the server is installed you should see an icon in your taskbar's icon try (tiny up arrow over by the clock). Left clicking on this will allow you to quickly start/stop/restart the server.

After you've downloaded the ZIP for Apache server 2.0 for win32 x86 and extract it to the directory of your choice you can start meddling with the configuration file. It's called httpd.conf and located in the Apache/conf folder. Simply open it up with Notepad and make the following changes:

  • Find thisServerName localhost:80 and replace localhost with whatever name you want. This will be the name you type into your browser on the server computer to check things as you set them up. I left mine alone.
  • You also might want to change this ServerAdmin admin@localdomain to whatever email address you might want to use. Again I left this alone as my server won't need email functionality.
  • If you don't want to use the default directory for you website's files then change the DocumentRoot "C:/Apache/Apache2/htdocs" to the directory of your choice.
  • Change the line DirectoryIndex index.html to also include index.php - we'll use that later after we set up PHP.
  • Next we'll want to set up a password. This is done by going to the Apache/bin directory then hold shit and right click in a blank area of the Windows Explorer window and "Open Command Window Here" for a command prompt. Type htpasswd -c "c:/Apache/Apache2/pw.txt" yourName. Replace the directory with your actual directory and replace yourName with whatever name you want for the admin account. You'll then be prompted to create a password and you're done.
  • Now we need to create a script to manage the login. Create a file in Notepad and name it .htaccess then enter the following:
AuthType Basic
AuthName "This is a private area, please log in" 

AuthUserFile "c:/Apache/Apache2/pw.txt"
AuthGroupFile /dev/null 

<Limit GET POST PUT>
require valid-user
</Limit>
  • Restart Apache server and then open a browser and enter localhost if all went well you should be prompted to enter your username and password. If you didn't create any index.html or index.php yet then you won't see anything else, so go ahead and create that if you want.
  • Now you're going to want to set this up so that you can access it via the web so open up your router's settings and port forward port 80 for the IP address of your server. Then set your server's IP to be in the DMZ (usually under WAN setup).  You may also want to make sure the computer you're using as a server has a fixed IP on the network and the address has been reserved on the router. 
  • Finally you'll want to open up your firewall and add an exception for two-way traffic on port 80. Now you should be able to go to any computer on the internet and login to see your website.
That's all it takes. Many other guides I see have a bit more detail, but they seem like they expect you don't know much about changing your router settings or how to navigate Windows Explorer to find files. I hope that this guide is a bit more to-the-point and helps the slightly advanced user get up and running quickly. If you're stuck on any point you might want to search Google for a more detailed guide. For many I hope this will get you up and running in a jiffy.

Next up is setting up PHP and then MySQL. Thanks for reading, see you next time!