How best to structure a MonoGame porject?

Hello. I’m still a beginner in MonoGame but I have a firm grasp of the basics like drawing and whatnot. But I’ve come from unity development and I am struggling to structure my classes and objects in an efficient and sensible way. I have two methods, each with their advantages and disadvantages:
-inherited classes (where I for example have a physics object class, that inherits from the collider class, which inherits from the sprite class. It works but is pretty all over the place and gets complicated really quickly)
-megastructure (got the idea from Tom Randall. Haven’t tried it out yet, but the idea is to have a class that has everything it could possibly need, and when making new entities, you just define them or put null if you don’t want the entity to have them. Sounds inefficient but pretty modular)

I want to know which of these is the preferred method for MonoGame, or if there’s another method that I don’t know about. Any help is appreciated!

2 Likes

Generally you shouldn’t have that many layers of inheritance, 2 layers or 3 if you can’t help it. I took that advice from someone after my code became a riddled mess and it’s really helped.

I don’t know about the megastructure class idea either, that sounds like the antithesis of object oriented design. :slight_smile:

I’m a fan of having a class for entities and then having event handlers triggering for Update, Draw, Initialize Graphics… And then inheriting that class while adding to the event handlers. Seems like a capable solution without complicating things. But the best part about Monogame is that you can do it however you want.

1 Like

thanks for the reply. So say if I wanted to just give an object my physics code. How would I go about that with your structure?

Just use something this.

Dead simple, but very powerful.

1 Like

The megastructure idea sounds like the “god” object as explained here:

My setup’s purpose is to take a case where you would want multiple inheritances and make it modular. So you can give something physics, you can make it fly around, you can make the player control it, you can make it floaty, you can add any code to it without changing the base entity class, and without worrying about (much) inheritance. Most importantly, you can do it all at the same time.

I have this setup in every game I do. I have a class that serves as an entity (this class is huge but the bulk of it is irrelevant to this structure). In this case it is a rectangular UI element.

The entity class has several EventHandlers, such as

public event EventHandler OnUpdate;

This entity class has a public object that contains behaviors. These behaviors can be combined in such a modular way that inheritance would make impossible.

Say I want to give an entity a behavior. In this case it’s drawing a background. The behavior that’s added will be a DrawBackGround behavior.

Widget.Behaviors.Add(new DrawBackground());

Widget is our entity. Behaviors is our behavior manager. The following is the most important part of the Add() method.

    public bool TryAdd<T>(T behavior, out T added_behavior) where T : WidgetBehavior
    {
        if (Contains(behavior.GetType()))
        {
            added_behavior = default;
            return false;
        }
        if (behavior.IsSubBehavior
            && !Contains(behavior.BaseBehaviorType)) {
            TryAdd((WidgetBehavior)Activator.CreateInstance(behavior.BaseBehaviorType));
        }

        // Note these two lines in particular
        _behaviors.Add(behavior);
        behavior.Parent = Parent;

        added_behavior = behavior;
        return true;
    }

When you add a behavior to this Widget entity, it sets the given behavior’s “Entity Parent” to be the entity. In doing so, it connects all the events. You should have it set so that when you remove the behavior, it disconnects the events as well.

~~

If this is too much to bite off, here’s a little bit of a compact example that I wrote up. Note: I did not test this;

I’ll start off with the end result.

        Entity entity = new Entity();
        entity.Behaviors.Add(new MoveSideWays());

This is ideal because you can remove this behavior or modify it easily. You do not have to code the behavior into the entity class.

/// <summary> This is my shoddy entity class. Best to keep it sealed so the behavior system isn't ignored. </summary>
sealed class Entity
{
    // This should be public so the outside code can add behaviors to this entity.
    public EntityBehaviorManager Behaviors;

    // These should be accessible to our behaviors, so they are public ---
    public GameTime GameTime;
    public SpriteBatch SpriteBatch;
    public Vector2 Position = new Vector2();
    // ---

    public Entity()
    {
        Behaviors = new EntityBehaviorManager(this);
    }

    public void Update(GameTime gameTime)
    {
        GameTime = gameTime;
        OnUpdate?.Invoke(this, EventArgs.Empty);
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        // Draw something using the Position value here...
        // ...
        // Draw.Something(spriteBatch, Position);
        // ...

        SpriteBatch = spriteBatch;
        OnDraw?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler OnUpdate;
    public event EventHandler OnDraw;
}

/// <summary> This is the behavior manager that will handle my entity's behaviors. </summary>
class EntityBehaviorManager
{
    Entity parent;
    List<EntityBehavior> behaviors = new List<EntityBehavior>();

    public EntityBehaviorManager(Entity parent) => this.parent = parent;

    public void Add(EntityBehavior behavior)
    {
        behaviors.Add(behavior);
        behavior.Parent = parent;
    }
}

/// <summary> The base class for all my entity behaviors. </summary>
abstract class EntityBehavior
{
    Entity entity_backing;

    public Entity Parent 
    { 
        get => entity_backing; 
        set 
        {
            entity_backing = value;
            Initialize();
            ConnectEvents();
        }
    }

    internal void Disconnect()
    {
        DisconnectEvents();
    }

