MenuBuddy 5.0.1
dotnet add package MenuBuddy --version 5.0.1
NuGet\Install-Package MenuBuddy -Version 5.0.1
<PackageReference Include="MenuBuddy" Version="5.0.1" />
<PackageVersion Include="MenuBuddy" Version="5.0.1" />
<PackageReference Include="MenuBuddy" />
paket add MenuBuddy --version 5.0.1
#r "nuget: MenuBuddy, 5.0.1"
#:package MenuBuddy@5.0.1
#addin nuget:?package=MenuBuddy&version=5.0.1
#tool nuget:?package=MenuBuddy&version=5.0.1
MenuBuddy
A complete MonoGame library for building menu systems and managing game state transitions. Based on the famous NetworkStateManagement samples from the golden age of XNA.
Features
- Screen-based architecture - Stack-based screen management with automatic transitions
- Multiple input modes - Support for controller, mouse, and touch input
- Rich widget library - Labels, buttons, sliders, dropdowns, text input, checkboxes, and more
- Flexible layouts - Absolute, relative, stack, scroll, padded, and tree layouts
- Customizable styling - Global stylesheet for consistent appearance across your UI
- Smooth transitions - Built-in fade, slide, and wipe transitions between screens
- Multi-platform - Works on DesktopGL, iOS, Android, and Windows Universal
Installation
Install via NuGet:
dotnet add package MenuBuddy
Or visit: https://www.nuget.org/packages/MenuBuddy/
Quick Start
1. Create Your Game Class
Extend one of the provided game base classes depending on your input type:
using MenuBuddy;
using Microsoft.Xna.Framework;
// For desktop with controller support
public class MyGame : ControllerGame
{
public MyGame()
{
VirtualResolution = new Point(1280, 720);
ScreenResolution = new Point(1280, 720);
}
public override IScreen[] GetMainMenuScreenStack()
{
return new IScreen[] { new MainMenuScreen() };
}
}
// For mobile/touch devices, use TouchGame instead:
// public class MyGame : TouchGame
// For mouse-based input:
// public class MyGame : MouseGame
2. Create a Menu Screen
using MenuBuddy;
using InputHelper;
using System.Threading.Tasks;
public class MainMenuScreen : MenuStackScreen
{
public MainMenuScreen() : base("Main Menu")
{
}
public override async Task LoadContent()
{
await base.LoadContent();
// Add menu entries
var startButton = new MenuEntry("Start Game", Content);
startButton.OnClick += (sender, e) =>
{
ScreenManager.AddScreen(new GameplayScreen());
};
AddMenuEntry(startButton);
var optionsButton = new MenuEntry("Options", Content);
optionsButton.OnClick += (sender, e) =>
{
ScreenManager.AddScreen(new OptionsScreen());
};
AddMenuEntry(optionsButton);
var exitButton = new MenuEntry("Exit", Content);
exitButton.OnClick += (sender, e) =>
{
ScreenManager.Game.Exit();
};
AddMenuEntry(exitButton);
}
}
3. Run Your Game
using var game = new MyGame();
game.Run();
Core Concepts
Screens
Screens are the fundamental building blocks of MenuBuddy. Each screen represents a distinct game state (main menu, options, gameplay, pause menu, etc.).
| Screen Type | Description |
|---|---|
Screen |
Abstract base class for all screens |
WidgetScreen |
Screen that can contain and manage widgets |
MenuScreen |
Widget screen with keyboard/controller navigation |
MenuStackScreen |
Menu screen with vertical stack layout |
MessageBoxScreen |
Modal dialog with OK/Cancel options |
OkScreen |
Simple alert dialog with OK button |
LoadingScreen |
Shows progress while loading content |
ErrorScreen |
Displays exception information |
Screen Lifecycle
LoadContent() -> Update() -> Draw() -> UnloadContent()
Screens support transitions when being added or removed:
// Add a screen with transition
await ScreenManager.AddScreen(new OptionsScreen(), controllingPlayer);
// Remove screen with exit transition
screen.ExitScreen();
// Clear all screens
ScreenManager.ClearScreens();
Widgets
Widgets are interactive UI elements that can be added to screens.
Labels
// Simple label
var label = new Label("Hello World", Content);
AddItem(label);
// Label with font size
var titleLabel = new Label("Game Title", Content, FontSize.Large);
AddItem(titleLabel);
Buttons
// Stack layout button (content stacked vertically/horizontally)
var button = new StackLayoutButton();
button.AddItem(new Label("Click Me", Content));
button.OnClick += (sender, e) => HandleClick();
AddItem(button);
// Relative layout button (content positioned relatively)
var relButton = new RelativeLayoutButton();
relButton.Size = new Vector2(200, 50);
relButton.AddItem(new Label("Button", Content));
AddItem(relButton);
Sliders
var slider = new Slider()
{
Min = 0,
Max = 100,
SliderPosition = 50,
HandleSize = new Vector2(64, 64),
Size = new Vector2(512, 128)
};
slider.OnDrag += (sender, e) =>
{
var value = slider.SliderPosition;
// Handle value change
};
AddItem(slider);
Text Input
var textEdit = new TextEdit("Default text", Content);
textEdit.Size = new Vector2(350, 128);
textEdit.Position = Resolution.ScreenArea.Center;
textEdit.HasOutline = true;
AddItem(textEdit);
Dropdowns
var dropdown = new Dropdown<string>(this);
dropdown.Size = new Vector2(350, 128);
dropdown.Position = Resolution.ScreenArea.Center;
string[] options = { "Option 1", "Option 2", "Option 3" };
foreach (var option in options)
{
var item = new DropdownItem<string>(option, dropdown)
{
Size = new Vector2(350, 64)
};
item.AddItem(new Label(option, Content, FontSize.Small));
dropdown.AddDropdownItem(item);
}
dropdown.SelectedItem = "Option 1";
AddItem(dropdown);
Checkboxes
var checkbox = new Checkbox();
checkbox.IsChecked = true;
checkbox.OnClick += (sender, e) =>
{
bool isChecked = checkbox.IsChecked;
};
AddItem(checkbox);
Layouts
Layouts control how widgets are positioned and arranged.
Stack Layout
Arranges items in a vertical or horizontal stack:
var stack = new StackLayout()
{
Alignment = StackAlignment.Top,
Horizontal = HorizontalAlignment.Center,
Position = new Point(Resolution.ScreenArea.Center.X, 100)
};
stack.AddItem(new Label("Item 1", Content));
stack.AddItem(new Label("Item 2", Content));
stack.AddItem(new Label("Item 3", Content));
AddItem(stack);
Scroll Layout
Provides scrollable content area:
var scroll = new ScrollLayout()
{
Position = Resolution.ScreenArea.Center,
Size = new Vector2(400, 300)
};
// Add many items that exceed the visible area
for (int i = 0; i < 20; i++)
{
scroll.AddItem(new Label($"Item {i}", Content));
}
AddItem(scroll);
Relative Layout
Position items relative to each other or the container:
var layout = new RelativeLayout();
layout.Size = new Vector2(500, 400);
var label = new Label("Centered", Content)
{
Horizontal = HorizontalAlignment.Center,
Vertical = VerticalAlignment.Center
};
layout.AddItem(label);
AddItem(layout);
Message Boxes
// Confirmation dialog
var confirm = new MessageBoxScreen("Are you sure?");
confirm.OnSelect += (sender, e) =>
{
// User clicked OK
};
confirm.OnCancel += (sender, e) =>
{
// User clicked Cancel
};
await ScreenManager.AddScreen(confirm, controllingPlayer);
// Simple alert
var alert = new OkScreen("Operation complete!", Content);
await ScreenManager.AddScreen(alert, controllingPlayer);
Loading Screens
Show a loading screen while content loads asynchronously:
// Load screens with loading indicator
LoadingScreen.Load(ScreenManager, new IScreen[] { new GameplayScreen() });
// With custom message
LoadingScreen.Load(ScreenManager, null, "Loading level...", new GameplayScreen());
Styling
Customize the appearance of your UI through the StyleSheet class:
protected override void InitStyles()
{
base.InitStyles();
// Fonts
StyleSheet.LargeFontResource = @"Fonts\MyLargeFont";
StyleSheet.MediumFontResource = @"Fonts\MyMediumFont";
StyleSheet.SmallFontResource = @"Fonts\MySmallFont";
StyleSheet.LargeFontSize = 72;
StyleSheet.MediumFontSize = 48;
StyleSheet.SmallFontSize = 24;
// Colors
StyleSheet.NeutralTextColor = Color.White;
StyleSheet.HighlightedTextColor = Color.Yellow;
StyleSheet.SelectedTextColor = Color.Gold;
StyleSheet.NeutralBackgroundColor = new Color(0, 0, 50, 128);
StyleSheet.HighlightedBackgroundColor = new Color(0, 0, 100, 180);
// Sounds
StyleSheet.HighlightedSoundResource = @"Sounds\MenuMove";
StyleSheet.ClickedSoundResource = @"Sounds\MenuSelect";
// Images
StyleSheet.ButtonBackgroundImageResource = @"Images\ButtonBg";
StyleSheet.CheckedImageResource = @"Images\Checked";
StyleSheet.UncheckedImageResource = @"Images\Unchecked";
// Options
StyleSheet.HasOutline = true;
StyleSheet.DefaultTransition = TransitionWipeType.SlideLeft;
}
Available Style Properties
| Property | Description |
|---|---|
LargeFontResource |
Font for titles |
MediumFontResource |
Font for widgets |
SmallFontResource |
Font for message boxes |
NeutralTextColor |
Default text color |
HighlightedTextColor |
Text color when highlighted |
SelectedTextColor |
Text color when selected |
NeutralBackgroundColor |
Default background color |
HighlightedBackgroundColor |
Background when highlighted |
HighlightedSoundResource |
Sound when item highlighted |
ClickedSoundResource |
Sound when item clicked |
HasOutline |
Enable outline rendering |
DefaultTransition |
Default screen transition type |
Screen Transitions
MenuBuddy supports various transition effects:
// Configure transition times
screen.Transition.OnTime = 0.5f; // Time to transition on
screen.Transition.OffTime = 0.5f; // Time to transition off
// Set transition type via StyleSheet
StyleSheet.DefaultTransition = TransitionWipeType.SlideLeft;
Available transition types:
TransitionWipeType.SlideLeftTransitionWipeType.SlideRightTransitionWipeType.PopTopTransitionWipeType.PopBottomTransitionWipeType.PopLeftTransitionWipeType.PopRight
Screen Properties
Control how screens interact with each other:
public class MyScreen : WidgetScreen
{
public MyScreen() : base("My Screen")
{
// This screen covers screens below it
CoverOtherScreens = true;
// This screen can be covered by screens above it
CoveredByOtherScreens = true;
// Modal screens block input to screens below
Modal = true;
}
}
Cancel Button
Add a standard cancel/back button to screens:
public override async Task LoadContent()
{
await base.LoadContent();
// Adds cancel button in corner (position configurable via StyleSheet)
AddCancelButton();
}
Error Handling
Display errors gracefully:
try
{
// Game logic
}
catch (Exception ex)
{
ScreenManager.ErrorScreen(ex);
}
Platform-Specific Setup
Use conditional compilation for platform-specific behavior:
#if __IOS__ || ANDROID || WINDOWS_UAP
public class Game1 : TouchGame
#else
public class Game1 : ControllerGame
#endif
{
public Game1()
{
#if DESKTOP
IsMouseVisible = true;
#endif
}
}
Dependencies
MenuBuddy depends on several companion libraries (automatically installed via NuGet):
- FontBuddy - Font rendering
- InputHelper - Input state management
- ResolutionBuddy - Resolution management
- PrimitiveBuddy - Primitive rendering
- GameTimer - Timing utilities
- And others...
Sample Project
For a complete working example with all widgets and features demonstrated, see the MenuBuddySample project.
The sample includes examples of:
- Main menu with navigation
- Options screens
- Scroll layouts
- Dropdowns
- Sliders
- Text input
- Tree layouts
- Context menus
- Drag and drop
- Loading screens
- Message boxes
API Reference
Game Base Classes
| Class | Input Type | Use Case |
|---|---|---|
ControllerGame |
Gamepad | Console/desktop with controller |
MouseGame |
Mouse | Desktop applications |
TouchGame |
Touch | Mobile devices |
Key Interfaces
| Interface | Description |
|---|---|
IScreen |
Base screen contract |
IScreenManager |
Screen management operations |
IWidget |
Base widget behavior |
ILayout |
Container layout behavior |
Common Methods
// ScreenManager
await ScreenManager.AddScreen(screen, player);
ScreenManager.ClearScreens();
ScreenManager.ErrorScreen(exception);
// Screen
screen.ExitScreen();
screen.AddItem(widget);
screen.RemoveItem(widget);
// Widget
widget.Position = new Point(x, y);
widget.Size = new Vector2(width, height);
widget.Horizontal = HorizontalAlignment.Center;
widget.Vertical = VerticalAlignment.Center;
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests on GitHub.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FilenameBuddy (>= 5.0.5)
- FontBuddy (>= 5.0.4)
- GameTimer (>= 5.0.8)
- HadoukInput (>= 5.0.0)
- InputHelper (>= 5.0.0)
- MatrixExtensions (>= 5.0.0)
- MouseBuddy (>= 5.0.0)
- PrimitiveBuddy (>= 5.0.0)
- RandomExtensions.dmanning23 (>= 5.0.0)
- ResolutionBuddy (>= 5.0.0)
- StateMachineBuddy (>= 5.0.5)
- TouchScreenBuddy (>= 5.0.0)
- Vector2Extensions (>= 5.0.0)
- XmlBuddy (>= 5.0.0)
NuGet packages (11)
Showing the top 5 NuGet packages that depend on MenuBuddy:
| Package | Downloads |
|---|---|
|
FlashCards
MonoGame library for making little flashcard games |
|
|
InsertCoinBuddy
A very simple MonoGame library that sits and listens for coin drops (keyboard press, etc.) and tracks number of credits. |
|
|
HighScoreBuddy
HighScoreBuddy is a MonoGame library for saving and loading of local high score tables. |
|
|
LifeBarBuddy
MonoGame library for rendering meters like life and energy bars |
|
|
AudioBuddy
MonoGame library for audio management |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.1 | 110 | 1/27/2026 |
| 5.0.0 | 538 | 10/10/2025 |
| 4.0.5 | 1,594 | 10/31/2023 |
| 4.0.4 | 1,296 | 10/24/2023 |
| 4.0.3 | 1,485 | 9/8/2023 |
| 4.0.1 | 1,398 | 9/8/2023 |
| 4.0.0 | 1,411 | 9/8/2023 |
| 2.0.93 | 2,126 | 2/15/2022 |
| 2.0.92 | 2,019 | 9/9/2021 |
| 2.0.91 | 1,950 | 8/6/2021 |
| 2.0.90 | 1,942 | 7/23/2021 |
| 2.0.89 | 2,033 | 7/16/2021 |
| 2.0.88 | 2,014 | 5/14/2021 |
| 2.0.87 | 1,885 | 5/13/2021 |
| 2.0.86 | 1,960 | 5/13/2021 |
| 2.0.85 | 2,025 | 5/11/2021 |
| 2.0.84 | 2,046 | 2/17/2021 |
| 2.0.83 | 2,143 | 1/13/2021 |
| 2.0.82 | 2,154 | 10/1/2020 |
| 2.0.81 | 2,157 | 8/25/2020 |