Dev Blog 24 - Something Something Subtitle Something (Suggested By My Friend)

It’s 2 days late because I’m tired of doing work on the weekends!! Get over it!!
It would have been 3 days late because today is a Canadian holiday, but I’m very generous. You should be thanking me, really.

Over the weekends, I’ve been getting back into Garry’s Mod Lua. I used to make all kinds of fun and awesome gamemodes, and I’m back at it after a long break! Check out this thing I’m making for a streamer that I’m friends with:

In regards to Rolled Out!, things have been a little slower over the past couple weeks… but we still have fun stuff to share.
However, we’re not going to showcase any art this time!

[SOUNDS OF CROWD BOOING]

…because we have some really cool stuff that we’re working on, and I think it would be a lot more fun to save it, and show it all at once!

[CONTINUED BOOING]

Suck it up! Trust me, it’ll be worth it. I hope. Probably.

In any case, let’s jump right in!

We recently pushed the first update to our playtesters in… probably over 6 months, because for the first time in ages, the refactor we’ve been working on is finally at a BASE LEVEL PLAYABLE STATE! Obviously, this means that we’ve been getting a lot of activity!

look at it go

Well, relatively speaking. Consequently, we’ve been able to get a ton of playtesting done with players of all skill levels, and I’ve had the opportunity to do lots of level design iteration. It turns out that the best player to newbie-proof your beginner levels… is a newbie. Always remember to do playtesting with your target audience, rather than assuming you know best.

before

and after

Let’s head into the writeups by CraftedCart and ComplexPlane.


Troubleshooting

As I’m sure Brandon above has just mentioned (NOTE FROM BRANDON: I wasn’t going to, but CraftedCart said I would, and threw a wrench into the whole thing!), we’ve just recently pushed out a new beta for playtesters! Most of what I’ve been doing over the past couple weeks has been bug-fixing, mainly - fixing a few things before the new beta release, and then fixing some more stuff past then. We’ve also just recently just upgraded the engine from Unreal Engine 4.22 to 4.25, which required, you guessed it, more fixing.

So yeah, a pretty dull couple weeks for me, but here’s a couple highlights I guess.

Upgrading from 4.22 to… 4.22?

So I like to work on Linux myself. Epic don’t provide any downloads for the engine on Linux, so I end up having to compile it myself… which is fine. It takes a long time to do, but otherwise is a pretty easy process so I’m ok with it.

So, I go ahead and merge in the 4.25 changes into my local copy of the engine’s source code, trash the old build, and start building anew. My computer starts chugging for a… a while… a few hours in fact, and after all that it’s done, I go to launch the editor, aaaand… it says it’s launching 4.22 again.

Turns out, the merge failed and I never merged in the 4.25 source code - that was a fun few hours wasted.

The game black-screens when launching standalone, but not when playing in the Unreal Editor

This was a fun one because of it’s timing - it started happening not too long before we were planning to release the new playtester beta. So… turns out that during game loading, the engine was trying to load something that depended on loading BP_PlayerBallPawn, which in turns depended on loading something else, which in turn depended on loading BP_PlayerBallPawn again! This… for whatever reason… caused the engine to get stuck in some kind of infinite loop presumably, or at least it was hanging somehow. Anyways, that was a dependency chain that needed to get broken in some way.

Soo yeah, there’s a couple stories for ya - nothing too exciting this time round.


Hello again! For this post I don’t have any specific topic in particular I feel like digging deep into and rambling on about, so what about if I just briefly talk about seven different random things I’ve worked on in the last few weeks? Let’s do it.

1: Physics Body Framework

Recently I reworked our physics system a bit to make it easier to implement new kinds of mechanics in the game. Previously, it was required for objects in the game (including the normal stage meshes which the ball interacts with) to perform collision detection with the ball themselves; this becomes problematic however when one object in the game requires multiple kinds of collision. For example, goals in the game have an outer frame mesh which must act like a hard mesh collision, as well as an invisible “trigger” mesh used to detect when the ball rolls through the goal; these have separate collision detection needs, and making the goal itself implement collision detection for itself makes this trickier. In addition, the old collision framework generally assumed that object collision would usually be with a hard triangle mesh, which isn’t always the case: detecting an overlap with an invisible “trigger” mesh can be done in less steps than a “hard” mesh, and detecting collisions with other shapes such as spheres must be done in an entirely different way.

