When Features Kill Optimization
So, in this writeup I'm going to talk about something that the other programmer on the project and myself ran into yesterday. I am not sure if it happens to other developers, but we spent the entire day on it because it felt wrong and dirty. To be honest, I'm not sure it feels any more right or cleaner today, but that's beyond the point.
So, I ask a question for the sake of curiosity:
To be, or not to be Wait, that's not it. Let's try again:
Should you kill optimization for a feature?
It's a very serious question of mine. I'll dive into more detail about the issue and how we fixed it. So, without further adieu...
I need to provide you with some background for the game real quick, since I haven't talked about it on here. The game which has no name currently is a 2D sidescrolling platformer. Yes, we'll keep it that generic because we aren't ready to talk about more to the public yet. It is being made in Unity3D (hence the tag!).
"Why use Unity3D for a 2D game?" I hear you ask. Well, let me tell you why. At the time of this post, the following platforms are what Unity3D can deploy to:
You see that list right there? Right above this sentence? Yeah, having one codebase that can deploy to all of those platforms? I'll take it.
So yes, while Unity3D was designed with 3D applications in mind (hence the name), 2D applications can be developed in it as well! And you can get a lot of the great benefits of Unity3D in your games. So, with that out of the way, let's talk about something else.
COLLISIONS! Alright, now that I've yelled at you about the topic of this paragraph, let's get into it. If you didn't know, Unity (typing 3D every time is getting really annoying) has a great physics engine built into it. You are more than welcome to take advantage of it if you'd like, but for a 2D platformer you shouldn't. Why? Because you cannot get the same fidelity in controls with a semi-unpredictable physics engine as you can with doing everything yourself. Want to put a fan in your level that launches the player in the air? It's going to take more work with a physics engine in place. Want to invert gravity? Change it on the fly? You probably see where this is going. All of this is why I decided to go with my own collision system -- raycasts.
Now, how efficient is my collision system? Extremely. Our game has no rigidbodies in it, and raycasts only happen with very specific things. The overhead is tiny. However, there is one problem...
I will forever have nightmares about moving platforms. I don't even want to talk about the amount of time it took to make sure your character didn't fall through them while they were moving up and down (side-to-side was easy). After the hours I poured into that, we hit the big bug. The one that took an entire day and ended with generous amounts of alcohol for those involved.
Jumping on a platform that is moving up.
Yep, I said it. This bug took a stupendous amount of time to fix. We knew what was happening for the longest time but had no idea how to stop it from happening... Efficiently. Let me give you the lowdown on what was happening.
On each frame, the player falls to "gravity". In the player's physics manager (that we wrote) the player raycasts for its deltaY and deltaX positions to see if it is going to hit something. This way it knows when to stop. Now bundle this with...
Platforms that are moving up. Essentially what was happening (terrifyingly consistently) was the player was falling and it would end up right on top of the moving platform, the platform would then move up into the player and the player's raycast on the next frame would no longer intersect the platform. This led to gravity ruthlessly slamming our character into the ground.
We have a fix. I don't like to talk about it but it is there. Basically, if the player was on the moving platform, then it checks to see if the player's collision box (we shrink this by 90% during the test to prevent it from happening on every frame) intersects the moving platform's collision box. If it does, then we move the player up.
Doesn't sound so bad, does it? WRONG.
When running the profiler, before this change the highest thing (after the busy wait that Unity has in it) was taking around 0.2% of the CPU time. That's nothing. After the fix... I get a little emotional here... The MovingPlatform's Update method was taking up 4% of the CPU time for the program. 4%!!! That's absolutely crazy.
So, when you play the game and see a moving platform that you can jump off of, hope your CPU doesn't overheat from the sheer amount of power (still incredibly low) that it takes to pull that baby off.
Oh well, the game still runs incredibly smooth. Stay posted for more information.
So, do you kill optimization for features?