"Generic" achitecture

You might be able to do this with interfaces as well its basically the same idea.

You could i suppose also keep all the basic data in a single class with static methods that return structs that are built out of only the data you require for just that type. Other non static methods that accept only that type of struct could assign only to the data members that are relevant to that corresponding type.

You would waste a little memory for a dictionary or list of those base data objects and might run the risk of cache hits if it got to bloated… but it would be simple. Though i guess that’s a alternative closer to your original example.

Here are a couple links to basic design patterns.

http://www.dofactory.com/net/design-patterns
http://www.dofactory.com/net/adapter-design-pattern

http://gameprogrammingpatterns.com/contents.html

I would choose a simple Base classes over Abstract classes or interface in this scenario ^ _ ^ y

    public class BaseMaterials
    {
        internal virtual void __Update()
        {

        }

        internal virtual void __Draw()
        {

        }
    }


    public class MatDefault : BaseMaterials
    {

        internal override void __Update(...)
        {
            // do your stuff
        }

        internal override void __Draw()
        {
            // do your stuff
        }
    }

    public class MatColorOnly : BaseMaterials
    {

        internal override void __Update(...)
        {
            // do your stuff
        }

        internal override void __Draw()
        {
            // do your stuff
        }
    }

    public class MatLightShadow : BaseMaterials
    {

        internal override void __Update(...)
        {
            // do your stuff
        }

        internal override void __Draw()
        {
            // do your stuff
        }
    }

////////////////////////////

    public class Entity
    {


        public BaseMaterials Materials;


        public void Update()
        {
            Materials.__Update();
        }

        public void Draw()
        {
            Materials.__Draw();
        }

    }

EDIT : I’m pretty sure Virtual function will not be the bottleneck on games application mostly it’s the rendering parts : - D

Welcome to software engineering.

You are approaching the limits of the C# language for games. C# 7 has neat stuff which might help you out, but even then there is a wall. For example MonoGame won’t adopt C#7 right now (for good reasons) so either you have to hack yourself or wait. I ran into similar problems when working on Entity Component System for MG.Ex. Stepping back and reflecting on this, I have some hunches why Microsoft “extinguished” XNA and told developers to use C++, but now only to “embrace” MonoGame (XNA) again. I also have some insights from studying Computer Science at university that give me this intuition that maybe Microsoft’s plan with open source is that they can evolve C# into the language to rule them all with instant feedback from smart people all over the globe who study compilers, A.I. philosophy, mathematics, language theory, etc. Maybe the short term goal is to evolve the language to one that is better suited for game development and web development. Sounds plausible, but who knows, that is just my opinion.

So your options are:

  1. Stick with MonoGame as is, learn software engineering, live with price that your game might not be highly efficient right now, and pray that advances in technology will make all your efficiency problems in the future disappear. You can find a lot of resources online but one I like a lot and that is free is Game Programming Patterns.
  2. Hack MonoGame for your needs to perhaps use C#7.
  3. Write parts of your game in C/C++ and interop with C#.
  4. Abandon MonoGame altogether and use C or C++ or some other language that better suits your requirements.

Honestly I think you should try option 1 first.

What exactly do you think would make C# better for programming games? I disagree with this design being an issue because of C# limitations. I do hope mixins make it to C#8 though.

Also, it’s not because MG itself is not using the latest C# version that you can’t use it in your game project (or libraries like MG.Ex for that matter).

Na there are a lot of ways to do it.
Just not a lot of ways to do it to were it both looks pretty and is efficient.

Your question is sort of a catch 22 because on one hand your optimizing. On the other hand your asking about making it prettier and simpler by condensing out these arrays.

However were you have separated the classes to optimize this originally. That has now caused a complexity a non optimization else-were or rather later which is now.

I think this is a case of (as Anders Hejlsberg might put it) “Simplexity” in that it can be either simple/pretty or complex/fast but not both in the same place. Then again Encapsulation is good for wrapping up complex ugly things in a pretty package.

