#Singleton & Dependency Injection

1 messages · Page 1 of 1 (latest)

ancient jacinth
#

I hit another roadblock recently with global readonly data and dependency injection. For example if I have a list of currencies/their amounts that I would need to be able to read from anywhere, but only allow a class CurrencyManager to actually modify the list, how would I go about that without turning CurrencyManager into a singleton with a public get, private set field?

Most of my project is already setup with scriptable objects for event channels and referencing default data. I considered using runtime sets and modular data via SOs as shown in the 2017 Unite talk and adding references to the SOs on any components that may need that data, but I thought scriptable objects were meant to be used as data containers that don't change at runtime? Do I just have to manage the values on the SOs at initialization and then save/load their state along with other game data?

#

I'm trying to pull all the list modification into one place to adhere to single responsibility, but I find that I still need to access the current data and then fire an event to the manager externally to modify said data

#

which seems to be running in circles

maiden canyon
# ancient jacinth I hit another roadblock recently with global readonly data and dependency inject...

if you really want to pass the list without letting other classes modify it, then you would either need to pass a copy or use something like IReadOnlyList<T>
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1?view=net-9.0
just gonna put this out there, I think the "scriptable objects for event channels" is a fad that needs to die out already. Yes scriptable objects are meant to be data containers for immutable data. If you suddenly need to change the data on this instance, you now need to rework your entire system

maiden canyon
ancient jacinth
# maiden canyon honestly im not sure what you mean with this message. if you have an example it ...

Updating the values in the list is all good, the issue arises when I want to check the list first to validate that the player has enough of a currency. Say a separate class Shop calls a method to buy an item, it first checks the player's currencies and then invokes an event to deduct the cost and grant the player the item. How would you setup the reference to the list in the first place? it seems redundant to go into a CurrencyManager singleton to grab the contents to validate, but then go back to the Shop to use an event to deduct the value

#

Also is there a reason you're against the scriptable object event channels? I found they made it a lot easier to prototype ideas once they're setup

maiden canyon
# ancient jacinth Updating the values in the list is all good, the issue arises when I want to che...

tbh i wouldnt have the players currencies stored as a singleton in the first place. though that doesnt affect that you need a reference to the object.
I think itd make more sense if you had a method on the CurrencyManager to check if there was enough of a certain currency or to get the specific currency in question rather than the whole list. Then have it call another method on the currency manager directly for subtracting the amount

#

i dont see where you need events in buying an item

maiden canyon
ancient jacinth
ancient jacinth
maiden canyon
#

or the currency manager can invoke an event if you have actions that need to happen based on that. though i dont think that really ties into whats happening here

ancient jacinth
maiden canyon
ancient jacinth
#

My hesitation around using singleton is that I have a handleful of managers acting this way

#

Seems like it would spiral pretty fast

maiden canyon
ancient jacinth
#

So the game scene is only for game logic

ancient jacinth
maiden canyon
#

that doesnt really affect anything there. If you want to avoid a singleton, you have to pass a reference to the shop at some point. This could be when trying to interact with the shop to buy items or when the game is being setup

ancient jacinth
#

I see

maiden canyon
maiden canyon
#

either way I think it still doesnt matter whats a singleton and whats not. you're using a singleton as a way to enforce there being one of an object, and using it to get a reference to said object. Avoiding it means you need to replace how this "get a reference to said object" works

ancient jacinth
#

Yeah I might just bite the bullet and make the managers singletons within the scene. My managers hold onto lists like currencies, current modules, and unlocks which means all game objects can access that data if they're singletons. At that point, if methods to modify that data sit on the managers and can be called from anywhere, do I just reserve events for cross scene communication?

maiden canyon
ancient jacinth
# maiden canyon Events arent specifically for cross scene communication and arent required for t...

I tried to approach it from a more theoretical point to avoid infodumping the whole project. And yes, everything is for one player. High level flow and progress through a GameManager, ModuleManager for creating/maintaining a list of modules, CurrencyManager. The idea was to have the functionality separated such that events could be raised from anywhere and listened to by the managers to handle accordingly, such as either the GameManager telling ModuleManager to create a new module or an already existing module sending that kind of event to ModuleManager. Although that can be done through the single player manager, just seems like I'll have a handful of dependencies to maintain in the individual managers

ancient jacinth
maiden canyon
#

The only thing I'm really unsure about is how youre using those events. Truthfully for an idle game, I doubt it matters how you setup this game.

ancient jacinth
#

With how small this project is, I doubt I'll have more than 4 managers/singletons and I can manage that. At the moment most of the events are used to load scenes and call methods from UI buttons

hybrid geode
#

I recently found success with VContainer / Zenject for dependency injection to solve exactly that topic

hollow cloak
#

Are you going to make use of the dependency injection in some way, eg having multiple implementations of the dependencies, swapping out dependencies during testing, etc?

ancient jacinth
hybrid geode
#

zenject still works but sadly is abandoned, vcontainer is actively supported but lacks some features that zenject has

maiden canyon
hybrid geode
hollow cloak
#

Over abstracting can be harmful as well. If for example, you aren't using the dependency injection in any way other than grabbing the only ever instance of the dependency, you are really just doing a bunch of ceremonies to grab a static/singleton instance.

ancient jacinth
ancient jacinth
#

Like @maiden canyon said, unless this project really works out for me, I likely won't come back to the template past the bootstrapping/scene loading

hollow cloak
#

You really should try to answer "what does this give me that the simpler alternative doesn't?" And if you can't answer that, maybe reconsider.

#

This applies to not just the question in this thread, but generally everything.

maiden canyon
#

I think even in your case, a singleton makes more sense. I mentioned before if you dont want the shop to reference a singleton, you need to pass the value somehow. This might just be more complex and as burrito described, a bunch of ceremonies, when there's only going to be one instance

#

Though just to answer in the case we talked about before of a shop. something needs to spawn this shop in or set the UI visible. That could be a game manager. The game manager could pass the value whenever you want. This game manager could have the reference to your player, especially if it spawns the player in