Dev Story: Natural Born Soldier – A Fun Multiplayer First-Person Shooter for Mobile
This guest post was written by Eric Lajeunesse, an indie developer from Montreal, Canada.
Ever wanted to step into a real soldier’s shoes as a crazy warrior with a shotgun, a stealth attacker or an agile sniper? Natural Born Soldier gives you this opportunity from your mobile as it delivers precisely what you expect as a competitive multiplayer shooter. Intuitive and smooth controls coupled with incredible and unique gameplay.
Natural Born Soldier is bringing you something pretty awesome: the game allows you to make your soldier authentically you by transposing your own image onto your 3D soldier’s face using a photo or an avatar.
Natural Born Soldier offers classic game modes like Free-For-All, Team DeathMatch, but also high-adrenaline game modes like «Search & Protect», a co-op survival mode, plus numerous new weapons to unlock as you progress through the ranks.
Natural Born Soldier comes deep from my passion for the FPS (first person shooter) games genre. I like the adrenaline that is generated when shooting at someone, making a nice kill, or being shot and running for your life 🙂 Of course all those in the context of a game.
I used to play more FPS when I was younger and the one I played the most was Rainbow 6 on PC more than a decade ago. At some point in 2012 Unity was giving a free license for one day only so I did apply for it and started playing with it. In parallel I was playing some FPS games on my iPad. I found Unity pretty cool and at the same time was kind of frustrated with the FPS games I was playing on mobile. So I figured out that it would be a really good challenge to create my own FPS game on mobile and that was when this crazy project was kicked off.
Natural Born Soldier is a cross platform FPS for mobile devices (iOS and Android mainly). Since day one I had clearly in my mind that I wanted to put the emphasis on the multiplayer aspect which is the part I like the most personally. I wanted to innovate on many fronts: the controls, the multiplayer game modes and also on the customization of the player itself.
Multiplayer FPS: feasible on mobile?
As I was playing some FPS on mobile I knew it was possible to create such game on mobile, but I was not sure it was possible with Unity. Furthermore, I had planned at the beginning to support 16-32 players, but I was not sure if that would be working at all on mobile devices.
I started investigating which network framework I could use for that as after little investigation I figured out it was totally useless to create my own from scratch and it would be too time consuming. I also had clear in my mind that going with a Peer-to-Peer (P2P) network framework would probably be my best shot in order to support such a big number of players and also scalability wise instead of going as a classic client-server (C/S) architecture.
I did read about Photon at first, but had some concerns as it is a C/S architecture and regards its data transfer limit (500 msg/room/sec.). Then, I did look at Badumna (from Scalify – R.I.P.), this was a new well-crafted P2P network framework that I considered the only good one that seemed to have a bright future. So I decided to jump into that one as it was looking good with the requirements I had in mind.
After about 6 month implementing my game and after having integrated the core part of Badumna into my game, I figured out after testing on a couple of devices that connectivity was not working so well and it was also requiring a lot of CPU resources in order to maintain all the TCP/IP peer’s connections. Having ~4 connected client was ok, but once going above that, the game’s frame-rate on my iPhone4 was dropping considerably which was not acceptable.
On top of that, there was another major problem: before allowing to connect with other clients, you needed to connect to a master server first in the cloud, but establishing this connection was a problem as sometimes it was taking as long as 1-2 minutes, which was really unacceptable and not consistent over time.
Client/Server VS. Peer to Peer networking framework: moving to Photon Unity Networking (PUN)
So after loosing some hair and being frustrated about Badumna, I had the feeling that this was not going to work out at all and I needed to change direction. Not an easy decision, but a good one at the end :).
So I decided to step back and read more deeply about Photon and other networking frameworks. I ended-up concluding that Photon was my best option now as I did found that P2P was not giving good result at the end performance wise, so I wanted the classic C/S architecture framework.
After some calculation I did figure out that the data limitation and the price was not really a problem at the end and fair enough :), so I jumped in. Nevertheless, because of the data limitation (500 msg/room/s) I did limit my maximum number of players to 8.
I had estimated about 1 month of work in order to replace my Badumna integration with Photon (PUN), but I end up really surprised that I was able to-do the migration within two weeks :). This was mainly because PUN was straight forward and also because I properly separated my network integration from the other layers (e.g.: GUI). Once it was implemented I’ve continued the development for more than a year and I can say that I never faced a connectivity issue using Photon Cloud. That was pretty amazing.
Photon Cloud and PUN: tweak the engine
While Photon was pretty straight forward to integrate, this doesn’t ensure your game’s multiplayer experience will be good. You need to use PUN and the tools provided properly in the context of your game to make that happen.
The first challenge I faced was the smoothness of the players that was not good enough; it was choppy and didn’t look good. I was using interpolation in order to smooth the movement at that time as shown in the demos coming with PUN, but somehow sometimes it was not working.
I figured out that sometimes old packets were coming in and this was generating glitches or message rate was not coming as often as planned. My message rate was initially at 15Hz (15*8*8 = 960 msg/room/s) which I figured out would not be working in production (> 500 msg/room/s). Finally, I end-up using 10Hz (10*8*8 = 640msg/s/room, but since I used “Unreliable On Change” on my player’s transform this averages down to ~500) frequency for player’s position, rotation and body angle, and interpolating this locally with some interest management to minimize CPU resources on the receiver part. For example, on the receiver part I only do the full smoothing calculation if the local player is actually seeing the remote player being processed, otherwise I only update the remote player information without doing any smoothest computation.
In addition to the information mentioned earlier, I also added a “short” to be sent in player’s OnPhotonSerializeView to be sure I would never process an old packet and get some glitches as mentioned earlier, as somehow PhotonMessageInfo.timestamp couldn’t be trusted at 100%, at least according to what I have experimented.
Furthermore, in order to minimize cheating and send sensitive data to other players in a secure way (eg: player’s photo, critical RPCs like when a player is receive damage, etc.) I needed to add a public API into PUN in order to be able to send encrypted RPC calls. This functionality has been added officially into PUN by Exit Games, the Photon creators.
Another area which required me more effort than anticipated (and which is not complete yet, as my Android version is coming) is how to handle properly the player’s state when the game goes into background, or when some native UI just popup on top of the game, like when a SMS notification come in, low battery popup, or if the player slides down/up the quick settings panel in order to change the luminosity of his screen etc.
At the end, I had to-do the following modifications for iOS (Android TBD):
- When a player goes into background, since I do not know when he might comes back, I disconnect him right away from the room, and in case it’s the master client, he will call PhotonNetwork.SetMasterClient to delegate his master role to another player, so that the game can continue working properly right away.
- When a native UI show up, OnApplicationPause is called (Unity related, not Photon), but in such case since this may be temporary, I don’t disconnect the player right away. I allow the player 10 seconds to-do his thing, and if he doesn’t come back by that time, I disconnect him as if would have gone into background. In order to achieve that, I needed to modify a bit the file UnityAppController.mm in Xcode among other things.
What’s next?
Natural Born Soldier for iOS has been released on October 21, 2015 on the App Store. I’m now working on the next update which will include a new map and couples of fixes, and in parallel I’m also pushing for the Android version, which will require some tweaks to manage properly the player’s state too among others things.
I hope to see all of you reading this on the battlefield so I can kick your ass 🙂 lol.
PS: in case of any questions please get in touch via elajeunesse@naturalbornsoldier.com
Best,
Eric