Saturday, May 6, 2017

TrueSync and Rollback Netcode Prototype

Ever since the release of the first iteration of Battle High I worked on was release, I wish I was able to get the game working with online multiplayer capabilities.
At the time and until recently, doing so seemed very difficult for someone without a vast knowledge of network experience.  Even some of the biggest companies still have problems when it comes to fighting game netcode.
Regardless, I know, if I ever wanted to add it to Battle High 2 or to make it for a future title, that I would want a rollback netcode solution.  I know GGPO exists, but it's C++ library (making it very difficult to integrate into Unity3D), expensive to get a license, and last time I checked, not even openly available, especially to Unity devs, anymore.
I had experimented with doing it myself using uNet, Unity's built-in networking library, but the results were far from perfect and rather buggy.

Anyway, a few months ago, I was browsing the Unity Asset Store and came across TrueSync by Exit Games.  The first thing I read, which appealed to me was that it used a Rollback Engine and since I had some experience using Photon, the networking library TrueSync is based on, I decided to give it a whirl.
Though the library is not finished, I'm still impressed and have been able to get a pretty decent prototype -- at least to me.
Here's a video showing off the tool to record information I'll be discussing shortly as well as an example fighter:

TrueSync has a few aspects which were interesting to work with in Unity3D.

Fixed Points

