I’m trying to create 2 classes for my UI system, i don’t want to know if a library in this style exist, i’m actualy in a training center, and i need to make a standalone project, it’s only a training purpose. So i Have a project build with MVC and State, everything is automatized and it’s working fine. I currently have 2 States (StateStartScreen and StateMainMenu), with every association to their respective Model, Controller, View.
So for my UI System, i have 2 classes Box<TEntity> : GUIBase
and BoxContainer<TEntity> : Box<TEntity>
, GUIBase only purpose is to set the game and state in the constructor, the purpose of those classes is to create a box with a Texture2D, a SpriteFont and other stuff later like Videos, effects. and in the case of BoxContainer, you can create multiple other instance of those classes and the position and size are set so element in BoxContainer are positionate with the main container size, so the base Box of BoxContainer. Those classes works fine for drawing a single Texture2D element, and the position of the element is good too but when there is more element it doesnt’ work for the next element and not at all for SpriteFont, it just don’t appear
public enum VerticalAlignment { Top, Center, Bottom }
public enum HorizontalAlignment { Left, Center, Right }
public class Box<TEntity> : GUIBase
{
protected TEntity _boxContent;
private string _boxPath;
private string _text;
protected Vector2 Size;
protected Vector2 Position;
private Vector2 _offset = Vector2.Zero;
private HorizontalAlignment _horizontalAlignment;
private VerticalAlignment _verticalAlignment;
// CONSTRUCTOR FOR CONTENT ELEMENT
public Box(GameBase game, State state, string boxPath, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, VerticalAlignment verticalAlignment = VerticalAlignment.Top, Vector2 offset = default) : base(game, state)
{
_boxPath = boxPath;
_horizontalAlignment = horizontalAlignment;
_verticalAlignment = verticalAlignment;
_offset = offset;
}
// OVERRIDE FOR SPRITEFONT TEXT
public Box(GameBase game, State state, string boxPath, string text, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, VerticalAlignment verticalAlignment = VerticalAlignment.Top, Vector2 offset = default) : this(game, state, boxPath, horizontalAlignment, verticalAlignment, offset)
{
if (typeof(TEntity).Equals(typeof(SpriteFont)))
{
_text = text;
}
}
// LOAD THE CONTENT FOR ANY TYPES
public override void LoadContent(ContentManager content)
{
if (typeof(TEntity).Equals(typeof(Texture2D)))
{
_boxContent = (TEntity)(object)content.Load<Texture2D>(_boxPath);
}
else if (typeof(TEntity).Equals(typeof(SpriteFont)))
{
_boxContent = (TEntity)(object)content.Load<SpriteFont>(_boxPath);
}
Size = new Vector2(GetContentWidth(), GetContentHeight());
Position = CalculateBoxPosition(_horizontalAlignment, _verticalAlignment, BoxContainer<TEntity>.SizeContainer);
}
public override void Update(GameTime gameTime)
{
}
// DRAW CONTENT FOR ANY TYPES
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
if (typeof(TEntity).Equals(typeof(Texture2D)))
{
spriteBatch.Draw((Texture2D)(object)_boxContent, Position, Color.White);
}
else if (_boxContent is SpriteFont spriteFont)
{
spriteBatch.DrawString(spriteFont, _text, Position, Color.White);
}
}
// CALCULATE THE MAIN BOX POSITION FROM CONTAINER SIZE
private Vector2 CalculateBoxPosition(HorizontalAlignment horizontal, VerticalAlignment vertical, Vector2 containerSize)
{
return new Vector2(CalculateHorizontal(horizontal, containerSize.X) + _offset.X, CalculateVertical(vertical, containerSize.Y) + _offset.Y);
}
private float CalculateHorizontal(HorizontalAlignment horizontal, float containerWidth)
{
return horizontal is HorizontalAlignment.Right ? containerWidth - Size.X : horizontal is HorizontalAlignment.Center ? (containerWidth - Size.X) / 2f : 0;
}
private float CalculateVertical(VerticalAlignment vertical, float containerHeight)
{
return vertical is VerticalAlignment.Bottom ? containerHeight - Size.Y : vertical is VerticalAlignment.Center ? (containerHeight - Size.Y) / 2f : 0;
}
// GET CURRENT CONTENT WIDTH
private float GetContentWidth()
{
if (typeof(TEntity).Equals(typeof(Texture2D)))
{
return ((Texture2D)(object)_boxContent).Width;
}
if (typeof(TEntity).Equals(typeof(SpriteFont)))
{
SpriteFont spriteFont = (SpriteFont)(object)_boxContent;
return spriteFont.MeasureString(_text).X; // Utilisez la largeur du texte mesuré avec le SpriteFont
}
return 0f;
}
// GET CURRENT CONTENT HEIGHT
private float GetContentHeight()
{
if (typeof(TEntity).Equals(typeof(Texture2D)))
{
return ((Texture2D)(object)_boxContent).Height;
}
if (typeof(TEntity).Equals(typeof(SpriteFont)))
{
SpriteFont spriteFont = (SpriteFont)(object)_boxContent;
return spriteFont.MeasureString(_text).Y; // Utilisez la hauteur du texte mesuré avec le SpriteFont
}
return 0f;
}
}
public class BoxContainer<TEntity> : Box<TEntity>
{
public static Vector2 SizeContainer { get; private set; }
private readonly ArrayList _elements;
public BoxContainer(GameBase game, State state, string boxPath, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, VerticalAlignment verticalAlignment = VerticalAlignment.Top, Vector2 offset = default) : base(game, state, boxPath, horizontalAlignment, verticalAlignment, offset)
{
_elements = new ArrayList();
}
public void AddElement(object element)
{
_elements.Add(element);
}
public void RemoveElement(object element)
{
_elements.Remove(element);
}
public override void LoadContent(ContentManager content)
{
base.LoadContent(content);
SizeContainer = Size;
foreach (var element in _elements)
{
if (element is Box<TEntity> box)
{
box.LoadContent(content);
}
else if (element is BoxContainer<TEntity> container)
{
container.LoadContent(content);
}
}
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
foreach (var element in _elements)
{
if (element is Box<TEntity> box)
{
box.Update(gameTime);
}
else if (element is BoxContainer<TEntity> container)
{
container.Update(gameTime);
}
}
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
base.Draw(gameTime, spriteBatch);
foreach (var element in _elements)
{
if (element is Box<TEntity> box)
{
box.Draw(gameTime, spriteBatch);
}
else if (element is BoxContainer <TEntity> container)
{
container.Draw(gameTime, spriteBatch);
}
}
}
}
I don’t get any error when debugging, i try to draw a basic SpriteFont in my ViewStartScreen with the same .spritefont and it worked fine, so i presume the problem is in a if(typeof condition) or maybe in the setting of position and size, then i tried to put multiple items in a BoxContainer and it wont work fine, the playButton is well place but not the loadButton in the ViewMainMenu and for the SpriteFont, it only appear when i create a simple Box, here is some screen and the code of the 2 views
public class ViewStartScreen : ViewBase
{
private BoxContainer<Texture2D> background;
private Box<Texture2D> logo;
private Box<SpriteFont> pressAny;
private Box<SpriteFont> pressAny2;
public ViewStartScreen(GameBase game, State currentState) : base(game, currentState) { }
public override void LoadContent(ContentManager content)
{
background = new BoxContainer<Texture2D>(_game, _currentState, "image/main-background");
logo = new Box<Texture2D>(_game, _currentState, "image/logo", HorizontalAlignment.Center, VerticalAlignment.Top, new Vector2(0, 100));
pressAny = new Box<SpriteFont>(_game, _currentState, "text/PressAnyKey", "PRESS ANY DON'T WORK KEY", HorizontalAlignment.Center);
pressAny2 = new Box<SpriteFont>(_game, _currentState, "text/PressAnyKey", "PRESS ANY NEARLY WORK KEY", HorizontalAlignment.Center, VerticalAlignment.Center);
background.AddElement(logo);
background.AddElement(pressAny);
background.LoadContent(content);
pressAny2.LoadContent(content);
}
public override void Update(GameTime gameTime)
{
background.Update(gameTime);
pressAny2?.Update(gameTime);
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
background.Draw(gameTime, spriteBatch);
pressAny2.Draw(gameTime,spriteBatch);
}
}
Result ViewStartScreen :
The visible text in the top of the window is pressAny2, pressAny is not visible or out of window range
public class ViewMainMenu : ViewBase
{
private BoxContainer<Texture2D> background;
private BoxContainer<Texture2D> menuOverlay;
private Box<Texture2D> menuIcon;
private BoxContainer<Texture2D> playButton;
private BoxContainer<Texture2D> loadButton;
public ViewMainMenu(GameBase game, State currentState) : base(game, currentState) { }
public override void LoadContent(ContentManager content)
{
background = new BoxContainer<Texture2D>(_game, _currentState, "image/main-background");
menuOverlay = new BoxContainer<Texture2D>(_game, _currentState, "overlay/menu-overlay");
menuIcon = new Box<Texture2D>(_game, _currentState, "image/logo", HorizontalAlignment.Center, VerticalAlignment.Top, new Vector2(0, 30));
playButton = new BoxContainer<Texture2D>(_game, _currentState, "image/active-button", HorizontalAlignment.Center, VerticalAlignment.Bottom, new Vector2(0,-200));
loadButton = new BoxContainer<Texture2D>(_game, _currentState, "image/active-button", HorizontalAlignment.Center, VerticalAlignment.Bottom, new Vector2(0,0));
menuOverlay.AddElement(menuIcon);
menuOverlay.AddElement(playButton);
menuOverlay.AddElement(loadButton);
background.AddElement(menuOverlay);
background.LoadContent(content);
}
public override void Update(GameTime gameTime)
{
background.Update(gameTime);
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
background.Draw(gameTime, spriteBatch);
}
}
Result ViewMainmenu :
And that is what i want to do with those classes :
I’m still a junior developer in training so it’s possible for me to make basic error but from what i can see and my experience i didn’t find anything. Thank you for your time.
PS : Sorry for my bad english, im not native, if you didn’t understand something don’t hesitate to ask me