For this week’s iDevBlogADay post, I’m going to explain how I implemented sharing of user solutions in Trainyard, my iPhone game. If you don’t know what Trainyard is or how it works, you can check out the trailer here. This isn’t really meant to be a tutorial, but rather just an overview of my approach to sharing solutions.
Why share solutions?
Trainyard is a puzzle game with tons of ways to solve each puzzle, so a sharing system gives players a way to show off their unique and interesting solutions. A somewhat similar approach could be taken with a different kind of game, such as replays in a racing game. Sharing is also a great tool to help spread the word about your game through Twitter and Facebook. High scores are cool, but it’s way more awesome to see a high score and see how it was accomplished. Sharing also gives you a great way to see how people are using your game. I love looking through user solutions for Trainyard.
What do you do on the iPhone?
Whenever a player presses the “SHARE SOLUTION” button, I immediately submit the solution to the backend on trainyard.ca. Submitting the solution involves a few steps. Every Trainyard puzzle and solution can be turned into a short custom-encoded string that looks something like this: ‘hh002Oja3Giaa00_003QQQ00′. I encode the solution’s short string and submit it along with the device’s UDID to the backend. I also create a flattened image of the solution and resize it to a couple different sizes (full size, half size, and thumbnail size), and send that along as well. I decided to do the image resizing on the iPhone to keep the server from doing too much work.
After a solution has been shared, I show the user the url and let them share it on Twitter and Facebook. I also let them choose their display name on trainyard.ca. I didn’t want them to have to create a full account with username and password, so I just associate names with UDIDs instead.
What do you do on the backend?
The backend for Trainyard is written in PHP and it’s running on Dreamhost, which has held up well consider there have been over 4500 solutions submitted. When a solution is submitted, I give it a link-shortener style id like “2fx” (as in http://trainyard.ca/2fx). I wrote a special little encoder for the ids so that they always start with a number and there are no similar characters like 1 and l and I. I wanted it to be easy to type the url in manually.
When solutions are submitted I store the flattened image of them and insert their data into the db. This includes basic info, such as the user who stored it, and more interesting stuff, like the number of track pieces used and the amount of “journey time” it takes to be solved. Every solution is associated with a puzzle, and each puzzle is part of a “city” of puzzles.
What do you do on the web?
You can see what the solution sharing section of site looks here: http://trainyard.ca/solutions. I wrote all the css and html, which was kind of painful, because I haven’t done it in a while, and I wrote an .htaccess file that turns everything into nice clean links like this http://www.trainyard.ca/solutions/laserMaster, so it’s easy to find other pages and to know what you’re looking at. There are pages that list all of the solutions by city, by user, and by puzzle, and there’s also a list of the 25 most recent solutions.
When you’re on the page of a specific solution, you can see eight other solutions for that puzzle and eight other solutions by that user. It’ll also show you if someone else has solved the puzzle the same way, which is pretty rare, except for here: http://www.trainyard.ca/3
How do you show solutions?
This is where the magic happens. Trainyard was originally prototyped as a Flash game, and I actually wrote a fully working version of the engine in Flash before I ever wrote any Objective-C. Once I saw the App Store market growing exponentially, I realized the game would be a perfect fit for the iPhone’s touch screen, so I targeted the App Store instead. Despite not releasing the full game in Flash, I knew I could use the engine code and create a Trainyard web-player instead.
Using an interactive web player has several advantages to a video player. Firstly, the file size is quite small. The SWF is around 200kb, and it only has to be downloaded and cached by the browser once, no matter how many solutions are viewed. Secondly, I can let the user control the speed of the solution, which is a necessary feature for some Trainyard solutions. The main disadvantage is that the viewer can’t be seen on an iOS device. To overcome that last drawback, I use SWFObject to check for Flash compatibility, and if Flash isn’t available, I show an image of the solution instead.
Hopefully this post has given you a good idea of how Trainyard’s solution sharing works. Please post a comment or message me on Twitter if you have any questions or thoughts. I’d love to find out how other people approached similar issues in their own projects.