Dev Blog 十一 - I Wanted to Write a Funny Joke About Depenetration But Then I Remembered Minors Read This Thing, So Let's Just Talk About How Much We Love Not Saying Curse Words

Good evening, everypony! Can you guess who it is? Can you, huh, huh, huh?!

Hold on a minute, you said… you know it’s me? How’d you guess so quickly?!

“Because you always introduce the blog posts, Bites, you nincompoop,” you’re telling me? I suppose that’s true!

I hope you’re seated comfortably and have prepared bottles (for general use) because you’re going to be here for a little while. Today’s blog update is bangin’! A bunch of our developers have contributed writeups on what they’ve been working on. If you aren’t very technically minded, do not fret! Most of what’s being discussed today is fairly straightforward.

I’d normally tell you about what I’ve been occupying myself with in my free time in the past couple weeks, but truth be told, it’s still mostly dance games and modding. Check out this dope score I got the other day!

my cool score

Oops, sorry - accidentally had it on the front facing camera.

my cool score

Anyways, let’s jump into the update.

I made levels.

level 1

Stay safe in the little half pipe, or prioritize speed over safety and try to cross through the middle, over the circles.

A fun little obstacle course! If you try to charge through too fast, you might just get flung into the abyss.

A dastardly checkerboard that moves as if it were breathing.

Just some fun shapes that I put together!

I don’t have anything to share on the background or character front right at this moment. Things are likely going to slow down during the next couple weeks for the holidays, so you might not see anything new on that front until after the new year! Sorry about that, but we’ll have news in due time, to be sure.

Let’s see what the other developers have been working on, shall we?

Greetings from your friendly neighborhood CraftSpider. Been a while, college is a fun time. But I’m back and ready to go, and have in fact already been doing some work.

First, I’ve been helping ComplexPlane with the new physics! While he did most of the work on this final implementation, I’ve been helping out a bit with the rotation math side of things. That, and in the future I intend to help improve the physics further using better motion and high-speed collision detection. Just for those of you who want to make stages where weirdly shaped objects with holes in them are flying around at mach 10.

Second, I’ve helped CraftedCart with new stage indexing. Adding SELECT statements to their SQL system, and improving the Models to make them ‘smarter’. Currently, a Model can be added to the database easily, but still has trouble say deleting itself, and there’s not a single standard way to load them yet. But we’re working on it, and soon Models should be powerful enough for us to do all sorts of fun stuff with them.

Alright, back into the codeworks for me. CraftedCart will now whisk you away into another world!

Which way is up again?

Wuh oh, the box fell over

That’s actually how Rolled Out! stages are made… I think… probably. We might need a version 3 of the stage-o-matic 5001. It doesn’t seem to know its lefts from its rights, and the conveyor output is too high such that packages tilt over when they fall off.

Jokes aside, I’ve been tinkering with the old stage loading code again, given that there were some issues with that. As much as I’m willing to abandon the old code, the new physics branch of our game is still reliant on it. One of the notable issues was our long-outstanding “solution” for stages being the wrong way up, and also flipped, when they were imported.

But first, a quick primer on co-ordinate systems. Various different 3D applications can have different co-ordinate systems: in a given co-ordinate system, each direction is defined as X, Y, and Z, in some order or fashion. Some of them like to use Y as the up-axis, while others like to use Z for up. In addition, some like to have positive X as the right axis, and are called “right handed”, while others have positive X as the left axis, and are “left handed”.

As you might imagine, converting between these isn’t the most pleasant experience. For our process, we model stages in Blender, a right-handed Z-up 3D modeler. These are then exported as FBX files and imported into the game using Assimp, which is right-handed Y-up. Finally, we take the data that Assimp has given us and transform it a bit for Unreal Engine, which is left-handed Z-up.

The three co-ordinate systems we have to work with

The easy solution, which is what we were doing before, was just to rotate everything by 90 degrees, and scale it by -1 on the X axis. This isn’t exactly the most ideal solution. It’d be better if we could fix the vertex data of the meshes, and their transforms, but it worked well enough for the old physics.

As it turns out… this is trickier that it sounds - especially when you have objects parented to other objects. In addition, I also have to fix up transforms in the config exporter plugin, to convert between Blender’s co-ordinate system to Unreal’s one. Anyways, after some twiddling around with both rotations and axis flipping and stuff, we have stuff mostly working in-game now, all ready for the physics team to work with.

Anyways, back to being bummed that packaging failed for a game jam submission.

ComplexPlane: Substantial Improvement in Collision Physics

We’ve made a lot of progress on our collision physics during the last two weeks! The ball’s interaction with the stage, whether it’s with a stationary part or an animated part, now feels quite smooth and correct.

