0

I'm refactoring a lot of stuff in my game,
And through CodeReview it's come to my understanding the I'm making the graphic module entirely wrong. And by that, I mean making the all modules know the UI instead of making the UI know all modules.

GitHub to the game code

Btw: the class is obviously not finished, it has some old stuff that I checked (Like Texture2D PlayerHealthTexture and so on)


Currently, my UI is a static class that is something like this:

using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace ModuloFramework.UI
{
    public delegate void UIDrawEventHandler(SpriteBatch spriteBatch);

    public static class UI
    {
        private static Dictionary<Color, Texture2D> ColorTextureRepository { get; set; }

        public static Texture2D GetColorTexture(Color color, GraphicsDevice graphicsDevice)
        {
            if (ColorTextureRepository.ContainsKey(color))
                return ColorTextureRepository[color];
            Texture2D tex = new Texture2D(graphicsDevice, 1, 1);
            tex.SetData<Color>(new Color[] { color });
            ColorTextureRepository[color] = tex;
            return tex;
        }

        public static SpriteFont Font { get; set; }

        public static Texture2D PlayerHealthTexture { get; set; }

        public static event UIDrawEventHandler DrawingEvent;

        public static void SubscribeToUIDraw(UIDrawEventHandler handler)
        {
            DrawingEvent += handler;
        }

        public static void UnsubscribeFromUIDraw(UIDrawEventHandler handler)
        {
            DrawingEvent -= handler;
        }

        public static void Initialize(GraphicsDevice graphicsDevice)
        {
            ColorTextureRepository = new Dictionary<Color, Texture2D>();
        }

        public static void LoadContent(ContentManager manager)
        {
            Font = manager.Load<SpriteFont>("UI/MainFont");
        }

        public static void Draw(SpriteBatch spriteBatch)
        {
            if (spriteBatch != null)
                DrawingEvent?.Invoke(spriteBatch);
        }
    }
}

And, whenever I want something to draw on the UI, I do something like this:

public ItemBehavior()
{
    UI.SubscribeToUIDraw(PrintUi);
    isDrawn = false;
}

protected override void BehaviorImplementation(IUnit destinationPlayer)
{
    Debug.Print("Behavior test print");
    isDrawn = !isDrawn;
}

private void PrintUi(SpriteBatch spriteBatch)
{
    if (!isDrawn) return;
    spriteBatch.DrawString(UI.Font, string.Format("Test"), new Vector2(20, 50),
        Color.Black);
}

I want to know what's a better way to do that UI module.
For example, if I have an Inventory class that's supposed to have a visual representation on the UI, do I make a Draw() method in the Inventory class, or do I make a DrawInventory(Inventory inventory) method in the UI class?


Also, should I make a IDrawingEngine interface and have UI become a singleton that implements that interface, as recommended in the CodeReview post?
If I do that, and say I follow the second method(having UI know other modules), How would that interface be useful to me outside of the UI class itself?


Thanks for helping!

Community
  • 1
  • 1
Giora Guttsait
  • 1,279
  • 15
  • 29

1 Answers1

0

This a very open question and my first recommendation is to go and look at home WPF and Winforms do their rendering. I also recommend picking up a copy of the Unreal Engine SDK and looking at how they have structured the UI. There are some interesting ideas out there.

A fundamental note

This isn't a new problem. People have spent a lot of time solving it already. Be inspired by their results! Is there an open source library you can integrate?

The issue at hand

Each item on the screen should be able to function alone and will have a different graphical representation. Separate the different UI elements into classes. You will probably want a base class for the basic UI support - Render() etc. Your Inventory should be its own class.

The reason you can an interface is so that you can change the UI later if you want to. Perhaps you have two versions of the UI and you want to swap them in and out for performance testing! Static things prevent you from doing that.

Gusdor
  • 14,001
  • 2
  • 52
  • 64