Exfal 6.0.0

dotnet add package Exfal --version 6.0.0
                    
NuGet\Install-Package Exfal -Version 6.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Exfal" Version="6.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Exfal" Version="6.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Exfal" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Exfal --version 6.0.0
                    
#r "nuget: Exfal, 6.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Exfal@6.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Exfal&version=6.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Exfal&version=6.0.0
                    
Install as a Cake Tool

Exfal

Exfal is a painkiller for MonoGame, providing an object-oriented rendering pipeline, input handling, time management, and even coroutines. It simplifies the development of games and graphical applications by handling common boilerplate code usually required in MonoGame projects.

Features

  • Object-oriented rendering system
  • Multiple cameras
  • Static resolution
  • Input handling
  • Time management
  • Coroutine system (StepTask)
  • Extensions for Vector2 and numerics
  • Works with MonoGame and other XNA-compatible frameworks

How To Use?

You can use only the modules you need. Basic modules are:

Rendering
StepTask (coroutine)
Time
Input

All modules are designed to work independently. If you don't need a module, simply don't use it.

Rendering

To draw something, create a proper function.

void Draw(DrawContext draw)
{
    // draw a rectangle on 0,0 position with width and height 10
    draw.Rectangle(new Rectangle(0, 0, 10, 10), Color.White);
} 

DrawContext has different kinds of methods for drawing. You can still use SpriteBatch.Draw(...)

For draw.Texture(...) and some others there is the DrawOptions structure in arguments. It is used to combine several parameters in one object, so consider it as just a simpler way to give arguments:

DrawOptions opts = new DrawOptions() { 
    position = new Vector2(x, y),
    origin = new Vector2(x, y),
    scale = new Vector2(width, height),
    color = Color.White,
    rotationRad = Deg2Rad(45) 
};

//you can store it as long as you need and change at any time
opts.position = Vector2.Zero;

renderer.DrawTexture(texture, opts);

Then, you'll have to register the method:

renderer.Cameras[Renderer.DefaultCameraIndex].Register(Draw);

You can also use more than one camera:

renderer.Cameras.Add(1, new Camera(renderer.Graphics, new Point(1920, 1080)));
renderer.Cameras[1].Register(Draw);

Each camera handles only its own registered draws.

Call renderer.Draw() in your draw cycle. Do not call SpriteBatch.Begin(...) or SpriteBatch.End(...) while renderer.Draw() is executing, as it already handles both calls internally.

StepTask

StepTask is a kind of coroutine. It helps with organizing independent running methods: interpolations, delays, etc.

IEnumerator MyCoroutine() 
{ 
    yield return StepTask.Yields.WaitForSeconds(3);
}

StepTask task = StepTask.Run(MyCoroutine(3)); 

StepTask.Yields has some methods to manage your waiting time in the coroutine.

StepTask.Yields.WaitForSeconds(...) and StepTask.Yields.WaitForRealSeconds(...) depend on Exfal.Time.Delta and Exfal.Time.RealDelta, so if you're using them, Exfal.Time should be updated before

It is easily extendable by making an extension class and overriding YieldInstruction.

//classical extensions class
static class YieldInstructionExtensions 
{ 
    IEnumerator MyExtension(this YieldInstruction _) { yield return null; }
}

//then you can call it
yield return StepTask.Yields.MyExtension();

To make all your coroutines work, call StepTask.Update() in a main loop. Each update makes only one call in all coroutines straight to the next yield return. By calling StepTask.Run(...) the coroutine starts automatically, but you have full control of how and when your coroutines run and stop.

task.Start();    // starts the coroutine from the beginning
task.Break();    // finishes coroutine, no event invocation
task.Complete(); // finishes coroutine and invokes Completed event

By creating it from the constructor, you'll have to call Start() yourself.

Time

For managing time, there is Exfal.Time or just Time class. It's static. Call Time.Update(...) before any time-dependant updates.

var delta = Time.Delta;       // depends on Time.TimeScale
var rdelta = Time.RealDelta;  // doesn't depend on Time.TimeScale
var fdelta = Time.FixedDelta; // always the same. Equals 1/60 by default

Time.TimeScale = 0.5f;       // time (Time.Delta) is 2 times slower
Time.FixedDelta = 1.0f / 30; // making bigger steps, can cause less accuracy in some physics engines 

Input

Exfal has Input class which combines mouse handling and keyboard handling. It uses Exfal.Key enum, which also includes both keyboard and mouse buttons. Needs to be updated through Input.Update() to work properly.

if (Input.IsKeyDown(Key.MouseLeft))
  DoSomething(); 

//or you can use events
void HandleKey(Key k)
{
    if (k == Key.MouseLeft)
        DoSomething();
}

Input.KeyPressed += HandleKey;
Input.KeyReleased += HandleKey;

There is Input.MousePosition property. It returns position on the screen. Since cameras can have different resolution, you'll have to use renderer.ToViewportPoint and then camera.ToWorldPoint to get position based on the viewport of the camera.

Tips

Rendering module makes resolution of the application static. If you want to use this ✨ fancy ✨ rendering system but don't want to deal with static resolution, there is an easy fix:

Window.ClientSizeChanged += (obj, args) =>
{
    renderer.Surface.Size = Window.ClientBounds.Size;
    renderer.Cameras[Renderer.DefaultCameraIndex].Size = Window.ClientBounds.Size;
};

If you have multiple cameras, you'll have to update them all.


Each Camera has its own properties for drawing. You can make its background transparent which can be really useful when you have a camera used only for UI rendering.

renderer.Cameras[myUiCamera].BackgroundColor = Color.Transparent; 

When Graphics.Viewport changes, Renderer automatically adjusts output using specific scaling function. You can make and use your own one! This could be done the same way as mentioned in YieldInstruction overriding.

static class RectScalerExtensions
{
    public static Rectangle MyScale(this RectScaler _, in Point source, in Rectangle target)
    {
        //do some calculations here
    }
}

//set it
renderer.ScaleFunc = Renderer.OutputScaler.MyScale;

Exfal has LOTS of extensions. The most detailed ones are extensions for Vector2.

//they are all returning values and DO NOT change the vector

v.Floored();               // Math.Floor(...) on both
v.Ceiled();                // Math.Ceiling(...) on both

v.Abs();                   // Math.Abs(...) on both
v.AbsX();                  // Math.Abs(...) on X
v.AbsY();                  // Math.Abs(...) on Y
v.Truncated();             // (int) on both
v.Rounded(digits: 0);      // MathF.Round(...) on both

v.TakeX();                 // set v.Y to 0 
v.TakeY();                 // set v.X to 0

v.WithX(123);             // set X to 123
v.WithY(123);             // set Y to 123
v.WithX(x => x + 123);    // add 123 to X
v.WithY(y => y + 123);    // add 123 to Y

v.Min();                   // minimum value between X and Y
v.Max();                   // maximum value between X and Y

v.Perpendicular();         // set X to Y and Y to -X

v.Normalized();            // vector in range of 1
v.Clamped(0, 123);         // limit X and Y between 0 and 123

v.Dot(v2)                  // dot product
v.Cross(v2);               // cross product
v.DistanceTo(v2);          // distance between vectors
v.RotatedAround(v2, r);    // rotated around v2 by r radians

// supported operators: >, >=, <, <=, ==, !=
bool anyAxisLess = vec.Any() < 123; //X < 123 || Y < 123 

// also supports +, -, *, /
bool bothAxesEqual = v.Both() == 123; // X == 123 && Y == 123
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.0.0 127 7/14/2026
5.2.0 111 7/13/2026