I’ve spent a lot of time in voice calls with Bites, CraftedCart, and CraftSpider recently, and they’ve tremendously helped the process of implementing and testing some of these new physics ideas. Special thanks to Bites for constantly feeding me ideas to help rapidly debug and refine things as we went along, to CraftedCart for tackling some dreaded axis-related bugs for our stage import/export code, and to CraftSpider for some of the math code they’d written before and for implementing a fix to a stage animation loop-point bug.

Here’s a small demo video which was posted to Discord and Twitter:

The demo’s a bit brief though; be sure to hang out in Bites’ development stream or watch some of our beta testers to see more of the physics in action!

Although it took us quite some time to boil down the ideas that led to this improvement, the math itself is actually pretty simple! In this blog post, let’s go over one of the ideas behind the new physics.

Triangle-Centric Collision

Whether you’re a game player or a game developer, it’s normal to conceptualize your experience from the perspective of the virtual player which you control. In the case of the ball and the stage, it’s natural to ask: does the ball hit the stage? If so, where and how? Stages are made of many triangles stitched together, so this boils down to: given the ball’s position and velocity at some given time, which triangle(s) does the ball hit, how does the ball hit them, and how should the collision affect the ball?

It’s tricky to implement something with this ball-first mentality in practice though in our case. The ball can potentially interact with several different triangles in rapid succession, especially considering how fast the ball can move and how wacky our stages’ animation can be, and it’s not immediately clear how to resolve every case. We want to give a sensible result for each potential collision which lets the player remain in control of the ball.

During the stage testing I did with Bites (which I discussed in the last blog post), I observed that the game appears to take a simple, reversed approach: for each frame of the game loop, check each triangle in succession, and only once, to see if it would collide with the ball. If so, apply a collision to the ball: depenetrate the ball by moving the ball onto the triangle, and apply a collision response to the ball by setting a new velocity for the ball as a result of it bouncing off the triangle.

Although maybe not apparent at first, this very straightforward approach vastly improves the robustness of ball-stage interaction in many cases.

  • Each triangle “does its best effort” to affect the ball, but once it’s tested, it isn’t tested again. We never get caught in a loop where the ball bounces around and interacts with the same triangles repeatedly in a single frame.
  • By only considering each triangle once, we permit the ball to exist “inside the stage” between frames. This might seem like a bad thing at first; wouldn’t we want the ball to be on the stage at all times? If the ball rams into a concave corner at high speed, or if a platform squishes the ball between two surfaces at once, it’s often more sensible to permit the ball to partially intersect the stage for a while.
  • Trying each triangle once in a row is an inherently ordered operation. If we try each triangle in the same order each frame, the ball should behave more consistently when it needs to interact with more than one triangle simultaneously.


Triangle-Centric Collision Examples

In each frame, the ball’s position is first affected by gravity and its current velocity, as indicated by the orange arrow (for this post, we’ll assume the ball has minimal initial velocity). It is then affected by each triangle (black line) in an arbitrary but consistent order. Orange means a triangle was tested and a hit was detected, and pink means a triangle was tested and a hit was not detected.

In situation 1, the ball will always collide with the top triangle last, so the ball will consistently get pushed into the lower triangle over time. Eventually, the ball will fall through the ground. Something to note is that we don’t count a collision if the ball has passed more than halfway through the triangle. This trick improves robustness when the ball is pushed through the stage.

In situation 2, a rotating triangle pushes the ball to the left over time. Since the ground triangle is always tested last, the ball tends to intersect the rotating triangle a bit between frames. Because the ball may remain intersecting the stage, it makes smooth and steady progress rolling to the left, as opposed to more jumpy and drastic progress.

In situation 3, the ball is pressed into a hole in the ground. In frame 1, the ball is affected by the top edge of each vertical triangle in succession, placing it on top again. In frame 2, the same thing happens but the ball is depenetrated away from the top triangle such that it intersects both vertical triangles again. If we fast-forward to frame 5, we get a slightly different but still pretty consistent behavior: the ball rests on the face of the right vertical triangle.

And finally, here are a couple real illustrations of this behavior in Rolled Out, courtesy of Bites:

Next Time

There’s a lot I didn’t cover for the new physics: I was going to write a bit more, but this much already took longer than I thought, hah. For example, how we handle triangle face, edge, and vertex collision in particular really helps the new physics have good behavior. Maybe next time?

Also, while the physics certainly feels better than it did before, there’s still much work to do! Next up, I will be looking into the following:

  • Performance optimization with a spatial acceleration data structure
  • Better ball restitution and friction behavior during simultaneous multi-object collision
  • Better friction behavior on sloped surfaces
  • Better continuous collision detection

Anyway, see you next time, hopefully!

These ding dongs made me wait until like, barely an hour ago to start writing this blog post, so in the interest of time I have elected to not write any jokes in this outtro.

Also, the blog won’t be updating on January 1st, ‘cause it’s the new year!!! Deal with it!!!

See you all January 15th.