Personally id stick the data for all 3 into a single struct that has generic data type names like Vector2 v0, v1, v2 int i0, i1, i2; ect… Id have a separate class or methods within it that grabs or places data as needed for each instance. Depending on a type id variable in each data struct. Even if all the data wasn’t needed for each type. Make a list of the structs or object instances use the id to switch case gets and sets. Provided this isn’t going to use a huge amount of memory. Problem solved pretty it up later move on.

Though i don’t know how big all that data is combined.

If the data was big and it was mostly not type dynamic data.

List manager = new List();
Class Manager
{
int typeID = -1 // not yet set -1 set on instantation or setting a object in;
Object_Default a;
Object_OnlyColor b;
Object_LightnShadows c;

// getters setters for each;
// problem solved
//
}

There are other ways to do it as well that are really ugly and fast basically make it all a struct or set of structs.
Again after it was wrapped you could make it look elegant to use.

Alternatively the really complex yet fast efficient route when the data really could grow very large. Encapsulated into a manager for ease of use with special methods. You could basically keep each object optimally sized and keep it fast. The cost is a lot of mental work and wrapping it later to be easy to use.

You could keep all 3 arrays for each type wrapped in a Manager class.
Make a tracking struct{ aWhichArrayID and Index }
put in a static list of them in the manager.
put one in each object;
put in a private static int indexCounter in the manager as well.
Each time you Added a object thru the manager or create a object thru the manager of a specific type
Increment the counter
Create a tracker.
Get the array Count for the trackers Index;
Assign the counter to the trackers ID and drop a reference to it into a self registering list of tracking structs.
As well when a type object is added to the manager add a tracker to the corresponding object to be inserted into the corresponding correct array.
Each object knows were it belongs in each array and you have a list of were each object is that you can iterate (little more to it, but that is the jist).
Ugly complex to look at on the inside of the manager but also fast and efficient.
Basically you create your own MultiType Non Generic Container
From the outside as seen from calls to the manager Prettied up with nice calls written as you go as needed to be perfectly practical.
Done problem solved but… that structural set up needs to be tested before implementation it needs quite a bit of thought and so it takes more time to code.

Support for data oriented design in C# beyond the reason of “legacy COM / PInvoke” is probably a good start. You can see Microsoft introducing some language support with this by ref returns in C#7. My point is that game developers / architects have different requirements and needs for a language then web developers. Game developers want or even need control over how memory is filled / layed out. Web developers not so much. Games have timing requirements. Web applications to some degree but usually are much more relaxed. Games are real-time applications, web applications not to the same degree. Sometimes garbage collection just gets in the way, sometimes that complexity is better handled by an A.I. My point is C# is nice language but there are definitely some pain points for game developers who have performance requirements. Take Nez for example: @prime31 toke the decision to not use C# properties (syntactic sugar for methods) at liberty because of performance requirements he wanted for his engine. I disagree with him however because it breaks the code guidelines we all come to agree upon which make it easier to read code (one of the philosophies we inherited for MG.Ex). Also as compilers get smarter they can inline most properties methods making the argument pretty moot, even debatable for reasons why getters and setters have been introduced in the first place. So yes, over time C# will probably become easier to work with for game developers, but until then…

C# as a RAD tool for desktop apps is amazingly efficient, and I understand some things must by locked under the hood to avoid “common” mistakes (malloc, destroy etc).
But I don’t want to abandon Monogame, as C++ with directx has a slower curve of development I think: just the initialization of the window is boring to code, models importation like it is done in MG’s pipeline tool is a big work, etc.

My problem is more a transposition of what I can/would do in C++ to C#. If we had pointers everywhere (not only on some types), class aggregations (in my case, classes with dedicated properties, which would be combined by aggregation to a complex object) etc, it would be easier. At least for me.
With C# I hesitate between a way using virtual methods, or choose a complete another way with delegates. And here I don’t want to spend 1 month testing one or another, I have little spare time to work on my engine, or else I’ll publish it with MG v7.0 and dx14 :confused:

On a side note, I avoid properties too, I don’t see the advantage but to permit other devs to only get a value or only set or both when sharing code/libraries. I saved about 5fps by removing them (over 280fps, it is minor but the gain exists)