    protected abstract void Initialize();
    protected abstract void ConnectEvents();
    protected abstract void DisconnectEvents();
    public abstract object Clone();
}

class MoveSideWays : EntityBehavior
{
    protected override void Initialize()
    {
    }

    protected override void ConnectEvents()
    {
        Parent.OnUpdate += Move;
    }

    protected override void DisconnectEvents()
    {
        Parent.OnUpdate -= Move;
    }

    public override object Clone()
    {
        return new MoveSideWays();
    }

    void Move(object sender, EventArgs args)
    {
        // Move the entity! That was easy.
        Parent.Position.X += 1f;
    }
}

From the sounds of it the Megastructure you referred to is a form of ‘composition’.

If Interfaces are a thing that sits on top of a object and inheritance is a thing that sits under an object then composition is a thing that sits on the side of an object.

For example if you wanted a class (Say a chair in your game) to have some physical geometry, then you could write that as a class and add an instance of that class as a property to the chair. Then you would call Chair.Geometry.X (or what-not). This same geometry class then can be added as a property to any anything class that requires physical geometry.

If you have used Unity then this should seem familiar as it’s how they did a lot of their stuff.

ECS (Entity-Component-System) is a architecture, more or less, built around this idea and is a fairly good approach to games. So some reading in that space and that of composition in general would be handy.

Now in saying all of that, I wouldn’t worry about it to much. There isn’t really a universal “right” way of doing this stuff. All of these things, inheritance, composition, interfaces, etc, are just tools. Use them were you think they are appropriate, don’t get too tied to design patterns.

A hacked together game that is done is always better then a well architectured but half finished game. :smiley:

My projects have died when my code got too complicated or I needed art assets that I didn’t feel like making, hence why I go crazy with organization.

Good art is harder than good code. Well, to me.

This looks like an overengineered version of EC. I’d not recommend this to anybody tbh. : D

Like, really, you only need an Entity, a list of Components inside of it and some static controller that calls Draw/Update events without using event handlers - they’re not that great for performance.

Also it’s not great practice to pass dt and spritebatch as event args. If you use them this much, put them into static class somewhere.

While it’s not Monogame, here’s an amazing, improved, open source recreation of C&C in C# (OpenGL I believe). I also examined for its structure and more.

Using RenderTargets you will sometimes use more than one SpriteBatch at once, so your static class approach would not work.

Otherwise, it may be true that your version is superior, if only just because you removed the eventhandlers. However, I already have the eventhandlers in my case, getting rid of them would not do much for me. Although I was looking to get rid of my ConnectEvents() methods in favor of some overrides.

So I suppose I will try converting to yours and see how it goes.

Here’s how it went… I already have event handlers for other reasons (40 of them, and I do need them, being a UI project). To add another system alongside it would not make sense and probably be worse for performance.

There’s also the fact that I very often add over 10 components to one entity, which would add 400 various calls to unused methods (with some extra code as well) for each entity using your method. In mine it only adds events in places where it’s needed. It pains me to think of the thousands of unused calls per frame when I have over 100 entities using ECS.

So my system is more complicated… it is not over-engineered. It has advantages and disadvantages over yours. Yours is likely “good enough” for most cases, mine is more scalable. That’s generally the case for all things that use eventhandlers over direct calls.

You totally can use a single batcher for your entire game. Even with rendertargets and whatnot. Ideally, you shouldn’t even see Spritebatch from your gameplay code, it all should be abstracted away into DrawSprite-like methods, with no annoying Begin or End.

Who said you need to convert all of them? I only got Draw/Update/FixedUpdate, so empty calls don’t really matter - especially when I have Enabled/Visible flags that can turn those events on and off on per-entity and per-component basis.

I remember there being some weird quirk that made it impossible to use just a single SpriteBatch at one point, idk what it was. I went through at least 4 revisions of my drawing code. It’s not an uncommon thing to have multiple spritebatches, I’ve seen a Monogame dev say he uses multiple spritebatches.

When switching render target mid draw I think, sometimes using immediate and sometimes using direct, using multiple sprite batches made it much easier. I had to draw something while a separate spritebatch was active using a different drawing mode.

And I’m not criticising ECS at all, I’m just saying it doesn’t make sense to use in a UI framework, which traditionally uses lots of eventhandlers. Admittedly I did not know about your structure, so I got a little sweaty when I saw you call mine stupid, because I thought I had it all wrong. :slight_smile:

But yeah TC should probably go with your method.

I could probably do away with the manual event connections by having virtual methods within the abstract component class, then use reflection to tell which ones are overridden and add those and only those to the eventhandlers of my entity class. That would be slow to detect during runtime, maybe on startup it could build a database.

For that to happen, I’d need to get every class that inherits my component class on startup, and that’s tricky considering the user can create their own. I could probably do that with Assembly.

I mean then I’d have the best of both worlds. It would be more complicated, but only under the hood, and then you could just override any of the 40 virtual component methods with no performance impact.

It’s definitely fine now. My engine uses a single static spritebatch for EVERYTHING and it works as it should, even with rendertargets.

Use inheritance sparingly. In general it should be avoided because say for example you have a ghost that can walk though walls and a different monster that shoots arrows both made with inheritance and you want a ghost that can shoot arrows you cant combine them if the shoot arrow and walk though walls behaviour come from in inherited classes.