Sharing Unity Code: The Journey

Introduction

At Space Ape we have a lot of shared code which we use across all of our projects. As of now, we have 57 shared code modules; these range from messaging systems, logging and our in-game console, to crowd rendering and asset processing, .

Why Share Code?

  • We don’t need to spend time reinventing the wheel.
  • We have the flexibility to take the shared modules we require.
  • We’re confident that this code comes with a suite of unit and integration tests.
  • We know it’s been proven in practical use across previous projects.
  • We are all familiar with the code, making project start-up times much faster.

Sharing code allows developers to focus more on the final product, in our case the games we create, because they spend less time worrying about low-level implementation details and non functional requirements.

The Journey

All of this shared code didn’t just happen overnight. We’ve tried and failed quite a few times with our release process, distribution and collaboration. As a result of failing and learning from these failures, we’re now able to easily share our code, and developers from various projects are all contributing to it.

The process is by no means perfect – we’re still working out the kinks – but it’s improved our workflow a lot, and maybe it will work for you too.

At the Beginning, there was only Ctrl+C, Ctrl+V

When Space Ape first started we were all focused on one project, so there was no need to share code. We were a start-up and our primary objective was to ship a product.

When the time came to start our second project, some of the code was copied over from the first project and we remove any project dependencies, but we had a code base to start with. Our first title was still being developed, bugs were being fixed, and features were being added.

Whilst all of this was happening the two code bases diverged quite a bit. If a bug was fixed in one of our games, there’s a good chance that fix didn’t make it into the other game – the same goes for features and improvements. As each project went on, the ‘shared’ code was modified to fit each project, and in the end sharing code between projects was more hassle than it’s worth.

Context of the Problem

Roll forward a few years. We now have a few established games, Samurai Siege, Rival Kingdoms, Transformers: Earth Wars and Fastlane, and we’ve entered into a partnership with Supercell.

Unsurprisingly, our company goals have changed a bit. We’re no longer a start-up in the true sense of the phrase. Our goal is to create a genre defining mobile hit, and in doing so we are moving away from our build and battle heritage.

We are branching out into many new genres, so we need to iterate quickly. We can’t predict that every new game idea will be a success. We need to try new things rapidly, and learn as quickly as possible.

Having a solid foundation of shared code would help us to iterate faster. In order to do this we would have to look at how we could share code between projects, with as little pain and slowdown as possible. When it comes to sharing code, the biggest obstacle is not writing the code itself, it’s the tooling and practices around releasing and distributing it.

Enter Git Submodules

Git Submodules are like a repository within a repository. You can continue to work on your code base and once you’ve finished a feature or fixed a bug, you can check it in. You just push your shared code up to one repository, and your project’s code to another.

This seemed ideal at first! We were already using Git across our studio so everyone was familiar with it. But we soon ran into problems.

As the source code is there for you to edit freely, teams would obviously change shared code, check it in and then when the other team pulled changes, their code wouldn’t compile! This sounds a little lazy and reckless, but this issue stems from the fact that there is no boundary between what is shared code and what isn’t. From a team’s point-of-view, they are just changing code in one big solution. The ideal solution here is to expose a simple yet well-defined API to the game teams.

So once this became an issue, each team decided to branch the shared modules off the master branch, and we were back to square one. Two diverging code paths, never merged together.

Further to this, we found that anyone who’s not a developer (artists, animators etc) can have quite a hard time using submodules. The tooling around submodules isn’t straight forward. Often we would update a submodule but someone wouldn’t pull changes for that submodule, so project and shared code would get out of sync.

Maven

Our server developers use Maven to manage and release packages. Maven is a tool developed for the Java ecosystem. When you are ready to release your project, Maven will take all of the information within a pom file and then package up your code so that it can be shared with others.

Because of all the features offered by Maven, and the fact that it’s not a native .Net tool chain, it often felt more complicated than it needed to be. Out of the box it comes with things like build life-cycle management. But at the end of the day all we were really interested in was dependency management, versioning and packaging; and that came with a lot of overhead. We ended up creating custom build steps to install our packages which made our build and release process even more complicated. As it wasn’t natively supported (or developed for) either Unity or .Net we felt that there must be a better solution.

Unity Packages

