Friday Fun #12

Welcome to Friday Fun, the blog where I poke my head up from underground, let you all know I’m still alive, and hopefully entertain you with some bits about my project progress and game development experience.

Quick Scripting Performance Update

Since my last post and my retraction from it, I was able to realize more significant performance improvements with my ever-more-customized version of Moonsharp. The biggest gain came from turning the core DynValue class that holds all Lua values into an immutable type, which saved tens and hundreds of thousands of copy operations as these values were often copied into read-only copies. Turns out immutable means read-only by design, so no copy necessary! This also enabled other optimizations such as string interning and caching of common values like true, false, zero, and one. The end result was a further 40% performance improvement and a 60% reduction in heap allocations!

Variables, Variables Everywhere

Despite the large performance gains late last week after my last FF post, my focus this week has not been scripting performance (which is largely good enough for now, even in the editor). I’ve been buckling down to working my way out of the rabbit holes within rabbit holes that I had found myself in.

One of the last things I needed to do to port the gardening functionality to the Lua side of the house is to have the visuals of the plant update based on the health and growth status of the plant. To do this, I was able to make use of my Unity Component binding system that I created some time back. I created new bindings that could bind to a Targetable object’s variables, and get notified whenever those variable values changed. Along with some binders for scale and material color, and I have a really flexible solution that we can use to control the visual and physical state of object avatars from Lua. There will definitely be things like binders for animator variables, and since the binders and bindings are decoupled, you can mix and match these, and even stack bindings on top of other bindings to get things like lerping value transitions.

When I integrated GameEvents with Lua, I had the GameEvent reference the Lua script rather than have a tight 1:1 correspondence between GameEvent entities and Lua scripts. Wow was that the right decision, because it turns out that I can (and did!) stick a Variables bag named Parameters on the GameEvent entity, and then have that bag bound to a global parameters object accessible by Lua. So now, if I have multiple Lua GameEvent scripts that differ by just a couple of values but have similar logic, I can combine those scripts, and have the GameEvent inject the differing values via the Parameters bag. Fewer Lua scripts not only means less code to maintain, but also less Lua scripts that need to be parsed and loaded in memory at runtime.

I suspect that the Variables bag will become increasingly important in the ongoing design of Dehoarder 2 and keeping it extensible without the need to continuously modify the core game engine. Their ability notify on value change is fundamental.

With these features implemented, I was finally able to accomplish the earlier goal of revamping furnishing movement two rabbit holes up, which then allowed me to play completely through the vermin flow from end-to-end: Buying a trap, moving the trap into position, trapping a vermin, and taking the occupied trap to the curb for pickup.

Fun Fact: The game considers this tree to be a “Wall” for purposes of placing furnishings.

Between U and I

The last big feature I need to tackle before I revamp Chapter 1 for all of these changes is to implement Gather mode, where, instead of the current “Direct Disposal” means of disposal that was a holdover from Dehoarder 1, disposed items are placed in a bag or other container.

This prompted a big re-think about how the UI has been implemented. Up until now, each individual tool has had its own dedicated UI mode. However, with Gathering, this would further explode the already over-enumerated 33 UI modes that were in the game.

Thus begins a quest to unify and reduce UI modes. The end goal is that a UI mode should not control any logic. It should simply specify which UI elements are available.

For example, all of the modes that involve emitting some kind of projectile will be combined down into two UI modes – ProjectileWithAim and ProjectileWithoutAim, with the only difference being whether the reticle is displayed. There will be one Gather mode, and not a Gather mode for each container type. Eventually all Dialog Window modes will be combined into one DialogWindow mode (or eliminated altogether!)

A UI mode can now specify what UI Overlays it wants – this enhances the UI mode flag that was determining whether to display the status HUD. So now things like the reticle UI or the item information popup can be shared among many UI modes.

With these changes, “Tool” has become a much more formalized concept, fully becoming a database entity rather than a WorldSettings setting. The Tool definition now contains information on its transformation relative to anchor points on the character when in various states, so that “drawing” a tool can properly be animated.

Some things may lack visual UI indicators right now – for example, with the switch from global resource inventory toward each item (such as fertilizer sprayer) having its own inventory, the UI indicator for how much fertilizer is left is gone. I plan to have indicators for things like this more integrated into the environment – for example, by adding a “translucent” patch on the side of the sprayer that shows internal liquid level (which is very easily supported using the Binder/Binding framework mentioned above!) This is a deliberate design decision to increase immersion and prepare the game for VR support. Eventually many things such as the time display will be removed from the UI and instead integrated into the environment, and the use of HUD and Dialog UI will be more limited and confined to the center areas of the screen.

Until Next Time

Hopefully by my next Friday Fun blog I’ll have the Gathering flow in place and have Chapter 1 updated to accommodate. Once those things are finished, I will begin putting on the spit and polish for the game’s initial alpha release!