Code Judo

Hey everyone,

I’m Johnnemann. As Steve explained in our initial announcement post, I moved up to Portland to help found the Fullbright Company as the programmer of the team. I’ve previously worked on some internal technical stuff at Sony during the PS2 era and the launch of the PS3, and then moved to 2K Marin to help release BioShock for the PS3. I turned to UI, gameplay, and AI programming for BioShock 2 and XCOM, and now here I am, going from a series of very specialized roles to having to remember/learn every aspect of game programming at once, from the fun stuff like player actions to the boring-but-necessary things like configuration screens.

As Steve mentioned, we’re using the Unity engine for our project. This is a bit of a learning experience for all of us, as we’re coming from a professional background in the Unreal Engine.  But so far, as a programmer, it’s turned out to be a wonderful experience: most things are easier than I expect them to be.

However, every once in a while the easiest way to approach a problem isn’t obvious from the beginning.  A few days ago, we realized we had a bug with our doors and drawers that you can see in the video.  They’re using Unity’s physics system to move, in order to allow cool effects like things rolling around inside. Behind the scenes, this effect is achieved with some hinges and springs that move the object along a constrained path, according to the physical forces acting on them. The player, though, is also an entity with a physics presence in the world – specifically an infinitely-strong capsule-shaped presence.  We discovered in playtests that the player’s collision capsule would sometimes interact in unexpected ways with the moving doors and drawers.

Low doors, when opened near the player, would sometimes slide under the edge of the player’s collision capsule and pop the player way up into the air, occasionally even shooting the camera out of the house entirely. The same would occur with bottom drawers. Essentially, it was as though a step had suddenly appeared underneath the player and the system overcompensated for it.

That ain’t so good.

The player could also attempt to walk into an opening door, and being of infinite strength, essentially tear it off the hinge. Sometimes, doors would end up embedded sideways into the wall or ceiling, or stretched in weird and eldritch geometries across the threshold.

That either.

Amusing as these various events could be, we knew we couldn’t ship a game where the player could inadvertently perform origami on a cabinet door. But I was stymied by the lack of options we had for changing physics-related things in the engine – Unity makes it very easy to do most things you’d like, but as a corollary to that, most of the powerful handles are hidden away where they can’t be touched, or at least not easily.  So we went back and forth for a while, trying to come up with something we could do. Make the player’s capsule a cylinder, so that drawers couldn’t force themselves under it? There wasn’t support exposed for that, and it would probably break going up stairs. Make the player have less than infinite mass, so that doors could push the player out of the way? That would involve re-writing all of the boilerplate player-movement code we were using, and could have undesired side-effects on the player’s interaction with the world.

Steve and I talked back and forth about various ideas and solutions, and kept running into the fact that Unity wouldn’t let us get into the guts of the systems, so we couldn’t fix any of the fundamental problems these physical interactions were causing. Finally we just decided to work with Unity, rather than fight it. We discovered some sort of Zen acceptance or fatalism, and we came up with two solutions easily: To prevent doors and drawers acting like sudden stairs under the player, we just changed the player’s step height so that Unity would no longer try to step the player up onto things as high as that.  And then I wrote some fairly simple code to detect when an opening door had hit the player, and stop it moving under physics at that point. Now doors would just lock themselves into place as soon as they couldn’t go any farther, and the player would have to clear the area in order to fully open or close them.  Both of these tasks were very simple in Unity and the door and drawer systems I had already written – so much so that the solution probably took about as much time to implement as all of our previous discussion.

Here’s the very simple result of this (code edited to remove unrelated functionality):

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject == Player)
        {
            FinishSwinging();
            /..../
        }
    }

	void FinishSwinging()
    {
        IsSwinging = false;
        rigidbody.constraints = RigidbodyConstraints.FreezeAll;
        /..../
    }

As a gameplay programmer, I’m often asked by designers and artists to solve problems. One of the most valuable questions I can often ask of either others or myself is “What are we trying to accomplish?”.  It’s all too easy to get sucked into trying to solve what looks to be the root of a problem, or the problem as expressed by a designer, and come up with some over-technical, convoluted solution.  Or to go the other way, and deal only with the surface problem by fixing the easiest-to-see instance and leaving an entire rotten system festering beneath the surface that will inevitably burst out in gangrene when you’re trying to ship.

In a perfect world, you would be able to build a flawlessly precise physics simulation, and be able to support edge cases like a cabinet door that’s one inch tall – but often all you’re really looking for is the most efficient compromise that will prevent the player from being suddenly catapulted into outer space.

This entry was posted in Programming. Bookmark the permalink.

3 Responses to Code Judo

  1. onetinyleap says:

    Very elegant solution. I hope you get to make more posts like these.

  2. Brian Takita says:

    Thanks for the post Johnnemann! I really like the narrative and your process in solving this problem.

  3. Jeff Fisher says:

    As I recall the doors in “The Suffering” would swing back closed or open if they ran into the player while trying to open or close (so return to previous hopefully good state where nothing is stuck). They would also heavy-hit react players and AI’s out of the way when opening in somebody’s face (luckily appropriate for that game). Blocking volumes would also spawn around moving doors so players and ai’s could not move into moving doors. The doors weren’t using real physics though.

    Doors, so hard.

Comments are closed.