If you are asking how you would set up a collection to simply use it to move through each element without using an array structure, simply put your objects into an ArrayList. ArrayList elements simply assume the type of object being stored in them.

With ArrayLists however, you can use multiple types but you will have to use a little reflection to extract information from each of the elements.

The sample code shown above that looks at this problem from the inheritance point of view is an excellent way to go if you like using this type of paradigm. However, inheritance has its drawbacks in that it is probably as inefficient as using reflection to any extent. And the more complex\heavy your objects are, the more inefficient inheritance becomes. In addition, anything beyond simple inheritance hierarchies often become unmanageable over time and this has been well documented over the years. Most large projects that use extensive inheritance have often become maintenance nightmares for its developers.

I am not saying do not use inheritance but just to be careful if you do.

The code I put together for you rather quickly below provides a somewhat primitive but simplistic method to do the same thing but using reflection. Reflection’s inefficiencies come from the need to for casting objects, which as other posters have rightfully stated forces the boxing and unboxing of objects.

Despite the inefficiencies of both paradigms, such inefficiencies are often not noticeable to the developer or user of an application until you begin working with large numbers of objects. Too often developers prioritize performance over common-sense coding techniques for small numbers of processes involved. The result is that a lot of effort is wasted on finessing internal efficiencies that often provide little advantage. Further, today’s compilers are so highly optimized that they will often make up for such optimizations no matter what paradigm you eventually decide to implement.

So for the code… I hope it helps… :slight_smile:

C# Main Class

using System;
using System.Reflection;
using System.Collections;
using System.Threading.Tasks;

namespace ArrayListOfObjects
{
class Program
{
static void Main(string args)
{
ArrayList ObjectArrayList = new ArrayList();

        Class1 loClass1 = new Class1();
        Class2 loClass2 = new Class2();
        

        ObjectArrayList.Add(loClass1);
        ObjectArrayList.Add(loClass2);


        foreach (object loObject in ObjectArrayList)
        {
            var loObject1 = loObject.GetType();

            switch (loObject1.Name)
            {
                case "Class1":
                    Class1 loNewClass1 = new Class1();
                    loNewClass1 = (Class1)loObject;                        

                    Console.WriteLine("String ID: " + loNewClass1.STRING_ID);        
                    break;

                case "Class2":
                    Class2 loNewClass2 = new Class2();
                    loNewClass2 = (Class2)loObject;                        

                    Console.WriteLine("String ID: " + loNewClass2.STRING_ID);        
                    break;
            }    
        }

        Console.ReadLine();
    }
}

}

C# Class1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ArrayListOfObjects
{

internal class Class1
{

    internal Class1()
    {

    }




    string csStringID = "1";

    internal string STRING_ID
    {

        get { return csStringID; }
    }


    internal string Get_String1()
    {

        return ("my string1");
    }

}

}

C# Class2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ArrayListOfObjects
{

internal class Class2
{

    internal Class2()
    {

    }




    string csStringID = "2";

    internal string STRING_ID
    {

        get { return csStringID; }
    }


    internal string Get_String2()
    {

        return ("my string2");
    }

}

}

This may not be the correct solution for your problem or the best one, but give it a try and see if you can use anything from it. With a bucket you can even create typed buckets to avoid weirdness casting back, and only have to work on your Add to make sure everything goes in the correct bucket. You can also make it a Queue instead (all depends on your requirements).

class Program
{ 
    public abstract class BaseEntity
    {
        public string ClassId { get; set; }
    }

    public class ColorEntity : BaseEntity
    {
        public string Color { get; set; }
    }

    public class PlayerEntity : BaseEntity
    {
        public string Position { get; set; }
    }

    public static class EntityBucket
    {
        private static Dictionary<Type, List<BaseEntity>> _collection =
            new Dictionary<Type, List<BaseEntity>>();

        public static void Add<T>(T entity) where T: BaseEntity
        {
            Type t = typeof(T);

            if (_collection.ContainsKey(t))
                _collection[t].Add(entity);
            else
                _collection.Add(t, new List<BaseEntity> { entity });
        }

