Sponsored By

Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs.

After being laid off in a studio closure, industry veteran Ian Cummings set out to make a game for fun in his spare time. That little side project has now grown into the top horse racing game on mobile, and this blog explains what happened along the way.

Ian Cummings, Blogger

May 5, 2016

11 Min Read

The Making Of Photo Finish


If you've made it here, welcome! Since the Kentucky Derby is upon us, and a huge new update has just launched for my game, Photo Finish Horse Racing, I wanted to put together a brief background of how it was made.

iTunes Link:https://itunes.apple.com/us/app/photo-finish-horse-racing/id993764346?mt=8

Google Play Link:https://play.google.com/store/apps/details?id=com.thirdtime.derbyking&hl=en 

This game (built in Unity) was started as a side project, but has now grown into me being able to start my own game studio (called "Third Time" - http://thirdti.me/), a full time source of income for myself and 2 other developers, along with landing us a publishing deal. I have been toiling away in the game industry for 15 years now, including a 10 year run at EA Sports where I was the Creative Director of Madden NFL franchise. Over the course of a few months of the summer of 2015, I self-developed, published, and marketed the game, so I hope anyone reading this can a) realize that it can be done by yourself and b) learn some tricks of the trade along the way. 

Why Horse Racing? 

The number one question I've been asked about the game's development is actually why I picked Horse Racing. Everyone asks "were you a big fan of the sport or something?''. In reality, no. I've only been to maybe 2 horse races in my life, and until last year probably couldn't tell you a single horse or even the names of any tracks or races outside of the Triple Crown ones. The reason I picked Horse Racing though was three-fold - 1) feasibilty 2) appeal to the platform and 3) niche audience. 

Feasibility is sort of self explanatory. I have no formal training in computer science, I have only just learned how to write code on my own over the years so I often hit roadblocks when it comes to complex technical problems. Horse Racing at the surface seemed easy enough for me to be able to make by myself, due to the rather rigid and predictable structure of it. Now of course a lot of things ended up being way more difficult than I thought (for example finding out how far away horses are from the finish line on an oval track), but for the most part it was reasonably straightforward to get some horses running in a circle. 

Another major reason to me was the appeal to the platform, meaning mostly that at their longest, horse races still only last a couple of minutes. It was critical to me (making a game for mobile) that the sessions be short and make it feel like you could make viable progress and soak in a meaningful amount of gameplay while you were waiting in line somewhere. 

Lastly, and the reason that a lot of people raise their eyebrows at me, is because Horse Racing is niche and a sport that's on the outs (at least in the U.S.). Having worked at EA and Zynga and seeing how aggressive big companies can be when you compete with them, I wanted absolutely nothing to do with any business that they would be interested in. I could always imagine a Horse Racing game making a decent amount of money, but never enough for one of the big companies out there to want to come in and muscle me out. 

Part 1: The Race

With the intro out of the way, I wanted to dig into some of the more minute details about the gameplay, and talk about how the game works. The primary gameplay loop of Photo Finish is earning "bucks" by winning races, and using those bucks to upgrade your horse / jockey so they get faster and can enter into more difficult races. Knowing this as my design direction up front, the very first thing I built was the base physics model driven by an attribute system.

In Photo Finish, each horse is moving at a variable rate of speed towards a waypoint. For the first prototype (and the primary mode of races), I just created a straight sprint of the home stretch, where they run in a straight line from their starting position in the gate to the finish line. The curves in the track I knew would be more difficult so I saved that work for later. After the race starts, the horse's speed is accelerating, and then once a top speed is reached, the horse's speed is decaying. In simplest pseudo code, this runs inside a FixedUpdate loop for each horse:


void FixedUpdate() 
{   
    // slowing down    
    if (_isDecaying)    
    {       
        MY_SPEED -= (BASE_SPEED_DECAY * Time.fixedDeltaTime);
        // make sure you never drop to zero speed       
        MY_SPEED = Mathf.Clamp(MY_SPEED, MIN_SPEED, TOP_SPEED);    
    }    
    else    
    {       
        if (MY_SPEED < TOP_SPEED)
        {      
            MY_SPEED += (BASE_SPEED_ACCEL * Time.fixedDeltaTime);    
        }   
        else       
        {          
            // clamp to top speed  
            MY_SPEED = TOP_SPEED;      
            if (!_isDecaying)  
            {     
                _isDecaying = true;           
            }       
        }       
    }
// move the horse toward waypoints. 
    _moveDir = _curwaypoint.transform.position - transform.position;  
    _moveVec = _moveDir.normalized * MY_SPEED * Time.fixedDeltaTime;  
    transform.position += _moveVec; 
}

 

A key detail here is that I am in essence just pushing a transform around, and animation is being ignored as part of this. I did this on purpose, knowing from experience that I really didn't want animation to have anything to do with how fast or far the horse actually moved. This is unlike traditional simulation sports games, where the animation typically has movement baked into it for realism purposes. I knew this would cause too much complexity for me, so I just put the actual animated horse model as a child underneath the main transform. You can see in the gif below, I switch off animation, and the horses are still moving at their correctly tuned speeds:  

 

 

Attribute System

The other key part of this first playable prototype was an attribute system. After all, how fun is it if every race is a tie? After I had my rough code working to move my object to the end of the track, I tuned the numbers to be as realistic as I could find for what a real race horse would do. The record I found on the internet was 20.57 seconds for a quarter mile, so I just kept iterating and tuning the BASE_SPEED_ACCEL, BASE_SPEED_DECAY, and TOP_SPEED constant variables until the horse to my eye had a realistic acceleration phase, not much deceleration, and ran the race in 20 seconds. No exact math for this guy! 

So now that I had what I considered the best time that could ever be run, it was easy to just scale it down from there. I decided on 4 attributes for the horse: 
- Acceleration: This would modify the BASE_SPEED_ACCEL value
- Top Speed: This would modify the TOP_SPEED value
- Stamina: This would modify the BASE_SPEED_DECAY value
- Finish: This would be available as a modifier to apply to multiple things based on the user input (using the Whip / Boost button).  



My Best Friend: MapRange()

MapRange() (Rosetta Code link) might be one of the most common code snippets I have used in game development, it's honestly one of the first things I bring over when I create a new project or prototype. In sports games or any games with attributes it is imperative to translate a somewhat human readable value (say a rating of 0-99) into direct numbers that will modify things like physics, reaction times, etc. So this was a relatively straight forward usage for me, I picked a range of attributes for the horses (I started arbitrarily with 100 - 1000), and mapped that into new values for my physics modifiers, and set my currently tuned numbers for the race speed as the max. For example: 


float modAccel = MapRange(horseAccelRating, 100, 1000, BASE_SPEED_ACCEL_MIN, BASE_SPEED_ACCEL_MAX);


This again just required some eyeballing to come up with the BASE_SPEED_ACCEL_MIN, I didn't want the first horse you started the game with to run a race in 90 seconds, but I also wanted a somewhat visual difference in speed as you progressed through the game. Side note: this is a common problem in any game where you are leveling up, and sports games especially. It typically sucks to start out as a golfer that only hits 180 yard drives, or a quarterback who has a total noodle arm and throws interceptions every pass. 

Here's a super early video of the game once I got attribute code in. There can actually be a winner now! You can see some horses started out quicker then faded fast, while the oddly colored one had a steady acceleration and higher top speed. I was actually still a ways out from determining a winner in code, which also proved somewhat tricky...I can cover that in a later post.  

 

Also of note, a special little trick of the trade I did was actually lower the numbers to slower times, but alter the game speed so that it didn't *feel* slow. For example, with the slowest possible horse, you may run a 35 second quarter mile, but I actually bump the timeScale of the game up to 1.25x so that the race finishes in less than 30 seconds. And of course, again I used MapRange() here to determine game speed based on my horse's ratings. 


float gameSpeed = MapRange(horseAccelRating, 100, 1000, 1.25f, 1f);

Adding Some Actual "Gameplay" (User Input)

Now that I had a functional (but admittedly lame) race, the next thing I knew I had to do was add some user control. This is a passion of mine, stemming back through my career at Madden, so I tried all kinds of different things here (and even continue to iterate them). The two things I settled on before release were a) a timing-based start mechanic and b) a timing-based boost/whip mechanic. You can see the current game mechanics in action below: 

