OWL is a lightweight scene graph for MonoGame. It aims to make rendering and scene management easier, especially for people who are new to MonoGame, by letting you build your game out of a tree of display objects instead of managing sprite batches and transforms by hand.
If you've used a retained-mode 2D library like PIXI.js or Flash's display list before, OWL will feel familiar: you create nodes, nest them inside each other, set a position/rotation/scale on a parent, and every child moves with it.
In plain MonoGame you draw everything through a SpriteBatch, and any grouping, relative positioning, or parent/child movement is something you track yourself. A scene graph flips that around. You arrange your game as a hierarchy of nodes, give each one a local transform, and OWL walks the tree each frame to work out where everything ends up on screen and to draw it in the right order. Move a container and its whole subtree moves with it; fade a parent's alpha and its children fade too.
- Hierarchical display list —
ContainerandSpritenodes that nest arbitrarily deep, with transforms that cascade from parent to child. - Full 2D transforms — position, rotation, scale, anchor and skew, resolved through a compact 2×3 matrix (
Matrix2) so world transforms stay cheap to compute. - Alpha inheritance — a node's world alpha is its own alpha multiplied by its parent's, so fading a group just works.
- Batched rendering — a
Rendererwrapping aBatcherhandles the actual draw calls; draw order is tracked automatically as the tree is traversed. - Materials — per-node
BlendState,DepthStencilStateandEffect(shader) via theMaterialclass, adapted from Nez. - Alpha masking — assign a mask sprite to another sprite and OWL sets up stencil-buffer masking for you.
- Texture atlases —
TextureAtlas/TextureRegion2Dplus a content-pipelineTextureAtlasReader, so you can pack sprites into a single sheet and address regions by name. - Bounds & collision — automatic bounding-box calculation for any node, plus a simple AABB
Collidehelper. - Utility belt — math helpers (
Mathf), color/texture/vector extension methods, seeded RNG, string hashing and more.
- .NET Core 3.1 (
netcoreapp3.1) - MonoGame.Framework.Portable 3.7.1
There's no NuGet package yet, so add OWL to your solution directly:
- Clone this repository.
- Add
OWL/OWL.csprojto your MonoGame solution. - Add a project reference to it from your game project.
git clone https://github.com/Owlzy/OWL.gitThe pattern is: build a tree of nodes once, then draw the root through a Renderer each frame.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using OWL.Graph;
using OWL.Rendering;
public class MyGame : Game
{
private GraphicsDeviceManager _graphics;
private Renderer _renderer;
private Container _root;
private Sprite _player;
public MyGame()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
// The renderer owns the batcher that issues draw calls.
_renderer = new Renderer(GraphicsDevice);
// The root of your scene graph.
_root = new Container();
// A sprite is just a node with a texture.
var texture = Content.Load<Texture2D>("player");
_player = new Sprite(texture);
_player.SetAnchor(0.5f); // rotate/scale about the centre
_player.SetPosition(400, 240);
_player.Tint = Color.White;
_root.AddChild(_player);
}
protected override void Update(GameTime gameTime)
{
// Because the player is a child of the root, moving or rotating
// the root moves the whole scene; here we just spin the player.
_player.Rotation += 0.02f;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_renderer.BeginRender();
_renderer.Render(_root); // walks the tree, updates transforms, draws
_renderer.EndRender();
base.Draw(gameTime);
}
}Anything you add to a Container inherits its transform, so grouping is as simple as parenting:
var squad = new Container();
squad.SetPosition(100, 100);
squad.AddChild(new Sprite(texture) { X = 0 });
squad.AddChild(new Sprite(texture) { X = 40 });
squad.AddChild(new Sprite(texture) { X = 80 });
// Move or fade the whole squad at once.
squad.Rotation = 0.3f;
squad.Alpha = 0.5f;
_root.AddChild(squad);| Area | Files | What it does |
|---|---|---|
| Graph | Node, Container, Drawable, Sprite |
The display list. Node is the abstract base holding transforms and the child list; Sprite is the drawable leaf you'll use most. |
| Rendering | Renderer, Batcher, Material, GraphicsResource |
Traverses the tree and issues batched draw calls, with per-node blend/stencil/shader state. |
| Texture | TextureAtlas, TextureRegion2D, TextureAtlasReader |
Sprite-sheet support, including a content-pipeline reader for packed atlases. |
| Math | Mathf, Matrix2 |
Fast math helpers and the 2×3 transform matrix used throughout. |
| Extensions | ColorExtensions, Texture2DExtensions, VectorExtensions |
Convenience methods on common XNA/MonoGame types. |
| Utils | Utils, Bounds, ReflectionUtils |
Bounding boxes, AABB collision, seeded random, string hashing and other odds and ends. |
Higher-level patterns built on top of OWL — scene stacks, pause menus, asset loading screens with progress, sprite transitions — live in the companion repository:
Note that constructs like a Scene class and a scene stack are demonstrated there rather than in the core library, so OWL stays small and unopinionated about how you structure a game.
The renderer, batcher and material system are adapted from Nez by prime31, and the transform/vertex maths follows the approach used by PIXI.js. Thanks to both projects.
Released under the MIT License. Copyright © 2022 Owlzy.