        public static List<ColorEntity> GetColors()
        {
            var t = typeof(ColorEntity);
            if (_collection.ContainsKey(t))
                return _collection[t].Select(s => s as ColorEntity).ToList();

            return null;
        }
    }

    static void Main(string[] args)
    {
        EntityBucket.Add(new ColorEntity { Color = "Red" });
        EntityBucket.Add(new PlayerEntity { Position = "X,Y,Z" });
        EntityBucket.Add(new ColorEntity { Color = "Black" });

        var colors = EntityBucket.GetColors();
        Console.ReadKey();
    }
}

I’m currently working right now on a Entity Component architecture for Monogame.
Unity is based on this architecture also.
This is an alternate approach to class hirerachy, where each component has its own state and behavior.
Surprised nobody mentionned it

1 Like

It’s essentially what I did by creating a base entity.

public abstract class BaseEntity

And every other entity inherits from it. It will weight on system communication and iteration, but that’s up to the architect and requirements to determine.

Just because you name a class ‘Entity’ doesn’t makes an Entity Component architecture :slight_smile:

With this architecture you are not supposed to inherit.
Here is couple article on the pattern:
http://www.randygaul.net/2013/05/20/component-based-engine-design/


http://www.chris-granger.com/2012/12/11/anatomy-of-a-knockout/

1 Like

You are absolutely right I was thinking of something completely different, but in that case why not use the Component model in Monogame already.

but in that case why not use the Component model in Monogame already.

I’m reusing the IComponent / IUpdateable / IDrawable interfaces indeed.
But in monogame these are designed to be global, while in an entity component system it is meant to be local to an entity.
Also each component can use other components, so a component resolution mechanism is needed

1 Like

For those who are interested we have ECS already implemented in MonoGame.Extended.

1 Like

wow good to know! I see it’s based on Artemis, I did have a look.
I wish I knew about it earlier :slight_smile:

You could just get rid of the base classes altogether.
Each type can be the exact size it needs to be.
Alternatively…
Instead of looking at it from the point of view of wrapping the classes.

You could create a class that tunnels into each and tracks them into itself.
Now this may seem a bit weird but its yet another way to solve the problem.

Its not a generic solution, its a specific solution.
Not everything has to be generic all the time.

I doubt this is a pattern, since i just made it up.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace QuickNDirtyTunnelingIterator
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Test test;       

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            test = new Test();

        }
        protected override void Initialize()
        {
            base.Initialize();
        }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            base.Draw(gameTime);
        }
    }
    public class Test
    {
        public Test()
        {
            A a0 = new A();
            A a1 = new A();
            B b0 = new B();
            C c0 = new C();
            A a2 = new A();

            for (int i = 0; i < IterationTunnel.thisList.Count; i++)
            {
                switch (IterationTunnel.thisList[i].whichArray)
                {
                    case IterationTunnel.IS_TYPE_A:
                        Console.WriteLine("IterationTracker.thisList[" + i + "]" + IterationTunnel.thisList[i].a_ref._Pos3D);
                        break;
                    case IterationTunnel.IS_TYPE_B:
                        Console.WriteLine("IterationTracker.thisList[" + i + "]" + IterationTunnel.thisList[i].b_ref._Color);
                        break;
                    case IterationTunnel.IS_TYPE_C:
                        Console.WriteLine("IterationTracker.thisList[" + i + "]" + IterationTunnel.thisList[i].c_ref._IsReceivingShadows);
                        break;
                }
            }
        }
    }


    public class IterationTunnel
    {
        public static List<IterationTunnel> thisList = new List<IterationTunnel>();
        public const int IS_TYPE_A = 0;
        public const int IS_TYPE_B = 1;
        public const int IS_TYPE_C = 2;
        public A a_ref;
        public B b_ref;
        public C c_ref;
        public int whichArray = -1;
        public IterationTunnel(A item)
        {
            whichArray = IS_TYPE_A;
            a_ref = item;
            thisList.Add(this);
        }
        public IterationTunnel(B item)
        {
            whichArray = IS_TYPE_B;
            b_ref = item;
            thisList.Add(this);
        }
        public IterationTunnel(C item)
        {
            whichArray = IS_TYPE_C;
            c_ref = item;
            thisList.Add(this);
        }
    }
    public class A
    {
        public IterationTunnel tracker;
        public Vector3 _Pos3D;
        public Texture2D _TexChannelA;
        //... (other mandatory properties)

        public A()
        {
            Console.WriteLine("A constructing...");
            tracker = new IterationTunnel(this);
            Console.WriteLine("A constructed");
        }
    }
    public class B
    {
        public IterationTunnel tracker;
        public Vector3 _Pos3D;
        public Texture2D _TexChannelA;
        public Vector4 _Color;
        //Other props
        public B()
        {
            Console.WriteLine("B constructing...");
            tracker = new IterationTunnel(this);
            Console.WriteLine("B constructed");
        }
    }
    public class C
    {
        public IterationTunnel tracker;
        public Vector3 _Pos3D;
        public Texture2D _TexChannelA;
        public Vector4 _Color;
        public bool _IsReceivingLight;
        public bool _IsCastingShadows;
        public bool _IsCastingLight;
        public bool _IsReceivingShadows;
        //Other props
        public C()
        {
            Console.WriteLine("C constructing...");
            tracker = new IterationTunnel(this);
            Console.WriteLine("C constructed");
        }
    }
}

