Home Creators Posts Import Register Favorites Logout

Content

Properly architecting the game is the main way to prevent its codebase from devolving into an unintelligible, unmaintainable mess of spaghetti code.

I was going to have to live with whatever decisions I made for months, probably a year or two. Better get it right.

Object interaction

The core gameplay concept in Cutting Edge: ROM is using the correct tool on the correct thing at the correct time.

Got a laceration? Swap to the Sutures and draw zig-zags.

Got a bleeder? Use the Exothermic Torch to cauterize it, but if you're too slow, you'll have to Vacuum the blood away first.

Seems simple enough. But some objects get more complicated. Curing a tumor requires a multi-step process:

First, reduce its moisture with the Exothermic Torch.

Then cut it out with the Scalpel.

Use the Forceps to dispose the growth onto a tray.

Use the Forceps again to pinch the resulting hole shut.

Finally, use the Sutures to sew it shut.

You might also need to use the Vacuum to deal with any hemorrhaging.

(This isn't quite the Powell Procedure...)

With the example tumor in mind, you can already see that these more complicated objects involve a lot of simpler steps.

It would be, frankly, insane to code all of that up every time. We've got to design something reusable.

Composition

If you're not familiar with composition, there are loads of tutorials that explain the basic concept much better than I could.

In CE:ROM, objects that the player will need to deal with during an operation are abstracted as an OpObject. Each of these can have an arbitrary amount of what I call Ables.

They're called that because they're "able" to be done by something. For example, something that can be heated up should contain a Heatable. Something that can be moved around by the player should have a Draggable.

Likewise, the tools the player has at their disposal all have certain Doers, named because they can, well, do stuff.

The Heater talks with Heatables; the Dragger talks with Draggables.

Here, you can see the structure of a laceration, as seen in Godot. It's pretty simple: it has a Sewable component.

Makes sense, since in order to cure the laceration, you have to use the Sutures (which itself has the Sewer script). Once it's completed, the Sewable broadcasts a signal that the parent object (OpLaceration) listens for, at which point it knows it's complete.

Here's the structure of a Tumor. As previously mentioned, it has quite a few more steps to cure it. But because of composition, the logic needed to get it to work is remarkably simple.

We just need to properly enable the correct Ables at the right times. But the Ables themselves don't need to know about each other or the object that they're in at all. There's nothing special about a Heatable in a Tumor compared to in, say, a cauterizable Bleeder.

(Particular values can be tweaked, of course - such as how much heat is needed. But those are super easy to do.)

Long story short, making complicated, multi-step objects is really easy to do thanks to composition.

Furthermore, adjusting the attributes of each tool is also a breeze. Because the tools use Doers, we can put relevant values all in one place.

For example, the Ultratorch Overclock boosts the strength of the Exo-Torch. It's simply a float multiplier stored as OpOc.HEATER_POTENCY_MULT.

All that's needed to apply the effect is to incorporate it into the Heater's heat application logic:

target.apply_heat(heat_strength x OpOc.HEATER_POTENCY_MULT x delta)

Pardon the "x"es. Patreon doesn't like multiple *'s...

Easy!

There are quite a few Doers and Ables in the game, but I've found this method to be quite effective and maintainable. I'll be sure to talk more about them in the future!

...don't laugh too much.

Files

Comments

No comments found for this post.