So, I decided to completely factor out the process of collision detection from objects in the game into the physics system, and have game objects only respond to collisions detected by said physics system. Game objects tell the physics system that they have “collision bodies”, such as a hard meshes, trigger meshes, or spheres, and the physics system notifies the game objects when these are collided with. Going back to the example of the goal, the goal just needs to specify that it has a “collision mesh physics body” that represents the hard outer frame mesh and a “trigger mesh physics body” representing the inner goal trigger, and the physics system reports to the goal when either of these are interacted with.

This is more conceptually similar to Unreal Engine’s collision detection system, which allows you to attach hitbox components to your actors and receive collision notifications; our system is a little simpler though since we don’t use a full-blown component system.

2: Line Trace Robustness

Some of our mechanics rely on a line trace to function properly, which generally involves drawing a line from one place in space to another point and seeing what it intersects with along the way. For example, to detect whether the ball is inside of a wind volume (more on those later), we must detect whether the ball’s center has passed through a set of triangles, or not. If the ball is moving slowly enough, the distance between the starting and ending point of the line trace may be too small, and we might not detect this small line intersecting with a triangle. To solve this, I added a line which follows behind that ball which only updates after the ball has moved a certain minimum distance. This way, the line we use to detect whether the ball has crossed a triangle is guaranteed to be a minimum length, and so this computation should be more robust.

3: Goal Loading

Goals are now showing up in the game again! For now it’s just an ugly debug placeholder model (don’t worry, Brandon designed it to look ugly himself!!) (NOTE FROM BRANDON: It isn’t ugly. It’s awesome. ComplexPlane is being mean.), but you can collide with the goalpost and we can detect when you cross through the middle. Loading goals needs to function a bit differently internally than loading normal stage meshes, since the same model needs to be loaded on different stages, so we need a separate database for objects like this.

4: Small Gravity Floor and Touch Platform Tweaks

For gravity floors, I’ve made it possible to disable line traces for a certain gravity floor. Gravity floors normally work by changing your gravity if you touch them, or if a line trace below the ball intersects them; this is what allows you to orbit around curved gravity surfaces! But sometimes this is undesirable, and it ultimately should be up to the level designers whether to enable this or not.

In a similar vein, I’ve allowed “disabling touches” on a touch platform in a touch platform group. That might seem to defeat the purpose of the mechanic, but when you touch one object in a group, all other objects in the group will start to animate. Sometimes, you’d like one object in this group to not cause the group to start animating, but still be affected if another object in the group is touched.

5: Wind Volume Stuff

Wind volumes are one among several other new mechanics I’ve been working on for the game. When the ball enters a wind volume, “wind” travelling in a certain direction should be applied to the ball. This is a little different than just applying a force to the ball; the force should be applied based on the ball’s speed relative to the wind. In addition, it’s common to approximate the force applied to something in a moving fluid based on the relative velocity squared, as well as apply more force when the fluid is more dense; in the case of air, it’s not very dense, so in order to feel realistic, it makes sense to use a small density constant so the ball doesn’t trudge slowly through wind volumes even when there’s no wind, similar to normal air.

In addition, I’ve found that it feels pretty natural to apply partial wind to the ball if it’s partially intersecting a wind volume. The way we’re determining how much the ball is partially intersecting the wind volume at the moment is a simple matter of finding the triangle of the wind volume which the ball is intersecting the least, and figuring out how far the ball’s center is from said triangle.

6: World Transform Caching

One overdue optimization we’ve finally implemented is world transform caching: previously, whenever the game needed to know where an object was in world space (aka, very often…), it would need to recompute that object’s world transform by walking up the scene graph while combining parent nodes’ local transforms together. This sort of math can get pretty expensive, and it’s silly to do when it only needs to be done once per frame. So now, that is the case.

Some mechanics cause objects to modify where they are (or where they “were”) in space when the ball collides with them, meaning some world transforms would become incorrect upon ball collision. Instead of recomputing all world transforms whenever this happens, we just mark world transforms as either “valid” or “invalid” depending on whether they’re correct or incorrect. Whenever something needs a world transform, we check if it’s valid, and if not, we recompute it. This is called being lazy in programmer-speak, but don’t worry, it can actually be a really good thing.

7: Additional Mechanics

Some of the other mechanics I’ve been working on include sticky floors, quicksand floors, springs, and conveyers. Looks like you’ll have to wait a little longer to see them fully in action though!

This is the end of the list.

Farewell until next time!


My headphones are falling to pieces… I really need to get new ones. That’s all I wanted to tell you.

Thanks for reading, and see you on the 15th.