Gamieon is a privately owned entertainment software development company located in Tampa, Florida. Since October of 2004, we have aimed to provide quality video game software which emphasizes both intellectual and action-driven challenge to the gaming community. Gamieon depends on the talent of individuals working as a team to develop video games and video game engines with a focus on exceptional game play and surrealism.
This is the follow-up to Indiedb.com. If this is your first time ever reading about "Paper Cowboys," please read the preface in the first article.
Good progress in this hour. I made the enemies aim toward the closest player, fixed the ledge jumping, increased gravity, made enemy bullets slower, fixed the bug where the buildings were not scrolling as fast as the player, and added enemies throughout the map.
I also started on the fun stuff: Options menu (player name, color, volume controls), scoring; and after those are done...ITEM DROPS! Sound effects will come later.
Got the options menu finished (name, color, sfx volume, music volume), and moved the active game list into its own menu so it wouldn't fight the other buttons for space. I also looked up how to send player properties (such as color) to other players and was in the middle of writing code to do that when my hour expired. I think the main menu won't go through many more changes before time expires.
I finished getting the player attributes to sync with all players, as well as scoring to work (which was rather tricky). I then tried a two-player playthrough (where one player just stands there doing nothing) and experienced some oddities where, sometimes after shooting an enemy, several warnings would appear in my Console window suggesting child objects of the enemy would be missing. There's also a problem where a new player will never spawn if the master player is dead at the time.
As badly as I want to work on adding drops and new weapons, I spent the rest of the hour investigating these bugs which still remain unsolved.
I believe the errors from the previous hour are now fixed; it was a combination of the barrel trying to act like an animated character, and all the players trying to control everyone elses bullets. Like I mentioned before, you have to think carefully about what your game components do in a networked environment! Now I can begin adding new weapons and limiting the rate of fire for the existing one.
I also pondered the enemy behavior a little more; and if I have time, I may change the enemy dynamics to what I call the "whack-a-mole" model.
Right now I make just one enemy appear at each spawn point as soon as it comes into screen range. Players can therefore advance through the game by incessantly shooting in the forward direction since their bullets will inevitably strike an enemy shortly after they appear on screen.
With whack-a-mole, there will be pre-defined indestructable spawn points where an endless (or limited depending on the setup) slow stream of enemies will come out at random times to fire on players. Enemies may also partially come out just to trick a player into shooting at them, and then wait until the player finally stops before they come out to fire back.
The advantage of whack-a-mole is that a stream of enemies can come from all corners of the screen, and that requires players to be more evasive and coordinated.
Of course this is all just thinking out loud; I need to start working on new weapons now. I'll go back to the enemy design later on after I do some playthrough testing.
I burned through the first 20 minutes fixing some earlier bugs that I discovered while thinking about the project as I fell asleep the night before. I also managed to get two new weapons fully functional:
- The Winchesta: Fires armor piercing (it won't disappear when it hits something) bullets that do 1.5x damage. No, it's not a Winchester....it's THE WINCHESTA!
- The Shotgun: Fires four shells that do 2x damage at a time with a reduced range.
And I drew up another weapon that isn't yet functional:
- The Rocket Launcher: Because I said so.
In the next hour I need to control the rates of fire, create ammo limits for non-pistol weapons, finish the rocket launcher; and make a weapon selection HUD that shows your weapons and ammo and your weapon hotkeys. If I have time, I'll do more network testing followed by starting on random weapon and ammo drops.
Well I refactored the player weapon class hierarchy a bit, put a limit on rate of fire, ammo, and threw together a HUD that lets you choose weapons (just barely in the nick of time). I also got the startings of the rocket launcher, but it's not done. I pretty much have two hours left to get the rocket launcher working, weapon drops, and a level 1 boss. I'm pretty sure that's not going to happen, so I need to prioritize:
I'll finish the boss, and then the rocket launcher.
I totally don't know where the time went. I did a little bit of refactoring, made it so you can't go past the end of the level, added gizmos so you could see the start and end points in the Unity editor, worked on the boss...and before I knew it, an hour had passed! This is it...I've got one more hour to go before the half-way point...can I get the boss done in time?
I finished the boss, got the rocket launcher rockets to unleash some smoke particles and got some play testing in with a good friend of mine who goes by the alias NullSoldier. I consider the test successful because the player elements kept in sync and the network-related bugs should be easy to fix. I uploaded the video to YouTube.
I'm at the half-way point, so I decided to sit back and assess things.
Features I wanted to get done by now:
- Rocket launcher. It can fire rockets; but they don't explode, have smoke trails, or shake the camera yet.
- Item drops including weapons, hats, ammo, belts for increased capacity, and cigarettes for fun.
Remaining bugs I wanted to fix:
- If a player leaves and rejoins, then all the spawn points respawn enemies!
- If you play from Chrome, keyboard inputs may get ignored (it happened to NullSoldier; I couldn't duplicate it)
- Barrels don't fall in sync between players
- Sometimes you cease to be able to jump
- When your friend dies, they don't get thrown in a direction like enemies do
- No Music for level 1
- "Respawning in" should be your player color, not black
- Too much GUI screen clutter in boss fights; you can hardly even see the boss
- The horses in the title screen don't have tails
Remaining features I need to do:
- Physics! I noticed while testing that fun with physics could be an untapped gold mine for this game...for example maybe a player could shoot a support pole that falls and unleashes a bunch of falling barrels; or maybe rocket-shoot a floor and the enemies on it all fall down.
- Item drops including weapons, hats, ammo, belts for increased capacity, and cigarettes for fun.
- There needs to be explosions and fanfare when you beat a boss
- There needs to be a visual cue that shows you when you can jump
- More weapons (maybe a flamethrower if I have time)
- Hats and scarves
- Sound effects
- "Whack-a-mole" enemies
- Two more levels; one of them on horseback
- Weapon display at the top and score list needs cleanup
- Player hues need to be a little darker; it's hard to see certain colors.
Check out my homepage and news feeds
And my projects!
I've spent the past decade developing games in my spare time (which I don't have much of) with unique game play that aren't side-scrollers, first-person shooters, RPG's, MMO's; and aren't even multi-player. Recently I've been feeling the urge to just stop doing things that way, and just make a good old multi-player side-scroller before I burn myself out. My motivations are:
I decided during a recent hiking trip to do just that; I would try to make my own 8 player "Sunset Riders" game. However, as I'm still committed to finishing my other in-development game Dominoze, I'm putting a cap of a total of 48 hours on this project before I stop and re-evaluate my goals. The actual time will be spaced out for as long as I want (and I'm guessing I'll be done in mid-June).
It's like my own personal 48 hour Game Jam except I don't lose any sleep.
Depending on how it looks, I MAY register it as a new game on IndieDB...I'm really not decided on that yet.
Decided to do the easy part first: The main menu. I created a new Unity project with Photon networking support. I grabbed the main menu script and the game script from my other project Dominoze and stripped them down to the essentials. Found a font on 007fonts for the western text (but I might replace it later), and set the buttons and game list up. Also drew the sun, a cactus and some mountains in MS Paint.
There are two background layers; one for far-away stuff (mountains, forests), and one for closer objects like cactii.
Got the background to animate by using simple texture coordinate translations and repeating textures. The mountains move slowly and the cactii move faster. Also found a good song for the main menu on AudioJungle, and put together a horse animation by grabbing the first gif off the Internet I could find as a reference, and hand drawing every frame. Also spent five minutes playing with my cat.
Cleaned up the main menu (except for the lack of options menu which is another ball of wax). Then I created a new desert background and the basic character animation frames; after that started pondering level 1's design. Just shooting some random baddies in the desert would be rather boring, so I decided I'll need to start drawing some old western buildings; including some foreground elements between the player and the camera. I also need to finish designing the player controls. One thing I liked was the concept of an "Input Focus" interface where the game manager decides what screen element gets your keystrokes. Before I add new scenery, I should get the player walking around and also able to aim and shoot the basic gun.
The player can now spawn in single player-mode and walk forward and backward. The character has a rigidbody so I can leverage Unity's physics engines to handle jumping and falling. I also added the "gun arm" that will ultimately aim toward where the mouse is pointing, but that part doesn't work yet. I also spent a fair bit of time deciding where and when the player is going to spawn. I'll finish that up in an upcoming hour.
The player can now fire bullets from their gun which eventually fall to the floor. It's not much in an hour, but I had to go back and recalibrate the player animation frames so that they were properly centered; and then I replaced all of the Unity "Plane" objects with my own square mesh where a scale of (1,1,1) truly is (1,1,1) and with just four vertices instead of a ton. Next I need to tweak the bullets, big time. They look very small and they may need to glow with the player's color; in fact I'm thinking the player and gun need to be scaled up a little bit as well.
I looked back at why it took 5 hours just to get to a player shooting, and my answer is: 1. I made the title screen 2. I did all of the art from scratch (it still would have taken a while to import someone else's art though) 3. I needed time to think through an easily maintainable way to make things work. Adding new weapons and items should be very easy to do, and I should almost never have to change existing code to support new items after the first time. 4. This is not a waterfall development model. 5. I'm not going to get everything right the first time.
Cleaned up the bullet appearance and also got it working with a physics collider; problem is it collides with the player so it never gets anywhere. For now I'm making it a trigger until I implement enemies and physics layers. I also made it so the camera can't go backwards to keep things very forward-moving (though I have yet to force the player to not go behind the limit as well). I also added a crosshair to replace the mouse cursor. Finally, the player is more elevated on the screen so that I can properly render a dirt trail under them.
I'll probably use the next hour to add support for jumping and ducking...then I can finally start bringing in the enemies.
I made a crouching texture, and got jumping and ducking to work. The tricky part was trying to make it work smoothly...in the end I ended up constantly polling for keys being up or down rather than just watching for key state change events. Based on all the key states in a frame together (and the player's upward velocity), I would update the player's appearance. It could be optimized, but I'll do that later. I also made the camera Y fixed for now...I may later decide to have levels were players move vertical like on a mountain climb.
Now I need to figure out how the enemies will spawn...and respawn?
I spent a good 20 minutes trying to figure out the enemy spawning system (Should they just appear from the sides of the screen? Should they continually spawn from central points?) until I came to the realization that I was overengineering it. Deciding there was always room for improvement later, I ended up simply going with the "Spawn once from a pre-defined point" model. Then there's the matter of the fact it's a network game; a poor design could easily cause the same enemy to get spawned multiple times. Thankfully there is a variable in the photon library that defines a "master client."
My plan is this: If any player gets close enough to a spawn point, it will broadcast a message that it "got close enough." Everyone who gets it will flag the spawn point as "contacted," meaning if anyone else ever gets close to the spawn point, they will not post a network message. The master client will not only flag the spawn point as contacted; they will also spawn the enemy. This way, we
- Don't crowd the game with a hundred pre-spawned enemies just waiting for players to come around when the game begins
- Ensure each enemy only spawns once
- Minimize the network traffic needed to coordinate enemy spawning
In this hour I created a basic enemy prefab, an Enemy class and a "ThugWithGun" class (which is the simplest enemy); and got part of the way through writing the trigger logic.
I also added a few more cactii in the background...because I'm using a projection view, putting them at different distances from the camera gives an altogether cool effect as you're walking.
Finished the code to make the enemy spawn, and the enemy is stationary for now. There will be time later on to do more advanced stuff (like leaping in from the side of the screen, appearing from windows, maybe initially sitting down playing cards...) and I'd like to keep things simple for now. I also got the enemy to fire to the left in regular intervals, and made the bullets properly pass through other objects of their kind (enemy bullets pass through enemies, player bullets fly through players).
The next natural step is to implement the player and enemy dying; but I'm far behind in network testing. Of course it works fine for one player, but I need to try getting a second and third player in and make sure everything is synchronized.
Got a little accomplished in a long time. Everything in "offline" mode was hunky dorey, but as soon as I tried to play on a server, things went downhill fast. For one thing, I couldn't even host my own game. Turns out my anti-malware software was blocking my connection thinking it was malicious. Then I found that things that used to work "offline" don't work "online," such as calling PhotonNetwork.Instantiate with non-atomic variables (like passing in a component instead of a string or a long integer). I also learned that I was going about observers / synchronizations incorrectly...for example if I didn't own a rigidbody, I needed to make it kinematic so that nobody else's physics engine but mine would try to act on it locally.
I'm close to getting it working; just need to fix the enemy bullet color.
But it's all good because I'm carrying all this knowledge to my other project "Dominoze."
I studied some Photon scripts to learn how to handle player movements. It gave me a new perspective on things -- you have to design around components that may and may not be yours depending on the instance. You also can't bind key commands and player appearance/animation in the same function anymore because now you're at the mercy of the network engine for updating player orientation. A lot of the work in this hour was trying different things and then cleaning up some existing code to make it easier to read. What I have right now kinda works (except for aiming; haven't figured that part out) but I might do a little more cleanup to make it player smoother; I'm disappointed at the latency between the time I move a player and the time I see it move on another screen, but the game should still be playable in these conditions.
After eating a "keep at it until it works" cake with commitment frosting and frustration sprinkles, I'm much happier now because now the players and enemy properly spawn and sync, and I've started work on making enemies and players die. Lesson to the reader: If you're developing a network game, make your own little network sandbox game first, heavily comment it, and keep it around. You will learn a ton!
I also made the title screen look a little better.
I can't believe I'm already 25% toward my deadline...I'd better get in gear and slam down a few sodas if I plan on getting level 1 playable with scoring and loot drops within 12 more hours!
I cleaned up some existing code, and then added support for enemies and players dying (and apparently I need to hide the crosshair in the next hour). Now I just need to do respawning.
Got respawning to work. I made it so when the spawn timer expires, the player asks the master client to tell them where to respawn. If the master client is dead, then the player will respawn where the master client was when they died. Otherwise the dead player will respawn where the master client's character is. Also did a little more code cleanup / odds and ends, and made a new building. All my efforts are now for screenshot saturday on Reddit.
Got the second building done; and I even added a barrel as an obstacle that you can shoot! Also fixed a few little bugs I found along the way, and started working on letting the player jump onto ledges and started a third building.
There are now four buildings and the ledge jumping works despite being real slow and clunky. Right now you just have to press the Up command to get onto a ledge; but Down is already deserved for crouching so I need to re-evaluate the jumping key commands. I also brought a few more enemies and barrel obstacles into the scene although they're quite easy to kill if you just button mash your way around. Having enemies respawn might not be a bad idea.
Check out my homepage and news feeds
And my projects!
...because maybe then I wouldn't still be stuck over a year later trying to figure out how to stop the pinball from getting stuck in a bumper, or behind a bumper, or going through a flipper.
The Unity physics system is a powerful tool built by a team of very talented developers who knew that there would be a large diversity of demands on it...so I believe I'm doing something wrong on my side even though I feel like most of the issues I've had should never have been issues at all.
Since the inception of Hyperspace Pinball, I've had to combat:
- Pinball falling through the flipper
- Pinball shooting through the playfield outright
- Pinball getting stuck in a wall
- Two pinballs cancelling out each others' velocities and hanging in mid-air for a moment
- (Unity 4) Pinball getting stuck in flipper
- (Unity 4) Pinball sinking into flipper and the act of pressing the flipper would make it rotate about the ball and not its pivot
To combat those issues I've:
- Capped the max pinball velocity to an unrealistically and dreadfully slow value
- Increased the Solver Iteration Count to 15 (this actually made things worse in Unity 4)
- Implemented the "DontGoThroughThings" script
- Implemented a very clever (meaning "I tried whatever worked") way for the ball to detect if it's going through the flippers, and behave in a way that makes the glitch only happen for a tiny fraction of a second
- Made the ball rigidbody to be continuous dynamic
- Made all walls static
When I released the game, I was able to get through the whole campaign without seeing more than maybe two issues at best. Despite these things and my own experience, I still get regular reports of the issues still happening frequently and was rightfully given a low rating on Desura (I consider anything less than 8 a low rating). Going back to try to make things better has also pulled me away from my upcoming projects; though I have myself to blame for that.
To compound things, I think Unity 4 deals with object penetration a bit differently -- when a pinball penetrates something, it seems to dig in rather than immediately correct itself in many cases. It's also a teachable moment: If you try to override an engine's physics behavior with your own scripts, then you may have to start all over again if the engine changes.
So the next steps are to:
1. Make a standalone copy of the project in Unity 4 (since that seems to not work as well as Unity 3 for the way my game is right now)
2. Strip out all the UI and game-specific logic until I'm left with just a playfield and an infinite supply of pinballs on tap (for later).
3. For each bad behavior, set the scene up in such a way that I can reproduce the behavior 100% of the time
4. Find a solution.
5. Apply the fix to the main game
When I deploy my Unity apps to Desura, I need to submit the Mac builds as DMG files. I pieced together my own process for this after doing a little bit of Googling. It has to be done from a Mac.
- "iDMG" - iDMG is an app that I found on Macupdate.com . It creates a single DMG file from a folder of files. It's been a while since I downloaded and "installed" it; but when I need it, I can find it in my Applications folder on my Macbook.
1. Build the Mac app with Unity.
6 (Desura users only): Upload the generated yourgame.dmg to Desura.
Since I started with Unity, I've released three games onto the App Store and Google Play: Tiltz, Hyperspace Pinball and Hamster Chase. Now I'm working on a fourth game, Dominoze; and now I find all my free time is spent chasing opportunities and maintenance issues for each.
Tiltz hasn't been updated for over a year, but I just got a new bug report that I consider a showstopper. Hyperspace Pinball is done, but I'm changing it to a freemium model since nobody is downloading it anymore (if I can't make sales, I may as well make downloads). Hamster Chase is about to have a promotional update with "Gifitz." Dominoze is just getting started.
One might think "well those other games are old and weren't smash hits; why maintain them?" Because while making a couple games to build experience is good; I think all of them, even Tiltz, are semi-professional-looking and worth spending time maintaining instead of letting them crumble into the dustbin of history too quickly.
My strategy is to knock out the easiest tasks first, followed by stuff that requires Apple's review. Since the Giftiz update is almost done (possibly 30 minutes of work left), I should just get that done first. Then I'll work on Pinball since I'm eager to get that promotion done and make it Freemium. While Pinball is in review, I can work on Tiltz until that gets in review. This will all delay Dominoze a bit, but I can always set aside a few minutes here and there to move the Dominoze design document along (mostly while waiting on Unity builds for my other projects).
I'm fairly happy doing all the work; but the moral of the story is: If you work alone and you have several projects on the market and you want to keep getting more downloads...then you should expect these kinds of things to distract you from new projects.
...and no I'm not quitting my day job.
It is possible to give yourself too much freedom to develop a game. I learned that after transforming the development of a physics puzzle game into a personal Mount Everest of feature creep.
The story begins in February 2001 when I got the idea for a puzzle game where you have to knock down a trail of dominoes by manipulating objects along the domino path. I thought the idea was so great, I hardly got any sleep that night! Development began the next day, and ran its course over subsequent evenings and weekends between 0-15 hours per week while I worked a full-time job writing unrelated software.
My development philosophy was this:
I list all the tools I used later on in the Facts Sheet section.
This year was spent trying and failing to write my own physics engine. I learned quite a bit in the process which helped me out later on when using other physics engines. I also wrote the "glAppGrapher" which is a great debugging tool for when you want your program to render things in a separate window acting as a "graphical server."
These years were a cycle of tinkering with, shelving and unshelving the Dominoze sandbox puzzle editor and game engine at the continued 0-15 hour/week pace. By October of 2004, after perhaps 3 or 4 attempts from near-scratch, I had written a fragile-but-functional game engine and editor based on the Newton physics engine, FreeGLUT, OpenAL, LuaScript and the CxImage library. That is the same month I also founded Gamieon, Inc. as the front end for Dominoze development. Four years is an awful long time to tinker around in even if it is under 20 hours/week; but time flies when you're having fun!
In 2006 my focus was on developing game content itself at the same pace as before. I still did not know exactly how I wanted the levels to look even for much of that year, but that's not for lack of trying all kinds of ideas. I finally conceded that since I can't come up with an art style myself, I would just fall back on photorealism. Rather than focusing on puzzle design and cranking out dozens of levels which reused the same concepts in different ways, I wanted each level to be as unique as possible and have elaborate backgrounds. At the same time, I wanted 100 levels. There wasn't a story to the game at this time; it just didn't seem important. Since everything was moving so slowly, 2006 was the year I started asking people for help with art and level designs. I started by commissioning one artist and one designer to help me out. The collaboration was simply "Can you please create X for me?" We'd agree on a pricing structure, got the work done, funds exchanged; and that was that. Of course, the art assets created new demands on my engine and editor, so programming continued to stay focused there.
These years saw continued level and engine development as features were added on a "need-to" basis as I came up with new ideas. Why just have turntables when you can have pulleys? Why pulleys and why not gear puzzles? Laser-mirror puzzles? Fans and blimps? Absolutely! There was no plan in place that defined boundaries on the project in terms of time or features. Dominoze was becoming five games in one! My development pace increased to about 10-20 hours/week. Despite bringing more level designers and artists to help me out, my requirements for the level count dwindled to 50 because making just one level was a big undertaking. In addition to "...please create X for me...," I invited everyone who I commissioned to have online chats and e-mail threads for sharing their thoughts on various aspects of the project. I also got the bright idea to start writing my own light mapper to make the levels appear more realistic. A developer could make it their full time job to maintain a light mapper; but hey, I wanted to see if I could pull it off! I wanted Dominoze to look as professionally done as possible, and give the illusion that there were multiple programmers working on it. I also finally came up with a story for the game: It would be about a parrot trying to rescue his friends. In return, the parrot would give you clues on how to solve puzzles.
Some advice for new and aspiring game developers: Coming up with a story for a game six years after its inception is typically something you don't want to do.
This was the most critical year for Dominoze; it was the year I finally said "I'm done tinkering with this project. I want to get the beta out and see if it's viable to even finish." By this point, I was investing all my free time into the project, and work had begun on the trailer. Things came to a head around July when I officially stopped new content development, and put all my energy into finishing the trailer, testing, and cleaning up all the existing content and engine features. Finally, in December of 2009, I released the first 30 level beta on IndieDB.com after a friend recommended the site to me as a launching point. Feedback on the site was scarce although positive. I got only a few bug reports, and addressed them all with subsequent updates while using Trac to maintain my bug lists.
This year was the last year of Dominoze development under my existing code base, and the first year I opened myself up to really networking with other people. In March I went to GDC 2010 and showed Dominoze to a few people. The consensus was that it looked like a nice game, but it would fare much better if I were to simplify it and move it to the mobile market. I also spent some time in the Unity booth learning about their cross-platform game engine and development tools. I was a little disheartened, but nowhere near feeling like my world was destroyed (I explain why later in this article under "Rewards for Dominoze Development"). I decided it was time to finish what I had, and then take a long holiday from Dominoze and figure out what I wanted to do next. By July, I had released all the trailers, the Dominoze editor, and a few bug fixes to the game. As before, I only got a handful of comments; and nobody in the games press seemed really interested in it (though I didn't make a big effort because the game was still technically in beta without a release date).
I then stopped development entirely because:
By 2011 I was comfortable using the Unity engine. I managed to create and play a very simple Dominoze level from scratch with Unity in the total time span of 2 hours. After 9 years.
To further study the prospect of Dominoze in Unity, I developed a small project called the "Gamieon Construction Kit" at Gamieon.com which is a multi-player sandbox where you can add simple building blocks to drive falling marbles into a little box. Your creations are stored online for all to see. As the code was hacked together as quickly as possible and for discovery purposes only, I have no plans to re-use it at this time (and the gallery broke down some time in 2012).
Using the Unity engine, I developed three games in my spare time since 2010: Tiltz, Hyperspace Pinball, and Hamster Chase. As of March 12, 2013, they have nearly 80,000 downloads combined. I think my Unity skills are now ready for Dominoze...and this time it's going to be cross-platform and network-ready (but completely playable from start to end without an internet connection).
Lessons Learned and Affirmed (in no particular order)
* Code Line Counts are approximations, and exclude blank lines. Calculated using the "Universal Code Lines Counter."
Costs of Dominoze Development
Rewards for Dominoze Development
Dominoze was never released as a completed product. It did not make any money. It also didn't come anywhere near the popularity of many Indie games. However, Dominoze is my "ship in a bottle." Looking back, I can now say that I programmed a game, a complex game editor, game engine, and video engine on top of lower level third-party components by myself (operative word is -programmed-; I had a lot of help with art and level design. See credits below.) While I do feel some envy toward Indies who did release acclaimed games; I think I loved programming and pushing myself against my own limits more than I did releasing games. I'll wear Dominoze as a badge of honor for the rest of my life.
The Future of the Dominoze Idea
Taking all the aforementioned lessons in consideration, I would like to take one last shot at Dominoze in 2013 using the Unity Engine. My goal is to create an app for the PC and tablet platforms that lets people create domino sets together real-time, watch as they knock over all the dominoes, and share with everyone online in a global catalog. To do this right, I need to:
I believe that a Dominoze app would reach its potential by being designed for kids, but fun for everyone. I also believe it would reach its potential by staying true to its creative core; and keeping players engaged by offering milestones, challenges, community building, competitions, sharing, and lots and lots of content.
What About the Legacy Game and Source Code?
I don't know what I will do with it; I just know that I have no plans to use it onward. Open sourcing it is one option, but I don't want to spend months training people on code where the comments and style are tailored for me and not for other developers. While the engine is designed to be lean and fast, it is too customized for Dominoze, and lacks a great deal of the functionality and ease-of-use that developers demand today. It is also not going to be actively maintained, but at least I can keep it around for reference. I'm willing to take things on a per-case basis if anyone is interested in the source, though.
If you don't set a finish line, then you can never win a race. Even running a race will not guarantee victory; so don't postpone your happiness until you achieve it. Finally, don't work hard...work smart.
Dominoze could not have gotten as far as it did if not for tremendous help with asset development from: Eric Barth, Jeff Gordon, Jordan Pelovitz, Yisroel Goldstein, Hélder Gomes, Russ McMackin, Bryan Taylor, and Jarien Strutts. Special thanks to Mick Rippon for donating his songs to the project! Special thanks to George Toderici for all the advice and web links that helped me with video engine development!
To the Reader
Dominoze PC Beta is still available for download at Dominoze.com if you want to tinker with it. Feel free to drop me a line at c.haag AT gamieon DOT com if you'd like to give feedback or offer help with the project.
Please follow my Dominoze news feed on IndieDB.com if you're interested in watching the new Dominoze project progress. If you have an iPad, Android tablet, or a PC; then I hope you'll enjoy creating your own domino sets once the app is ready!
Hamster Chase Online Part 2: Client Side
This is a continuation of the article at Indiedb.com . In this article, I describe how the app itself downloads and maintains puzzles that other players created. The app was developed using the Unity engine.
Here are the core requirements:
1. The app has to communicate with the server.
2. The app needs to store requested puzzles, their preview thumbnails and ratings on the device.
3. The user should be able to select puzzles to play.
Here are the requirements for an ideal implementation:
1. The app should handle cases where the server is down.
2. The app should run smoothly even when the server is slow to respond.
3. The app needs a unique identity that can be sent to the server when voting on puzzles.
4. Visible thumbnails need to get to the player as quickly as possible.
5. The app should adapt to the fact that the master puzzle list is constantly changing.
6. Players should be able to vote on puzzles.
7. There should be easy browsing and filtering of puzzles.
How I'm satisfying the core requirements:
1. Hamster Chase communicates with Gamieon's server using Unity's WWW objects to make POST requests to it. Responses are received asynchronously so as to not force the main game loop to halt. The requests are directed to a domain name, rather than an IP address, so that I don't have to push any updates if the server's IP changes. Puzzle catalog requests include: The page number of the catalog to load (as if the catalog were a big book), and the criteria (new puzzles? popular puzzles? difficult puzzles?).
2. Because of the ever-changing nature of the master server's puzzle list and puzzle ratings, it doesn't make sense to store the puzzles on the device's secondary storage for when the user isn't playing. It also doesn't make sense to store -all- the puzzles in memory, because there could be thousands. My approach is to load puzzles and preview thumbnails from the server into memory that fit one of two criteria: The player is requesting to see them in the puzzle selection screen, or the player may soon request to see them in the level selection screen.
Think of the server catalog as a big book of puzzles. Each page in the book has eight puzzles (because the level selection screen fits eight puzzles at once). Suppose this book has 26 pages, and each page is a different letter:
In my design, the app will retain in memory the puzzles and thumbnails of the page that the player is selecting from, as well as the five pages before and after it. For example, when a player goes into online mode, the app will request pages A-F:
Now suppose the player goes to page F. Since the player moved five pages forward, the app gets the next five pages forward (G,H,I,J,K). The new range is:
Now suppose the player advances to page G. The rule is we keep five in either direction, so the app will wipe page A from memory, and then load page L. The range becomes:
There will always be 11 pages * 8 puzzles/page = 88 puzzles in memory at most. Unless the player is changing pages like crazy, the app should be able to keep up with the player and it should give the illusion that everything just instantly loads.
3. The convenient thing about Hamster Chase is that all the puzzles are very small. Therefore, when I write that the app 'downloads puzzles,' I really mean just that! As soon as the puzzle and its thumbnail have been downloaded, a player can simply tap to play.
Now, if puzzles were huge (say 100K+ in size); then I'd be referring to "puzzle metadata" instead (name, description, size). In those cases, a request would have to be made to download the actual puzzle when the player wanted to play it.
To satisfy the requirements for the ideal implementation:
1. Dealing with unexpected connection issues or server downtime should be given equal priority to when conditions are functional. Don't just spend 10 minutes implementing an error message "that should never happen" and then do something else. Hamster Chase anticipates two kinds of failure conditions:
A. "The server is in maintenance mode." This is a special message sent by the server when it's futile to repeat requests for data. Hamster Chase will notify the user that the server is down, and then move them away from online functionality.
B. The app can't connect to the server, or the server is throwing irregular errors. In my implementation, the app will just try again and again every few moments until the player finally gives up waiting.
2. Because the server transactions are asynchronous, the implementation will naturally run smoothly even if the server is slow to respond. Nobody likes to see activity indicators, but sometimes those are the breaks.
3. When a player votes on a puzzle, they should only be able to do it once. So the app needs to send an ID unique to itself along with the submission. In Unity, you can use the SystemInfo.deviceUniqueIdentifier function to get a unique identifier for a device. That will get the job done for everyone except players who use a cloud service to sync their game over multiple devices. In those cases you'll need to generate it on any one of them, and have the cloud propagate it to the others.
4. Up to now I've been writing about "downloading puzzles" and "downloading thumbnails"...but have been vague on the exact details until now. You need to balance packet size with the number of trips to the server. When a player requests a page of puzzles in Hamster Chase, they get all eight back from the server in one shot. Thats 3 kilobytes per puzzle max * 8 puzzles = 24 KB/trip. Once the app has the puzzles, it will launch eight requests for thumbnails; one per puzzle. Each thumbnail is 3 KB.
These are the implementations I considered:
A. Get the puzzles in the first trip, and the thumbnails in eight subsequent trips (as I described above).
B. Get everything; puzzles and thumbnails, in one 48 KB trip.
C. Get just the count of puzzles in the first trip, and then download each puzzle and thumbnail as a pair in eight subsequent trips (6 KB each).
D. Get only the thumbnails and ID's in one 24 KB trip; then download the actual puzzles in the next trip.
The issue I have with option B is that the player has to wait for a 48 KB transfer followed by the decoding of 8 jpegs as textures one-after-another in the main loop, causing a noticeable delay. Option C should be apparently quicker than option A because the first trip requires less data to transfer, and the player still gets the same per-thumbnail activity indicators. However, I went with option A because Unity's WWW object made it very easy to download one image and only one image in a single trip, and because A was still quite fast when I tested it. Option D would have all the thumbnails available to the player right away (though again you have decoding all the jpegs one-after-another), but I don't like the idea of having a thumbnail on the screen for a puzzle that hasn't been downloaded yet. If the puzzles were large, I could understand...but not when they're only 3K. More importantly, there's also the possibility that a puzzle was deleted in the brief moment between the thumbnail and puzzle request.
5. Players can upload puzzles, and just as easily take their puzzles down. Taking them down can cause some weirdness in the level selection screen as a player navigates through the server's catalog: puzzles can be skipped or appear to be duplicated. However, what I think is not forgivable is starting at the level selection screen, and then going backwards only to find new puzzles just appeared. The first page should always be the first page.
My solution is this: When the app makes its initial request to the server, the server gives back the ID of the highest puzzle in the server's catalog. In every subsequent request, that ID is sent back to the server saying "I don't want any puzzles that were created after [ID]." This way, new puzzles don't confuse the player into wondering which page is really page 1.
6. Players can vote on puzzle quality and difficulty separately. They are asked when they beat the puzzle, but they can also manually vote later. They can even change their votes. To make sure everyone gets one vote, the device's unique ID is sent along with the vote. The server stores them. This won't defeat someone with 50 devices upvoting and downvoting puzzles, though.
7. To keep things interesting and organized, Hamster chase's online puzzle selection screen lets players filter on:
- New puzzles (Sorting by puzzle ID)
- Popular puzzles (Sorting by rating by ID...though I need to do a weighted system where the age of a puzzle pulls its calculated ranking down)
- Difficulty (Sorting by difficulty rating)
Players can also filter on puzzles made by their friends on Facebook. In the main Online mode screen, a player can enable Facebook integration. This causes their puzzle submissions to include their Facebook ID so that they are effectively bound together. I believe that is an effective way for friends to network together through what could be a very crowded puzzle catalog.
All things considered, I think the implementation should be viable for players to navigate through and play online puzzles in the first release of Hamster Chase Online. With only a few thousand active players at the time of this writing, I don't expect any meltdowns, but I will need to monitor things and make sure that players are not waiting more than 2-3 seconds for each page to load.
One of the requirements of the next Hamster Chase mobile app update is the ability to fetch a list of Facebook friend ID's so that a player can search for online content that only their friends created. To integrate my app with Facebook, I use Prime31's Social Networking Plug-In. Between Prime31's documentation and the Unity forums, I was able to find everything I needed except for the most important bit: The format in which the Facebook friends list is returned back to me. Was it in XML, or maybe some proprietary format? Did I get it back from the plug-in as a Hashtable or an ArrayList?
I figured it out in the end, and I wrote this blog in hopes that other Unity developers can benefit from my code snippets. Here are the two main things to know:
1. If you want to see how Facebook sends the friends list back, you should try it yourself using the Graph API Explorer. Just go to Developers.facebook.com , and then submit a Graph API request of "/me/friends" To get your own ID, just submit "/me". It's a terrific site where you can do all kinds of testing.
2. The code I wrote to get the results from Prime31's plug-in is:
You may have seen some forum crosstalk about the request not returning all of a person's friends. I believe this issue was resolved by Facebook in May 2012 - see Developers.facebook.com for details.
Hamster Chase is a mobile puzzle game where you guide hamsters around a maze of interactive obstacles (which I'll just refer to as "puzzles" from hereon) to get them to their seeds. In the Hamster Chase 1.1 update, I intend to have players be able to create their own puzzles, submit them online; and let every player be able to download and play them.
Here are the core requirements:
Here are requirements for an ideal implementation:
How I'm satisfying the core requirements:
1. The easiest decision to make was that I would not host anything from home. For both puzzle and thumbnail storage, I chose to go with a MySQL server hosted by an outside vendor because it can quickly filter on and return puzzle content, because I'm familiar with how to use it, and because the vendor I use for web hosting already had one set up.
2. I would also rely on the vendor to deal with the data hosting, web hosting and all the logistics thereof. I would write PHP scripts to put on the web server that allow players to submit and download puzzles from the database.
How I'm trying to satisfy the ideal implementation requirements:
1. A typical puzzle is between one and three kilobytes of text when uncompressed (and I could probably cut that down in half with some formatting changes; but that's a topic for another day), and a preview thumbnail is also three kilobytes on average. Between the size requirements, a properly indexed data structure and the use of stored procedures in MySQL, I expect fast processing from the storage server.
2. The PHP scripts are lightweight; all they do is validate the inputs, query the data server and give results back to the player. There are no processor-intensive operations going on that I expect would cause a bottleneck.
3. When someone uploads a big puzzle, at most they're sending a roughly 6 KB (3K puzzle not counting any compression + 3K thumbnail) payload to the server. I don't think uploads will take place more than a few dozen times per day after some time passes since the release.
Downloading, on the other hand, can get a little bit more messy. Suppose a player wants to see the first page of puzzles on the server. A page consists of eight puzzles...so that can be (3 KB Data + 3 KB Thumbnail) * 8 puzzles per page = 48 KB being sent to the player. No problem...but this player is discerning and they may just want to flip through pages of thumbnails to find puzzle they like; so they request a new page every three seconds. That means the server needs to be able to send 48 KB to the client every 3 seconds. No problem! Now lets say you have 1,000 discerning players who want to do the same thing at the same time. That means the server should be able to send out (48 KB * 1000) = 48000 KB ~= 46 MB every three seconds. A good server can handle that and throttle incoming requests as necessary. I don't think the game is so popular as to have this happen in the near future, but still it's something that needs to be thought about.
There's also the matter of how those requests are made (is everything done in one shot, or spread out in multiple requests?) I will cover that more in depth in part 2 of this article when I describe how things work on the client's side.
4. Validation happens at the PHP script level:
5. As far as backups and other general upkeep, I rely on the web host vendor on those things. However, I'm responsible for ensuring they get done.
6. The MySQL user (that the PHP script accesses the database with) only has permissions to execute certain stored procedures I wrote that are used in both puzzle submissions and downloads.
7. The "on/off" switch is basically me going into my PHP scripts and uncommenting the first line that is effectively "print 'Server is down' and terminate script."
I think things will work best if I always treat the implementation as very imperfect and in need of monitoring. Bugs will no doubt be revealed by both well-meaning individuals who stumble upon them, as well as by clever hackers or folk who just want to harm the server. I also expect to learn a lot of lessons that others have already learned...I just need to continue seeking out their blogs and articles so I don't learn too many of them the hard way.
1. Social networking share buttons
A good game gives players reason to run over to their friends and family and say "you gotta see this!" or "I finally got that achievement!" They may not all be in the same room when it happens, so providing an outlet for people to brag from within the game itself in the middle of the action is the next best thing. Those shared posts may excite or at least interest other people, and they will be more inclined to play the game if they already have it, or get their own copy if they don't. "Refer a friend" buttons are good, too!
2. Support for carrying game progress to other devices or versions of the app
Using technology like iCloud to sync a player's progress among several devices and different apps of the same series can be a huge benefit. Often times, people will not upgrade from the free to the full version of a game because they can't take their level progress with them. Using the same sync store for multiple apps will allows sequels of your app, and even other games of yours to see what the player has played; and reward them with bonuses and unlocks.
3. A developer feedback button
It's no fun for a developer to discover new bugs and shortcomings of their game from comments in user reviews; especially ones that hurt their overall rating. It can happen if things just really bother the player, or if they just review everything they play. If you have a way to let them send you feedback in less than a few taps, you stand a chance of them deciding to send their comments to you directly. They might just give you a chance to fix whatever ails them and not write that bad review...so long as you deliver. Of course, they may also want to thank you and give you suggestions for some good new features!
4. Multiplayer or other community functionality
Building and maintaining a community of players is essential to the long-term success of a game. You can have a big successful product launch...and then have everyone stop playing after the first month. If you have players engaging each other, or developing content of their own to put into the game and share with others; then it adds whole new dimensions of things to do, and ways to have fun in the game. Competitions, tournaments, grinding, hunting, collaborations...and those are just some of the ones that developers have already come up with so far...
5. A Rate this app! button
My most recent game currently has over 13,000 downloads and less than 1% of players have rated it so far. How can prospective players trust it to be good if there's only 7 or 8 ratings in the market? For all they know, those all came from your friends and family. The game might not be inspiring enough to make people rate it...but maybe that's because it requires several taps to get back to the store's portal to do so. Letting the user get there in one tap might be the way to go. Just consider the risk involved: This is a good thing for good games, and a not-so-good thing for not-so-good games that might get not-so-good ratings.