The current rotation based start mechanic was probably my 10th attempt at a start mechanic. I tried all sorts of meters, hold/release, swipes, etc, and this one I found was my favorite. It mirrors a three click golf mechanic somewhat, but it reminded me of the old California Games Frisbee mechanic a little bit (am I dating myself there?). Simply explained it kicks off 3 180 degree rotation tweens in a row, and when you tap, it stops the tween, and measures how far off you were from dead center. I take the total error, and of course MapRange() it into a modification on the acceleration values.

The second and slightly more complicated mechanic is the boost mechanic. I took inspiration from the old Tecmo Bowl and Madden NFL kick meters, as well as the original Gears of War active reload mechanic. The boost takes points out of your horse's stamina reservoir and adds them back to your current speed, but the stamina reservoir is limited, so you have to choose when to do the boost and not run out of stamina too early in the race. The idea of the mechanic then is just that you should get a maximum 'boost' if you nail it in the perfect spot, and there is more penalty to going early than going late. If you duff it, you lose all the stamina you were going to lose, but don't get any speed added to your horse. 

Closing

Well, I hope you enjoyed this small glimpse into the development of Photo Finish. For future blogs I plan on going over Presentation (Cameras, Sound, Particles, etc), UI/UX, Monetization Design, and Marketing / Advertising as individual topics. I'd also encourage everyone to download the game via the links to help our little indie studio out. If you see anything in the game you are curious about, or just have any questions about me, the studio, or the game's development, just let me know in the comments and I'll hopefully be able to get it all covered!

iTunes Link: https://itunes.apple.com/us/app/photo-finish-horse-racing/id993764346?mt=8

Google Play Link: https://play.google.com/store/apps/details?id=com.thirdtime.derbyking&hl=en 

Thanks for reading, now get racing!  

Read more about:

Featured Blogs

About the Author(s)

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like