Managing tons of game logic?

I apologize if this has already been asked and answered.

Hi all, just to give a brief background before my question:

I’m learning how to create games independently in my spare time as a hobby using C# and MonoGame.

C# is the most familiar language to me and I am probably an
intermediate programmer with it. I have completed a couple of 2D space
shooter tutorials, one by an individual on the internet and the other by
Microsoft. I picked up where Microsoft left off and implemented their
XNA game state and input management into the tutorial game and I fully
understand it, it’s very efficient and flexible. My goals are to learn
other game tasks such as file management, networking, and efficient
content management, but there’s a lot of information on these topics and
they sound trivial to implement.

However, my trouble is with game logic. Even in a very simple and small 2D
space shooter like I am working with, there is already a lot of objects
and data to process and is clearly way too much for one Update() method.
I had divided up all of the logic into further methods within the game
screen class to organize things but this just resulted in about a dozen
nested methods which seems very sloppy.

I was thinking about implementing a Logic Manager class to handle all
of this logic but I think it would quickly become bloated and have the
same problem as the game screen class. Then I thought about having
different classes, i.e. Player Manager, Projectile Manager, Enemy
Manager, etc. I am still going to have to pass a lot of data from the
game into these classes either into their constructors or their methods,
unless I am approaching this poorly.

I can only imagine how much logic would be written for larger games
which I will be working on in the future and it sounds like a nightmare.

My main question:
Is there any conventional wisdom, approach, or general
architecture games use to handle this behemoth amount of logic that any
of you would suggest? Or is it different for every game and I
just have to hammer it out through trial and error, trying to improve my
OOP skills? I haven’t been able to find much searching the internet. I
suppose I could just try to read some source code if I could find some
that’s good.

Sorry for the long post, thanks in advance!

I try to put all my different game elements in lists, and update (and draw) them in a for each loop.

Like:
for each (Enemy enemy in active_Enemies)
{
enemy.Update();
}

When they are killed, or leave the screen or whatever, I add them to list enemiesToBeDisposed…

And finally, for each (Enemy enemy in enemiesToBeDisposed)
{
active_Enemies.Remove(enemy)
}

Anyways, point is, have code for behavior inside each class, rather than having a fat external manager control everything…

If you want group behavior, create a “formation” enemy that just contains a list of enemies it governs…

The cool thing about this, is that the UPDATE in main, scales with the scene, rather than always running a ton of code, or checking a lot of conditions…

…Also, you can have lists for each graphics layer, and draw them all in the correct order very easily…

Like:
foreach (terrainSprite sprite in background)
{sprite.draw}
foreach (terrainSprite sprite in midground)
{sprite.draw}
foreach (terrainSprite sprite in foreground)
{sprite.draw}

Thanks, that makes sense, especially drawing sprites in different lists depending on what needs to be on top.

However, I think the code already does what you’re talking about. There’s a list of projectiles, enemies, explosions, and the player.

But all the loops and collision checking is done in the game class. I feel like all of this logic should be done elsewhere to make it more organized. There’s like 250 lines of code involving looping through the different lists, checking collision, and updating data. The game is very basic and it already seems lengthy and difficult to read.

Yeah, I do collision detection within the classes too… you could have each active_enemy and/or projectile test against each player on the active_player_list…

You have to use code to test enemy vs player anyway, there is no way around it, might as well structure the code so that each thing happens inside whatever class its happening to…

Say each enemy has this in update: (pseudo)

If (my_rect collide with thatPlayer.rect)
{
thatPlayer.GetHit();
Kill_Me();
}

That way, each enemy type can easily have its own hitpoints, movement style, death animation, score modifier, etc, and its ALL contained in that one seperate class… Easy to search, easy to read…

And easy to operate and maintain in the future… Since all you have to do is call Update() on it, and it will do whatever, all on its own…

This way, you can keep adding variance and depth to your game, by growing your class library, rather than growing your game-loop…

Okay, great, that confirms what I had been having trouble with. A lot of the logic you just described as an example was written outside of the objects that they happen to. Makes more sense the way you explained it.

I can recommend checking out GRASP if you’re looking to get better at software design. EDIT: sorry, I linked the dutch page earlier

Great… I dont know how experienced you are with sub-classes, but they are great for this stuff, and just as easy to use as normal classes.

You would have a class called ‘Enemy’.

and then you would have a class called ‘RocketTrooper : Enemy’. and one called ‘Tank : Enemy’.

that way you can add rocket troopers and tanks to your universal Enemy list, and they each just over-ride the base Enemy class with their own individual behavior…

So when you do a:

For each ( Enemy badguy in activeEnemies)
{
badguy.Update();
}

they each have their own separate behaviors, from their own independant Update and Draw… despite being updated from the same master list, in one go…

As opposed to having a list of Rocket_troopers AND a list of Tanks…

Yeah I am familiar with inheritance and stuff, I probably do need to re-write all of the classes to inherit from a common GameObject or Sprite class, then inherit from more specialized classes like enemies, projectiles, and players.

I think the object oriented approach is that these objects should have no knowledge of each other? (although that could raise an entirely new question like how do enemies find players and attack them…) The problem still remains as far as who should create these objects, check for things like collision, call their update() methods and then destroy them? I think this is still too much to hard code into the main game screen class itself. I was looking at design patterns and was thinking about making a “mediator” class to handle these things and gets updated and drawn on the game screen.

I suppose I just need to dive in and start writing some stuff for hands on experience.

Sounds right. -but as you say, even if you did have a manager class to check for collision between units, it too would somehow need to know about the units and all their variables anyway. -And you might have to edit or redo the manager classes every time you redo your or add new unit types, to take their behavior and needs into account.
(some enemies check rectangles, some check distances, and some might only collide with certain colors)

The way I’m suggesting, each unit can be modified in any way what so ever, like its a whole other mini program, without you needing to modify any other code outside that class…

That’s what gets hard to maintain, when classes are dependent on each other for functions/code, not so much in my experience, when they read from each other for data, like a position vector etc…

  • Because you can overcome missing or bad data like a real-world enemy… When there is no enemy position vector to be had, or the values are out of range somehow, he just lowers his gun and patrols around or whatever…
    (all self contained code)…

The manager would have to contain all sorts of ifs ands or buts to account for all the crazy Enemy instances you might create. (say you build a teleporter enemy that can check for collisions in two places, or TWICE per frame, for some reason… Your manager would have to do that somehow, which is just an example of the crazy level of contingencies your manager would need to accommodate a growing library of Enemy sub-classes)

And in regard to sub-class structure, I try to keep it how my brain sees the objects intuitively… So I don’t categorize classes into sub-classes into sub-classes according to some advanced hierarchical scheme I’ll never remember in 2 years…

Games like any other area has specific patterns but there’re general guidelines (principles) that are applied to any area. Any game even a tiny one has a lot of classes and connection among them so your code eventually will become unmanageable if you don’t follow these rules and practices.

Here’s a (must read) book that talk about these principles and practices I think you must read it to keep your code clean and readable.

https://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258

Robe.

Having all of your code in one giant update function isn’t inherently bad because spreading the code out has disadvantages. If there’s one separate thing after another and there’s no duplicated code then using functions or classes will not actually reduce the amount of code it will just relocate it and I find that actually makes it harder to edit the code as you now have to travel further to find what you are looking for.

One strategy to organize long functions is to put comments in between the different sections. Another is to surround groups of code in { and } to signify that it’s a separate from the code around it.