The goal of TrueSync is to keep players in-sync.  There are two aspects of base Unity3D development that make this difficult:  floating point precision and determinism.  Because different computers interpret floating points differently, there can be problems with syncing.  To fix this, TrueSync provides its own structs such as FP (Fixed Point) and TSVector.  They work similarly to floats and Vector3's, but with the goal to be consistent between machines.
Overall, a lot of Unity3D components have TrueSync versions such as TSTransforms used to replace Transforms and track their position, rotation, and scale; however, some aspects of Unity are still nondeterministic such as the Animator and can make certain types of game, such as a 3D fighter, rather difficult to make.
Anyway, this blog goes over some aspects of TrueSync and workarounds I used to get the game working and still synced (at least to my knowledge as I haven't tested it a ton with other players.)


TrueSyncBehaviours created by the TrueSyncManager, the MonoBehaviors that manages the TrueSync scene use a method called OnSyncInput.  This method is used to take player input, send it to the opponent and then perform a rollback if it has changed.
I feel sending the less values over for this, the better, so I just send a single integer and then use a bitmask to see how it has changed.

AddTracking Attribute

Another important aspects of TrueSync is the AddTracking attribute.  TSTransform positions and rotations are tracked; this attribute is important because when the game rolls back, these parameters will be taken into account.  Overall, anything that changes on the player and is important for both players to know needs this attribute; however, I wish I knew if there was a limit or warning if you try to track too many variables.

Animation & Playables

Anyway, since I was doing a 3D fighting game prototype, I had to figure out a way to make TrueSync do the following:
  • Translate and rotate the character using animations' root motion
  • Figure out where certain limbs were on certain frames for hitbox detection
The normal animator system was causing issues with this.  Limb positions were different between users as were root positions.  The solution came in the form of Playables, Unity's newer alternative to the Animator (though recently I learned as of 5.6 and onward, this system is changing, once again.)
In 5.5, the advantage is that it allows me to set a time directly instead of letting the animator playout, which can cause problems with floating points precision errors.
To get my game working, I had to do the following:
  • Store an array of TSVectors based on frame for translation and rotation
    • I did this with a tool that plays out each playable, recording the changes in root position and rotation to TSVectors and TSQuaternions respectively.
  • Store a similar array of TSVectors for the position of different limbs.
One thing to note is that TSTransform does not have all the same functions as Unity3D's transform, so functions like InverseTransformPoint don't exist, so to get these TSVectors, I had to do a little work.  In my tool, I use the following between frames:

Vector3 prePos;
Vector3 diff = transform.position - prePos;
prePos = transform.position;
diff = transform.InverseTransformVector(diff) * 60f;
fighterInfo[currentInfo].velocityByFrame.Add(new TSVector(diff.x, diff.y, diff.z));

I record the velocity change each frame by using transform.InvertseTransformVector and store it in an array.

For rotation, I use the following:

Quaternion newQuat = Quaternion.FromToRotation(preForward, transform.forward);
preForward = transform.forward;
Vector3 v = newQuat.eulerAngles;
fighterInfo[currentInfo].rotationByFrameEuler.Add(new TSVector(v.x, v.y, v.z));

Then, during OnSyncBehaviour, the TrueSync's behaviour method, I translate and rotate these back to my characters by using the following:

TSVector vel = tsTransform.rotation * states[currentAnimIndex].velocityByFrame[currentFrame] * TrueSyncManager.DeltaTime;
tsTransform.position += vel; 


An important thing to note is I also don't let the Animator playing the Playable use root motion.  Anyway, because currentFrame uses the AddTracking attribute, when the game rollbacks because of new inputs, my character's positions and rotations are fixed and recalculated.

For keeping track of joints and other areas that need to be tracked for hit spheres, I use the following:

Transform t = anim.GetBoneTransform(fighterInfo[currentInfo].hitBoxPoints[i].boneRef);
Vector3 iP = 0.5f * (t.transform.position + t.GetChild(0).transform.position) - transform.position;

iP = transform.InverseTransformVector(iP);

I get the bone's position and average it with the first child so it feels more center (for example, I get the middle of the hand instead of the wrists.  I then subtract the root position from this and use InverseTransformVector.  In the game, when I want to get this position back, when testing hit collision, I use the following:

TSVector hurtBoxPos = tsTransform.position + tsTransform.rotation * currentState.hitBoxPoints[0].trackedPoint[currentFrame];

It's similar to my velocity, but I add the current transform position first.

Overall, this allowed me to get points that in a non-networked game I could probably get more easily, but this allowed me to get this rather accurately.

Local Multiplayer

This is another issue I was having and wasn't addressed, but most if not all fighting games have the ability to be played locally offline.  By default, TrueSync doesn't really provide this.  Photon does have an offline mode, so when I want a local match, I set offline mode on and instantiate a second player.  This player uses a different key during OnSyncInput; otherwise, both players would mimic each other the entire time since it's the same machine.

A Work in Progress

TrueSync is still a work in progress.  For example, the provided physics are still rather problematic.  I tried using them at first but characters were sinking through the floor, going through walls, and all other sorts of strange behaviour.  To be honest, I always struggle when I use an engine's provided physics, so I went with my own solutions instead -- using sphere intersection checking, distance checking, etc.

Also, it's built off Photon, which is great, but there's a lot about Photon I still need to make myself familiar with, for example, how to cleanly exit a room?  Is it usable for Xbox One games and if so, what do I need to do?  Also, Photon is not free; unless I'm okay with only 20 people being able to play at a time, which I'm not, I'd need to pay to get more eventually; unless, I'm willing to host my own server, which quite frankly I'm not.

Will I use this to port Battle High 2 to an online mutliplayer solution?  Maybe!  The issue is this prototype is going smoothly because I started working with online in mind from the start.  I did not do this with Battle High 2 A+; however, this does not mean I can't do such a thing, but I know there is a lot more work involved.

Finally, I uploaded the protoype to; if you'd like to try it, feel free!  I'd love to know if the online worked for you! (I know, from a fighting game perspective there is still a TON of work to do).

Thursday, January 12, 2017

Battle High 2 A+ @ Magfest!

So as I previously mentioned, I entered Battle High 2 A+ on a whim into MagFest's indie game showcase.  MagFest is an game and music festival near Washington DC.  Since there was no entry fee, I figured entering was a win-win.  If I got the game into the show, I'd get an awesome opportunity to show the game off; however, if it were rejected, I'd be able to enjoy the conference without the stress of presenting a game.
Fortunately for me, it was accepted!  It was a great learning experience that I would like to share.


What I Did Well

Since this wasn't the first indie showcase at MagFest, there was plenty of useful resources out there to prepare.  I believe I was pretty well prepared and did the following well:
  • Be comfortable and have food and water:  Being at a booth for 4+ hours a day can be rather tiring, especially if you're standing a majority of that time (fortunately, I had extra chairs), but I made sure to dress comfortably as well as have food and water.
One of the "delicious" snacks I had
  • Have a carpet! (or make your space presentable):  I had banners, a carpet -- actually an outdoor floor mat which wasn't too soft and conflicted with comfort a bit -- and two setups.  I think my setup could have been nicer, but it was acceptable in my opinion.

  • Get help!:  As a solo dev, manning a booth can be rather difficult.  Fortunately, I had some coworkers and friends come to MagFest to help, even briefly for bathroom or lunch breaks. 
  • Have back-ups!:  I had my Xbox One with Battle High 2 A+ on it as well as my Microsoft Surface.  I also brought 3 monitors and extra cables.  Having 2 setups was great -- allowing more people to play the game -- but it was also good in case something broke!


 What I Could Have Done Better

This was the first time I had really shown off the game at a gaming venue, so there were a few things I could have done better.
  • Bring a dolly cart!  I recently bought a new car with a lot of room, which made transporting all of the monitors and other gear easy; however, taking it from my car to the hotel was rather frustrating.  A dolly cart would have made this a lot easier.
Would have helped so much...

  • Make it easier to see you worked on the game.  The first and second days of MagFest I wore Battle-High-related gear; however, on the 3rd and 4th days, I didn't, so people didn't know I had worked on the game and thought I was just watching or waiting for my turn to play.
A photo posted by Matt (@mattrified) on

  • Give credit better:  Though I work primarily alone, a lot of talented people worked on Battle High, and I wish I had better information about them when asked.  A lot of people would ask about the pixel artist or the graphic designer, and it was awkward trying to explain the situation of those individuals with people.  Having their business cards -- with their permissions of course -- would have made this easier.
  • Better print materials and swag:  This is mixed.  People liked my buttons -- which I'm practically out of -- and business cards.  I also had post cards -- which were the best thing to give out -- however, the post cards didn't have accurate or enough information.  For one, it only listed that the game was out for Xbox One and  Unfortunately, right after printing, I published Battle High 2 A+ on Game Jolt, so I had to tell people this directly.  I wanted to print out a new post card with the additional platform, as well as information on the back about Battle High 2 A+'s history (pictured below), but I procrastinated -- THANKS, CHRISTMAS. 

  Another thing I did is I get pencils printed.  Though I thought this was a neat bit of swag, they didn't go as well as I would have thought -- and now I have over 300 pencils! Regardless, the misprinted postcards were probably the most frustrating part of this.

A photo posted by Matt (@mattrified) on

  • SPEAKERS!  I bought really nice BenQ monitors for MagFest that had built-in speakers; unfortunately, I didn't realize till later that they were rather quiet.  I should have bought speakers as well.  No one could hear the sound design, voice acting, or music, which was especially embarrassing when the sound designer showed up to player -- SORRY!
  • Let people play themselves.  On the first day, some people wanted to play and instead of letting them play Arcade, I would volunteer to play them in Versus, probably scaring some of them away.  Though, and this was a bit awkward, a lot of people would ask me, "Hey, can I play?" to which I sometimes looked at them like a confused dog.  I guess maybe they thought I was in line to play or something and not the dev, but still, I wasn't sure what to say.
I think I nearly did this at least once.
Overall, showing my game off at MagFest was a great learning experience.  I met with a lot of people who were enthusiastic to play the game as well as its future and some that even showed interest in working with me in the future on updates or new titles.  Sure there were some people who weren't interested or poked fun at the cheesy dialogue, but nothing heinous and nothing directed at me like "Go jump off a bridge!"  The worst comment I heard was "Oh geez, I never heard of this game before!" which mostly made me realize my lack of marketing.
I got to see people play the game in a competitive setting which is probably the best way to learn about the game and I learned a lot.  For example, I learned that Beat has a nasty high-low mix-up, and that Jada's Lightning Whip's are overpowered.  I also got to witness the first (that I'm aware of) Battle High 2 A+ tournament!  Sure there were only 12 entrants and 4 of them didn't show, but it was still awesome to see!

Footage of the Battle High 2 A+ Tournament in Action!

I also got to see the game played at MagFest Versus -- a Nick Arcade-like gameshow held at the festival.

Footage taken from MagFest Versus!

Now, I've heard developers complain that sometimes cons aren't worth it, that a lot of people will say they like your game and will buy it but then "forget" to after the show, but you know what?  I don't really care.  I had a great time, learned a lot, and would love to do it again either at MagFest or another similar con with Battle High 2 A+ or another game!

Wednesday, January 11, 2017

2016 In Review

So it's over a week into 2017, and I realized I haven't written much about 2016.  I wanted to take some time now and write a (semi) game-development-related retrospective of 2016, its highlights, lowlights, and maybe a midlight.

Lowlight:  Rushing a Game for IndieCade

Though it was a learning experience, the year did start off a little rough.  I had just come off of releasing Battle High 2 A+ on Xbox One in December of 2015, so I was taking a bit of a break from game development in the beginning of the year.  Soon though, I was trying to finish a game for IndieCade, an independent game festival.  The entries were due in May, so I figured I had enough time to get at least a competent prototype done.  I was working on a merfolk themed tactics games with fighting game elements.

Though I made some good progress, I still felt I was rushing and was unhappy with what I came up with.  I wrote about this on Gamasutra.  Since then, I've decided to start the idea over.  One issue with it was that it was starting to feel too copied and unoriginal.  I don't want to use the grid-based system for movement.  In addition, I just wasn't happy with the art.  I want to try something else and I don't want to rush the game for some contest.  Though I think deadlines are important, setting one that is too soon can make the project feel insurmountable.

Highlight:  Patching Battle High 2 A+ Successfully -- Twice!

After taking a break from the merfolk game, I decided to do a small Battle High patch.  I was pleased, once again, with how easy it was to update it through the ID@Xbox program.  In fact, later in the same year, I decided add a new character to Battle High 2 A+ named Beat -- which I wrote about in previous blog posts.

Lowlight:  Oral and Other Health Issues

Before the Beat patch, however, I had some drama.  Around July, one of my teeth started bothering me.  The dentist didn't quite know what was wrong, noticing that the tooth was wiggling a bit.  Because I had trips coming up in October, I was nervous about doing anything major, especially after being told by the endodontist that nothing seemed problematic in the x-rays.  Fast-foward to mid-October, right before Unite (one of Unity's yearly conferences), I go in for a checkup and my dentist discovered the tooth wasn't cracked but that the crown was loose.  She recements it, and the problematic pain returns the following weekend.  I then go through a root canal retreatment -- essentially a root canal on the same tooth.

Imagine having this done on the same tooth...twice

Overall, this isn't very game development related, but things like tooth pain are distracting.  From July to October I was worrying about my tooth, seeing if it was a gum infection or a cracked tooth, using an over-the-counter bite guard, not wanting to have an unnecessary extraction done, but worrying about it nonetheless.  At the same time, I was also having lower back pain back in February when I was working on the tactics fighter which made working a bit distracting -- this was mostly due to bad posture while working for long hours.  This made me come to the conclusion that I need to be more assertive when it comes to self-care.  I need to be less afraid to get something done instead of waiting-and-seeing, and I need to exercise and do more preventative care.  I need to sleep more and eat healthier.  These are all resolutions, and I've made progress on some.  I've starting speaking to an e-therapist to help with my depression, and I bought a treadmill (though I should have bought an elliptical machine) so I can jog (or at least walk) when it's ugly or too hot outside.

Highlight:  MagFest!!!

Another good thing that happened though is that around August, I decided to enter Battle High 2 A+ into the indie game showcase at MagFest -- a music and games festival near Washington DC.  It was accepted, which was a great -- yet rather stressful -- experience.  I'll write about that more in detail in my next posts.

MidLight:  Featured Blog

Admittedly, I can be a bit of a scrub at time...
I wrote a blog article about accessibility in fighting games, which got featured on Gamasutra.  I was excited to have it featured; however, some feedback on Twitter was rather harsh and made me worry that I had tarnished my reputation somehow, that if I were to release fighting games in the future, the genre's communities would see my name and ignore it.  I realized a lot of the criticism wasn't correct though, that people focused on one small argument while ignoring the a good majority of what I wrote.  What I said is that better tutorialization and simpler inputs could help with fighting game accessibility, not that they were the ultimate or only solutions.


Despite knowing that they are cheesy at times and almost none of them happen, I'd like to make some resolutions or goals for 2017:
  • Practice better self-care -- eating habits, exercise, sleep schedule, etc.
  • Prepare a game that I feel comfortable publishing before May of 2018
  • Write more blogs -- both here and on Gamasutra
  • Organize my web presence / social media accounts -- instagram, twitter, tumblr, etc. -- better
  • Don't let criticism hurt my progress or confidence and instead learn from it
Thanks for reading!