Texture Atlas, Settings, and More – BB – Update 17
Posted: June 29, 2025
Last Updated: June 29, 2025
Texture Atlas, Settings, and More – BB – Update 17
Timeframe: June 2, 2025 – June 28, 2025
Welcome. It feels like these updates just get more wordy and tedious each time, but I promise it’s because there’s a lot that went into the actual development. Sometimes those developments are only interesting to me, though. This time around, focus is mostly on a generalized settings menu and revising my texture atlas approach/fixing some texture memory leaks and other memory problems. Oh boy, fun!
TextureAtlas (And Memory):
- MultiTextureAtlas: contains multiple separate atlases to hopefully reduce precision-related problems when calculating UVs.
- TextureExtensions added for Pad, Binarize, Scale, ScaleToSize, Grayscale, and Chromakey.
- Memory: Looking at the profiler, there textures seem to take up an excessive amount of space. Some is unavoidable (textures for individual sprites and texture atlas), but it still seems large. Found a bunch of spots where textures were being made but not destroyed later.
- Artifacts: Testing atlas with various images causes the weird box artifacts again. After tons of attempts, I finally found the problem: mipmaps. I thought I had set the mipmap count to 1 (basically none), but it was being set higher when adding textures from file to the texture atlas because the loaded textures had mipmaps. Doing this also improved the memory situation because the texture atlas no longer had to store mipmaps.
- SpriteAssetManager improved to reuse certain textures and destroy unecessary textures when opening a new project. Texture count should now break even when opening a project (instead of leaking).
SettingsManager:
- SettingsManager: Ported and heavily changed from a different in-development game.
- Subclass SettingsManager and override various methods to create a custom settings menu easily:
- AddSettingListeners: Adds listeners to given stats in the given GamePrefs. These listeners will be invoked on any changes to the settings (temporary and final).
- AddTempSettingListeners: Adds listeners to temporary GamePrefs that change as the user alters settings.
- GamePrefs class represents the current settings for the game. Subclass GamePrefs to make a set of custom settings:
- AddPresets: Add presets to your settings (volume, video, control, or custom presets) to add new setting names/types (float, int, bool, string) to the GamePrefs.
- AddSettings: Like AddPresets, except for adding individual/custom setting names/types to the GamePrefs.
- Reset: Define what happens when settings reset.
- IGamePrefs interface defines GetSetting<T> for retrieving a setting value of type T.
- GamePrefTypeMap is a dictionary mapping for a single type (int, float, bool, string). GamePrefs has one map for each of those types.
- RegisterSettingCallback or RemoveSettingChangeListener from outside the SettingsManager to add or remove (respectively) listeners that are invoked during changes to the corresponding setting.
SettingMenuInspector:
- SettingMenuInspector is like BuilderInspector except for SettingsManagers. Pass a SettingMenuInspector into a SettingManager’s SetupUI method to have it build a settings menu according to the SettingsManager’s setting keys using sliders, toggles, and buttons.
- SettingInput abstract base class for each input type allowed in settings.
- SettingSlider: Hook setting to int or float.
- SettingDropdown: Hook setting to int or string.
- SettingToggle: Hook setting to bool.
- SettingButton: Hook up an action to a button.

Settings Menu which was assembled programatically.
AudioManager:
- AudioManager class is responsible for being a centralized place to register and dispatch changes to different audio sources.
- AudioManager can register 3 different types of audio sources:
- Music: For sources that should play music.
- Effect: General purpose “sound effect” sources.
- Voice: For visual novel voice-acting lines.
- MusicManager with 2 audio sources for fading between tracks.
- AudioSystem (bad) attempts to use AudioManager to update its audio source volume in accordance to the effectsVolume.
Play Mode:
Started messing around with making a menu scene and doing some scene transition stuff.
- Core Builder: Needed a stripped-down version of the builder object so that when loading a project to play, it could still create all the prefab Entities necessary to have the level.
- LevelHelper utilities for starting and destroying levels.
- PlayProjectLoader creates a reduced builder object, runs project setup, and gathers up builder registries.
- LoadedProject represents a loaded project (mostly to organize its registries).
- LevelSelectManager manages inter-level loading and processes.
- New Scenes: Created some linked scenes (main menu, level builder scene, level select scene).
- SceneControl wraps SceneManager to control some visual transition effects.
Health System Changes:
- HealthChangeElement buffer tracks instances of changed health.
- HealthSystem now provides some custom jobs that do specific things when player and enemy change health.
- HealthChangeGatherJob consolidates all health changes (from buffer) for each entity and each health change type (active/passive damage/heal).
- HealthChangeManageJob manages changing final health, setting invincibility, and marking dead entities to kill.
- Bullet collisions now just add HealthChangeElement to buffer on hit. Collisions keep track of invincibility internally, but do not write it back to the health component.
New Trigger Processors:
- PlayerTriggerProcessor: apply preset, respawn, invincible, heal, damage.
- AudioTriggerProcessor: set volume, set track, stop track, start track.
Miscellaneous:
- PauseManager, a central place to track multiple IPauseSources.
- IPauseSource, a thing that can cause a game pause. Usually register in OnEnable and deregister in OnDisable.
- Fixed TranslationWidget dragging action. Enemy path multi-edit panel now only affects selected nodes instead of all nodes.
- Added exception button to notice preview (can click this button to toggle exception log).
- Notice preview is now movable.
- Top menu bar now toggleable with Escape key.
- VisualsSystem processes a bunch of visual-related jobs (for the future).
- Sprite flashes during invincibility.
- GameUI for providing a single API for changing UI values and activating UI events: GameUIBarSlider, GameUIText, GameUIImageStatus (think original DOOM portrait), GameUIPopupImage for fun little images popping up.
- ScoreManager static class keeps track of score. Change, set, or zero.
- ScoreComponent on anything that can add score.
- ScoreOnHit and ScoreOnKill used in ScoreSystem to add score based on health changes and whether something is scheduled to die.
- Bugfix: Fixed problems in UnpackMounts where it does not properly fail during project loading when the dependency prefabs (waves) for the level have not been built yet. Passing a new OnFieldRetrievalFail argument fixes the problem.
- Bugfix: Improvements to reflection to NOT skip Entity fields nested in SimpleList fields.
- Bugfix: InteractiveDropdown_GameTrigger fixed to run even if awake is not called.
- Bugfix: Player sprite on respawn was not right. Problem was that the default sprite info was never initialized, so the default data used in NewSubject is basically zeroed/default. Now check the default sprite info for the builder category.
Video Demos
A full view of the (very incomplete) scene transition, level selection, GameUI and scoring. When a scene transition occurs, you may choose whether or not the loading bars are visible. Selecting “Play” brings up the level select scene, where you first choose a project to play, and after loading, pick a level from that project. On the right is the GameUI. The buttons are just debug testing, but the health bars and score text are placed and updated programatically.