Because we are using Unity, the next technology that came to mind was Unity Packages, just like you see on the Asset Store. It was really easy to integrate. However, the whole release process and package storage was quite unregulated. There’s no real package versioning support and no dependency management. You also need additional tooling to uninstall a package as there’s no defined package structure, so we would have to clean up the old package before installing the new one.

Finally, Unity packages traditionally contained source code. We wanted to stop teams making changes to source code within these shared modules and improve compile times. This meant we needed to use Dynamic Link Libraries. DLL’s also allow us to easily develop shared code modules that depend on other modules, without having to make sure that the source code for the dependency was the correct version and compiled in the first place. Whats more using DLL’s would also lead us to faster compile times.

So we looked elsewhere, and found:

NuGet

If you’ve not come across Nuget before, it’s a package management system designed specifically for the .Net framework and it supports dependency management. There are currently over 110,000 packages on the public repository, some of which we were already using. However this repository is public, and a lot of our code isn’t for public release, so we couldn’t just go ahead and push our packages up to this public repository.

Before we could make a start there was quite a bit of work involved in setting up a whole development and release process around Nuget, not to mention setting up our own Nuget package server and getting everything to work nicely with Unity. In my next blog post I’m going to take you through everything, from start to finish.

Creative Engineering: The Source Of Your Imagination

In another instalment of our technical events series, today we hosted Creative Engineering: The Source of Your Imagination.

In this jam packed event we heard from Tom Mejias, Bill Robinson and Matteo Vallone.


Tom Mejias spoke about how we decide which projects to start, and which architectures we use to get them off the ground. He described our fail fast philosophy on prototyping, and the razors with which we judge our prototypes.

His slides outlining his approaches and learnings are here:


Bill Robinson gave us an insight into how animation curves can be used for game balancing with his Multi-Curve editor. He also introduced UIAnimSequencer – a tool to quickly add juicy transitions and animations within Unity.

You can see his slides including his video demonstration here:


Matteo Vallone revealed how to make your game stand out and give it the best chance of success in the market. As former Google Play Store Manager he gave a valuable insight into making a big impact with your game launch. Now as an early stage game investor, he described how to maximise your game’s discoverability by building a beta community, engaging with app stores teams and partnering with influencers.


 

We are always looking for talented game developers at Space Ape Games. If you’ve been inspired by hearing about how we work, have a look at our careers page.

A video of the whole event will be posted here shortly. Follow @SpaceApeGames for all the latest announcements.

Discover our games on the Space Ape Games site.

Trajectory prediction with Unity Physics

In some recent prototyping work, we needed to display a prediction for a projectile trajectory in the game. You’ve probably seen something similar in many games before, such as Angry Birds:

AngryBirdsTrajectory

The tutorial from Angry Birds 2. Note the dotted line, showing you the predicted trajectory of your bird, if you released the slingshot now.

Our prototype game was in Unity, and the projectile was set up using Unity’s physics engine. We had several requirements for the prediction:

  • Immediate. Player input can change from frame to frame, and the prediction needs to stay in sync with it.
  • Accurate. The time of flight could be several seconds, and any small error will accumulate to product significantly incorrect results.
  • Simulates drag. We’re using drag on our rigidbody, which many solutions do not account for.

I assumed this sort of problem came up often and searched online to see what popular implementations were out there. They generally fell into three groups:

  • Accurate, but slow. These solutions introduce an invisible projectile clone into the world and launch it along the flight path, recording its motion over time. As there’s no way to step the Unity physics simulation along yourself, you have to wait for this prediction in real time. This means that a three-second flight takes three seconds to fully predict. This is far too slow – the prediction would constantly lag behind the player’s changing inputs.
  • Doesn’t include drag. There are some good, accurate solutions, but most will specifically rule out drag.
  • Inaccurate. Some combination of incorrect equations, assumptions, and approximations meant that with longer flight times and more drag (or different gravity) the prediction would be wrong.

Perhaps the perfect solution for us is out there, but I hadn’t found it. By combining existing solutions and running some tests, I came up with my own implementation, which is presented below.

 public static Vector2[] Plot(Rigidbody2D rigidbody, Vector2 pos, Vector2 velocity, int steps)
 {
     Vector2[] results = new Vector2[steps];
 
     float timestep = Time.fixedDeltaTime / Physics2D.velocityIterations;
     Vector2 gravityAccel = Physics2D.gravity * rigidbody.gravityScale * timestep * timestep;
     float drag = 1f - timestep * rigidbody.drag;
     Vector2 moveStep = velocity * timestep;
 
     for (int i = 0; i < steps; ++i)
     {
         moveStep += gravityAccel;
         moveStep *= drag;
         pos += moveStep;
         results[i] = pos;
     }
 
     return results;
 }