The output is as follows.

A constructing…
A constructed
A constructing…
A constructed
B constructing…
B constructed
C constructing…
C constructed
A constructing…
A constructed
IterationTracker.thisList[0]{X:0 Y:0 Z:0}
IterationTracker.thisList[1]{X:0 Y:0 Z:0}
IterationTracker.thisList[2]{X:0 Y:0 Z:0 W:0}
IterationTracker.thisList[3]False
IterationTracker.thisList[4]{X:0 Y:0 Z:0}

The trick here this time, and you can make up different takes on it is…
We just replace the type with a int, so we don’t have to cast we just catch it with a proper type or just call on the instance. Thus avoiding boxing unboxing.
We replace the container with a injected tracker into each class to be tracked.
We get rid of the inheiritance so we don’t have to worry about vtable calls.
We self register on object construction to the tunneled tracker by reference.
We can keep the instance or we can iterate the tunnelers list that links to it by reference.

Note you don’t have to have a tracker in each class you could just call new IterationTunnel(this); all by itself i left it in to show how you can link from the class to the list bi directionally if desired.

Btw on the earlier suggestion of Arraylists. Be Warned ! they are not only slow, worse they treat everything as if they are objects internally. Meaning they box and unbox everything.

The big reason to avoid properties in my opinion is you could potentially be hiding side effects that the setter/getter is hiding. Any setter/getter could have any amount of code in it. To hide that via a call to something like ‘someObject.expensiveSetter = thing’ isn’t fantastic. We also get in this nasty situation where our instance variable declarations have some ugly as hell syntax with all that get/set junk and curly braces all over the place. We get code mixed in with those declarations making it harder for people new to the code to parse it. Lots of good reasons to avoid them and very few to use them.

…it breaks the code guidelines we all come to agree upon…

I don’t remember getting a call from Microsoft to voice my opinion :wink: I didn’t agree upon any of what they came up with for the code they write. If I learn of a better way to do things I will not hesitate to adopt it.

Microsoft made a decision on conventions 10 years ago when the language was vastly different than today’s C#. They are bound to it. Your code is not. Come up with your own conventions and just implement them consistently across all your code and you’ll make your life a happier place :slight_smile:

Basically my point; it’s hard to have “generic” architecture; it’s going to depend on so many factors. But there are some patterns and solutions that do pop-up time after time in various languages and that’s why I suggest @Alkher that you should read up on patterns found in game programming.

If you write your own properties, you know what the getter/setter do.
Writing string MyProperty {get;set;} isn’t more expensive than string MyField; as the compiler treats a property with empty getter/setter just like a regular field.

Today they are focusing on .NET Core and they are free to change what they did wrong. Looks like they haven’t seen anything wrong with properties.