Bullet Hell Utilities – BB – Update 16
Posted: June 5, 2025
Last Updated: June 5, 2025
Bullet Hell Utilities – BB – Update 16
Timeframe: May 24, 2025 – June 1, 2025
Here’s my first real update since the hiatus. I was working on another project making a Python backend and a frontend page with HTML, CSS, and JavaScript. I already knew Python, but all the frontend stuff was new to me. Now, I still don’t like JavaScript, but learning and making a project with it for the past 2 months has given me a new appreciation for treating functions as objects (it has also reinforced my love of statically typed languages).
It was fun, but now I’m back doing some work on the bullet hell. This update mostly deals with cleanup, but also has some cool additions, like moddable triggers and easy-bake utility panels for builders.
MOD TRIGGERS:
Triggers have been a part of the level builder for a while now, but it has been some time since I expanded upon them. The only available ones were just a few post-processing effects and a few gameplay utilities. While it was a powerful system with lots of potential entrypoints, it was also just limited to whatever I could think of. Thus, I moved towards a way to make the whole thing more modular.
- IGameTriggerProcessor: Interface for a “trigger processor”. At its simplest, a trigger processor only needs a GUID and a method (ProcessTrigger) that takes an IGameTrigger and performs some action, typically using the trigger’s “process” field to choose the action.
- Changed IGameTrigger: Instead of having a hard-coded enum field for each type of processor, instead just has a GUID field (representing the IGameTriggerProcessor), and an int field (representing the action that processor should perform).
- ModTriggerEnumAttribute: Add this attribute to an enum to mark it as an “action set” for a specific IGameTriggerProcessor. In other words, it should represent what the IGameTrigger “process” field represents when paired with a specific processor.
- GameTriggerManager Processor Tracker: GameTriggerManager now keeps a static mapping between GUIDs and IGameTriggerProcessors.
- Added PostProcessingProcessor.
- Added BulletHellBasicProcessor.
- Dynamic Dropdowns: Dropdown inputs for triggers now update. Dropdown for process automatically reads the available IGameTriggerProcessors in the static map. Selecting a new processor also changes the action dropdown with the ModTriggerEnumAttribute enum corresponding to the selected processor.

UTILITY PANEL:
- Utility Panel: InGameBuilders now each have a utility panel, which is simply a panel with buttons populated to activate helpful methods on the builder (e.g. reset preview, resave creations, preview cutscene script, etc.).
- AddUtilities: InGameBuilders can now override the AddUtilities class to add helpful buttons along with limited inputs to the builder’s utility panel.
- AddUtility: A series of methods in InGameBuilder that take a display string and a callback which helps easily populate the utility panel with buttons that perform custom actions.

CLEANUP:
InGameBuilder Improvements:
- AddBufferElement: Generic method to add an element to a buffer. Calls necessary updates so you don’t need an individual method for updating specific buffers.
- RemoveBufferElementAt: Generic method to remove an element from a buffer at specified index. Like AddBufferElement.
- ClearBuffer: Generic method to clear a buffer. Like AddBufferElement.
- Converted multiple subclass methods to use AddBufferElement, RemoveBufferElementAt, and ClearBuffer.
- RemoveBindingListElementAt: While RemoveBufferElementAt works on a passed in DynamicBuffer, this method works on a given list field of the binding object. This allows easier removal from areas that just have direct access to binding names rather than access to builders’ buffers.
- UnpackMounts fixed to utilize an OnFieldRetrievalFail argument and properly succeed/fail at correct times.
WidgetManager Improvements:
- Changed DestroyWidgetAndRemoveFromBinder to DestroyWidget. It still removes the widget bindings from the Binder.
- Removed old DestroyWidget method. There is no case I can think of where you need to stop tracking a widget but still need its bindings in the Binder.
- Changed DestroyWidgets to DestroyWidgetsWithInfo.
- Changed DestroyWidgetsWithInfo to a private method. It was only used internally.
- Removed DestroyWidgetsForIndexAndShiftBack. There were no usages of this method anywhere else.
- Removed DestroyWidgetsForFieldAndIndexAndShiftBack. There were no usages of this method anywhere else.
- Removed DestroyWidgetsForFieldAndIndex. There were no usages of this method anywhere else.
- Removed DestroyWidgetsForIndex. After removing other methods, this one was unused.
- Add DestroyWidgetsWhere, which allows custom Predicate<WidgetInfo>
- Changed DestroyWidgetsForField and DestroyWidgetsWithTag to use DestroyWidgetsWhere with correct predicate.
- Add CorrectWidgetIndicesAfter which takes in a Predicate<WidgetInfo> to determine ADDITIONAL predicates needed other than just having an index greater than input index for correcting indices.
MISCELLANEOUS:
- BindingObjectAnalyzer: Can now pass a Type into the analyzer, and it will tell you whether that type matches a top-level generic list type in the binding object, as well as return the field name if it matches.
- Enemy FiringPoint Fix: Fixed problem where enemy firing points were not spawning when spawned from a wave. Ended up being a problem where prefabification was not failing when it should have been. Fixed with UnpackMounts fix.
- Level Cutscene Fix: Cutscenes were not showing sprites when started from a level if the cutscene had not been played in the cutscene builder yet. Fixed with a LevelSetupSystem that iterates waves, looking for cutscenes and loading that data in the visual novel framework as the level starts.
- Added some more options to the top toolbar.
Also, here’s a neat pattern:
