| name | engine-overview |
| description | Engine overview for FlatRedBall2. Start here for any game development task. Covers what the engine does automatically vs what game code must implement, the frame loop, bootstrapping, and known stubs. Trigger when starting a new game, needing to understand the engine architecture, or unsure how FlatRedBall2 works. |
FlatRedBall2 Engine Overview
FlatRedBall2 is a 2D game engine built on MonoGame. It provides physics, collision, rendering, input, and UI (via Gum) out of the box. Game code creates Screens, Entities, and wires them together.
What the Engine Does Automatically
- Physics:
pos += vel*dt + acc*(dt^2/2), vel += acc*dt, vel -= vel*drag*dt — every frame, for every entity
- Collision resolution: All registered
CollisionRelationship pairs are tested and resolved after physics
- Rendering: Everything added via
screen.Add(renderable) is drawn, sorted by Layer + Z
- Input polling:
Input updates keyboard, mouse, and gamepad state each frame
- Gum UI updates: Click/hover/focus events routed to all active Gum elements
- Screen transitions: Old screen torn down, new screen initialized — entities, factories, Gum elements all cleaned up automatically
- Camera: Initialized from window viewport; transforms world coordinates to screen
What Game Code Must Implement
- Entity subclasses — override
CustomInitialize (add shapes, input) and CustomActivity (per-frame logic)
- Screen subclasses — override
CustomInitialize (create factories, entities, collision relationships, UI)
- Collision relationships — call
AddCollisionRelationship in screen's CustomInitialize
- Game1.cs — initialize
FlatRedBallService.Default, call Update/Draw each frame
Frame Loop Order
Each frame runs in this order:
- Screen transition (if pending) — old screen destroyed, new screen initialized
- Input update — keyboard, mouse, gamepad polled
- Gum update — UI input events routed
- Physics — entity positions updated from velocity/acceleration/drag
- Collision — registered relationships resolved; positions corrected
- Entity
CustomActivity — each entity's per-frame logic
- Screen
CustomActivity — screen-level logic (sees post-collision, post-entity state)
- Draw — all registered renderables drawn
Bootstrapping a Game
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
FlatRedBallService.Default.PrepareWindow<GameplayScreen>(_graphics);
}
protected override void Initialize()
{
base.Initialize();
FlatRedBallService.Default.Initialize(this);
FlatRedBallService.Default.Start<GameplayScreen>();
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit();
FlatRedBallService.Default.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
FlatRedBallService.Default.Draw();
base.Draw(gameTime);
}
Key Design Rules
- Y+ is up in world space. Camera flips Y for screen rendering.
- Always use
Factory<T> to create entities — never new MyEntity(). Factory sets Engine, registers with the screen, and enables GetFactory<T>().
- No static state (engine infrastructure only) — only
FlatRedBallService.Default is static. Everything else is accessed via Engine on entities or directly on screens. Game code may use static singletons for global game data (e.g., GameData.Current holding a monster roster or player save state) — this rule prohibits engine-layer statics, not application-layer ones.
- Shapes default to
IsVisible = false — always set IsVisible = true.
Entity.Engine: Use CustomInitialize, not the constructor — Engine is null until Factory injects it.
- Use Gum for all UI — HUD, health bars, menus, win/lose screens, any text display. Shapes are for world-space game objects (collision geometry, projectiles, platforms). If you reach for a shape to build UI, stop and use Gum instead.
Complete Screen Example
A minimal but complete screen showing factory + entity + collision + input wired together:
public class GameScreen : Screen
{
private Factory<Player> _playerFactory = null!;
private Factory<Wall> _wallFactory = null!;
public override void CustomInitialize()
{
_playerFactory = new Factory<Player>(this);
_wallFactory = new Factory<Wall>(this);
_playerFactory.Create();
var wall = _wallFactory.Create();
wall.X = 0; wall.Y = -Camera.OrthogonalHeight / 2f;
wall.Rectangle.Width = Camera.OrthogonalWidth; wall.Rectangle.Height = 40;
AddCollisionRelationship<Player, Wall>(_playerFactory, _wallFactory)
.MoveFirstOnCollision();
}
public override void CustomActivity(FrameTime time)
{
}
}
Sub-Systems (accessed via Engine.*)
| Property | Type | Purpose |
|---|
Input | InputManager | Keyboard, cursor, gamepads |
Content | ContentLoader | Load textures, fonts via .mgcb pipeline |
Random | GameRandom | Seeded random with helpers (Between, RadialVector2) |
Time | TimeManager | Frame timing, async delays |
Audio | AudioManager | Stub — throws NotImplementedException |
DebugRenderer | DebugRenderer | Stub — all draw methods are no-ops |
Which Skill to Read Next
| Task | Skill |
|---|
| Set up screens and transitions | screens |
| Create entities with shapes | entities-and-factories |
| Load textures and use sprites | content-and-assets |
| Set up collision | collision-relationships |
| Handle input | input-system |
| Physics and movement | physics-and-movement |
| Platformer mechanics | platformer-movement |
| Camera setup | camera |
| UI/HUD with Gum | gum-integration |
| Timers and cooldowns | timing |
| Level layouts | levels |
| Shapes (no-art visuals) | shapes |