This function plots the trajectory of a rigidbody under the effect of Unity’s physics by simulating some FixedUpdate iterations and returning the positions of the projectile at each iteration. It uses the global Physics2D.gravity setting, and takes into account rigidbody drag and gravityScale. Note that the mass of the rigidbody is irrelevant.

float timestep = Time.fixedDeltaTime / Physics2D.velocityIterations;

The code attempts to produce the same results as running the normal Unity physics iterations. To do this, it must also run as an iterative solution. A common error here is to assume that one iteration is run every FixedUpdate(). Instead, the number of iterations to be performed is accessible and tweakable – it’s Physics2D.velocityIterations. This helps us compute the timestep.

Vector2 gravityAccel = Physics2D.gravity * rigidbody.gravityScale * timestep * timestep;

We take into account the rigidbody’s gravityScale property when computing the effect of gravity. We found that we wanted a different amount of gravity and drag on each object, so this per-body setting was really helpful.

float drag = 1f - timestep * rigidbody.drag;

Drag acts as a reduction on moveStep in each iteration. We can compute it upfront and then apply it to each step of the iteration, producing a cumulative effect.

for (int i = 0; i < steps; ++i)
 {
     moveStep += gravityAccel;
     moveStep *= drag;
     pos += moveStep;
     results[i] = pos;
 }

Finally, the main loop. Each iteration, you’ll move due to gravity, reduce the movement due to drag, and then accumulate and store the new position in the results.

This solution worked well for us. While not exhaustively tested, we used it for projectiles that had lots of different velocities and drags, and it proved accurate each time, even after 4-5 seconds of flight.

 

Drawbacks

There’s a lot of computation involved for long trajectories. With default settings, you have to run the loop 400 times for each second of flight you want to predict. We only have one projectile to predict in our prototype, so we’re just running one prediction, which doesn’t cost very much. If you used this to predict lots of projectiles for lots of different launchers in a large scale game, perhaps this would begin to be a problem for you.

Also, it’s only simulating the trajectory, and not actually running the physics engine or simulating anything else in the game. This means it doesn’t predict collisions or collision resolution. If you render this path as-is, it’ll just clip through walls or other obstacles in the world, which obviously isn’t actually what will happen when the projectile is launched.

These drawbacks weren’t a problem for our prototype, so it turned out to be pretty useful code. We share this now in the hope that someone else out there is faced with the same requirements and finds it useful too.

 

Possible Future Upgrades

I have some ideas around the drawbacks of this method. This is the main area for improvement, as the actual functionality is fine.

For performance, no profiling or optimisation work has been performed. I’ve just laid things out in the way that made sense to me. It’s hard to guess at optimisations, but perhaps a little profiling would reveal some simple speedups. The bigger step would be to push this code out to a native dll and get down to nitty-gritty c++ optimisation – perhaps with SIMD instructions. You can’t parallelise the steps (each iteration of the loop depends on the result of the previous) but you could parallelise multiple projectile predictions – e.g. if you have many projectiles, run 4 or 8 predictions in parallel.

The other big upgrade is around prediction. For some games a true prediction would be really valuable – for example, visualising the outcome of collisions and reactions in a pool table game. You’d want to see the predicted path of the ball, even after several bounces. This isn’t going to happen with any simple model if you have any in-depth physics properties. You’d need a big shift in your approach – to run the physics engine yourself. I’d find an appropriate existing physics engine and build it into the game/Unity, which is a shame as it’s duplicating the work that Unity’s already done. But after doing that, you’d have control over the physics simulation and how you update it.

You’d try for a setup where you’d be able to clone the existing simulation and run some update ticks – to, essentially, look into the future – you’ll be tracking the future state of the simulation, assuming no inputs change. This would have to be a separate simulation, as you wouldn’t want the actual state of the pool table to change – just to compute the predicted future state. This will be even more expensive that just running the basic prediction code we had above – it’s the full physics simulation.