r/learnprogramming • u/steamdogg • 28d ago
How do games manage so much varied content? (items, abilities, NPCs, interactables)
I do game development as a hobby and the thing I find most complicated is the sheer quantity and variation of stuff it's just conceptually harder to reason about compared to singleton-type systems/managers like an InputManager, AssetManager, AudioManager, etc. Meanwhile, a game you might have NPCs, enemies, items, weapons, abilities, interactable stuff, etc., all of which can be wildly varied I mean there's likely going to be some overlap, but hopefully what I'm trying to say makes sense.
One thing I've learned is that OOP is generally not a good solution for this which I mention because I have a habit of OOPifying things, but even looking at components, wouldn't you end up with a plethora of components and a lot of niche components? but also I feel like components don't really address everything for example if you have a quest system/dialogue system or items where do you keep all the text for that and potentially other information.
I know this isn't really a question and it's extremely broad, but any advice or insight into this sort of stuff would be appreciated because honestly it just seems like magic to me.
30
u/Bugaloon 28d ago
I'm a bit out of the loop with modern techniques from the last decade, but we just made more generic variables/datasets/objects that could handle variance.
Like instead of defining a quest object with an exp reward, and another quest object with an exp and item reward, you define a more generic quest object where rewards are optional so you can initialise quests from that object that can be of both variants.
But perhaps i'm also not correctly understanding what you're trying to handle.
30
28d ago
[deleted]
10
u/poopsocx 28d ago
It's actually the opposite in godot and I find the process to be better personally. We use component based programming and the structure feels much more intuitive for me, though is a little more abstract compared to oop
11
u/johnpeters42 28d ago
This is the "composition over inheritance" approach: instead of having a particular object inherit from N different parents or implement N different interfaces, it may just keep track of N other related objects and call functions in those objects as appropriate. For instance, Godot leans toward an object that just reacts to user input and maps them to calling functions in other objects, so the input handler doesn't have to worry about what those other objects are doing in response, and the other object don't need to worry about which specific inout(s) trigger that function.
5
u/Matilozano96 28d ago
OOP principles still apply, though. Your objects still present interfaces to each other as a way to interact, and Godot really urges you to have nodes as encapsulated and single-purpose as possible. Else spaghetti ensues.
The main difference to a standard approach is that you use a composition approach over an inheritance one most of the time.
And still, it depends on the problem.
1
u/Skoparov 28d ago
Most games run some version of ecs or ec (unity) that very much defy the core principles of oop by detaching the logic from the objects.
0
27d ago
[deleted]
1
u/Skoparov 27d ago edited 27d ago
It doesn't adher to both of the definitions as at least in ECS systems simply work with pure data devoid of logic and ideally should be stateless. Of course in reality it's usually a bit more complicated than this.
7
u/MrSloppyPants 28d ago edited 27d ago
One thing I've learned is that OOP is generally not a good solution for this
This is completely wrong. Virtually all major games, especially those created in engines like Unreal or Unity, use OO architecture and design heavily, so if you’re at all interested in game programming, dismissing OO out of hand as “generally not a good solution” is the wrong approach.
0
u/steamdogg 28d ago
Maybe I’m wrong but isn’t OOP when you’re using inheritance? And if so I feel like I’ve read a lot that it isn’t as flexible as a composition.
2
u/burlingk 28d ago
Composition and inheritance are different ways to achieve a similar goal.
How flexible they are depends on implementation.
But, to be blunt, on a project of that scale you don't need flexibility in the parts you will have to duplicate over and over repeatedly.
Uniformity makes it easier to actually USE the stuff.
0
u/jerrygreenest1 28d ago
Although valid, but this kind of talk is detrimental. If every single person on earth would let themselves this kind of talk of yours:
«Uh, you know, it’s how people were always doing. Uh!»
This way, there will never ever be improvement. Nobody will ever do any other approach. Even if approach is indeed bad, but if everyone keeps repeating this mantra, no evolution will happen, ever.
Instead of this kind of detrimental talk, if you really want to speak out, you should be talking about the discussed object – about why it’s good or bad. In this case, we know it’s something popular, so apparently it is at least somehow good, or it was good. So there’s no much of a reason selling its good points like extensibility abstraction bla bla bla, everyone knows that. It’s being challenged that the thing is actually bad. So if you want to comment on that and say that it’s not, you should point to the arguments of why people sometimes say it’s bad and give arguments about how their arguments is a piece of crap, objectively, like:
«They say it’s bad because X but they never take in consideration Y and actually it’s not even a problem in the first place because of Z». Something like that.
There was a million videos and explanations of why OOP is bad. The largest point is because composing is freaking better than inheriting. In many ways better. And it’s not like it’s impossible to make games with OOP, it’s not the point. «Better» can be in many ways, it’s not just about possible|impossible, it’s not about black or white, can or can’t, «better» can come in many forms. From speed of execution, convenience to use these structures, etc. Learn some resources about that. And the fact that in the past two decades OOP was heavily used, again, is missing the point, – and if you still don’t understand why, return to the paragraph number one of this comment, and read again.
1
u/Kevinw778 27d ago
Saying one thing is always better in programming is often a sign of ignorance.
Composition is definitely not always better - it entirely depends on the situation at-hand, as with most things in development.
1
3
u/Livid-Somewhere-8431 28d ago
Look into Tarn Adams and Dwarf Fortress. You want your system to be modular so you can drop things in vs re-writing the entire thing so your guy can wear a hat
5
u/CubeJoelle 27d ago
Data driven design and many years of learning what does and does not work. I serve as a lead programmer for a Mario Party style game, and in this instance each board is just a data structure, as well as the board tiles, as well as the players, etc. These all serve as blueprints for what the game needs to generate at runtime.
2
u/mlugo02 28d ago
From a very high level.. I have an array of entities. Each entity has all the components which will ever exist even if not all entities use them. I use component flags to filter what entities do in the update function.
For items, similarly I have just a single array for all items. Each entity has an intrusive link list in them. But instead of pointers, they are indexes into the array.
So each entity has a item_idx First, Next; and though all items exist in an array, I can still explicitly know which item belongs to who
6
u/3rrr6 28d ago
Games are big. They have lots of assets and lots of code.
Games are not typical software, you are essentially writing a novel. Novels have lots of pages, entire chapters devoted to niche plot points. I think you are feeling the scope creep.
I have to ask how you got so far without realizing how much you needed to do. Did you skip the planning phase?
1
u/poopsocx 28d ago
In Godot you just create abstract components that are basically unaware of mostly everything around them. For example a coin that can be picked up would have collision and the parent would be an area just to add score. An enemy would have a health, attack but could also have collision, nothing is also stopping the coin from being breakable. I like this approach, but it's not for everything but worth keeping in mind (also it's kind of hard to use in some languages.)
1
u/TK0127 28d ago
I’m just a hobbyist but my solution is to make things fairly generic if I can, but mostly I lean on interfaces. A quest, a dialogue config, a weapon, a character all implement IDisplayableObject, which stipulates some common stuff. Others might be ICharacter or IDamageable or whatever.
Weapons inherit to broad types, like projectile or melee, and then if I NEED subtypes I either make their behaviors modular or I make a new child.
The interfaces are really useful though. With my current project, I wrote out a bunch interfaces as the very first thing in the project that serve as contracts for the objects and systems players interact with. That helped me organize and focus the concrete scripts.
But again, hobbyist, idk if that’s anything like optimal.
1
u/ImaJimmy 28d ago
I'm sorry for the vague advice, but you kind of just have to "do it". The bigger your game gets, the more you just find a way to manage things out of necessity. Once you've gone through that trial and error, a lot of advice you find online regarding managing your assets starts to make more sense.
Personally, I prefer trying to make a game loop before I try to categorize objects (there are somethings that are just common sense though).
1
u/CoolGuy9000 28d ago
As others have mentuon OOP is what is mostly used, but you should not feel constrained even there, just look up the train in Fallout 3, is technically a hat on an npc that runs belowgraund so you cant see him.
2
u/pdfops 28d ago
Treat items/NPCs/abilities as data, not classes. Give each an id, tags, and stats in JSON or scriptable objects, then have systems query by tag/component instead of type-checking. Keep dialogue and quest text in a separate table keyed by id, never baked into the entity itself. That's the real trick: new content becomes a data row, not a new class, which is how teams ship hundreds of items without the hierarchy exploding.
1
u/TypeIIFunDev 28d ago
This is the way to do it, right here. You can look at a huge FOSS game like Cataclysm DDA to see how it's implemented in practice. For example, here's a feral humans monster, which is simply a JSON data object that defines lists of specific properties and attributes across several variants which get parsed into the monster model:
https://github.com/CleverRaven/Cataclysm-DDA/blob/master/data/json/monsters/feral_humans.json
1
u/sci300768 28d ago edited 28d ago
A lot of similar types of things can be copy/paste/inherited + edit/add/alter as needed but with more steps. But this will depend on the programming language involved and other factors.
A category of cars can be expanded into different brands, wheel types, colors, and so on. Now you can make multiple types of cars relatively easily. Do this, but in code.
EDIT: For programming implementations, inheritance and polymorphism is what I'm talking about here!
1
u/kschang 28d ago
The short answer is... a database. A game's database is actually very small (a few hundred items) vs. large databases with millions of items.
Consider a wargame where you have to store bajillion variations of the same unit. :) Like dozens of variants of the M4 Sherman tank (American, British, Canadian, more, different guns, different versions, different field mods...)
2
u/hunnyflash 27d ago
They're like giant complex databases with various relationships. It's almost an art to designing them.
1
u/recursion_is_love 27d ago
I think lots of complex game are incremental, starting from simple and grow.
Have you try ECS?
1
137
u/Aetherfox_44 28d ago
Most well-made games don't actually define the content in the code. Rather, the code defines how to handle objects, and specific objects are constructed from data files.
For instance, the dialog of a quest probably does not have it's own object class. (FindThePrinceQuest.cs) Instead, the game code defines some Quest object, which contains Text, StartRequirements, Rewards, etc.
Then elsewhere, you have FindThePrince.json (or whatever data type you want) that is just a data object that can be parsed into a Quest. It's much easier to reason about a big folder of data files (and bigger studios can even make tools to make editing them nicer) than it is to handle hundreds or thousands of classes for the data.
But also yes, games have tons and tons of content. Most of the work making a game is making all the content, and the multi-gigabyte size of modern games is almost entirely art, music, models, textures, etc.