Thunder.UnitsNET.Vectors.MonoGame
0.4.0
See the version list below for details.
dotnet add package Thunder.UnitsNET.Vectors.MonoGame --version 0.4.0
NuGet\Install-Package Thunder.UnitsNET.Vectors.MonoGame -Version 0.4.0
<PackageReference Include="Thunder.UnitsNET.Vectors.MonoGame" Version="0.4.0" />
<PackageVersion Include="Thunder.UnitsNET.Vectors.MonoGame" Version="0.4.0" />
<PackageReference Include="Thunder.UnitsNET.Vectors.MonoGame" />
paket add Thunder.UnitsNET.Vectors.MonoGame --version 0.4.0
#r "nuget: Thunder.UnitsNET.Vectors.MonoGame, 0.4.0"
#:package Thunder.UnitsNET.Vectors.MonoGame@0.4.0
#addin nuget:?package=Thunder.UnitsNET.Vectors.MonoGame&version=0.4.0
#tool nuget:?package=Thunder.UnitsNET.Vectors.MonoGame&version=0.4.0
Thunder.UnitsNET.Vectors.MonoGame
MonoGame / XNA integration for Thunder.UnitsNET.Vectors.
Provides a Camera2 type for world-to-screen projection and extension methods to convert unit-aware LengthVector2/LengthVector3 (and their derived types) to and from XNA Vector2/Vector3. Scaling is expressed as a PixelScale — a typed value that bundles the pixels-per-unit ratio and the world unit together, so the scale is always self-consistent and zoom is a first-class operation.
Supported frameworks: net8.0, net10.0
Quick start
// dotnet add package Thunder.UnitsNET.Vectors
// dotnet add package Thunder.UnitsNET.Vectors.MonoGame
using Thunder.UnitsNET.Vectors;
using Thunder.UnitsNET.Vectors.MonoGame;
using UnitsNet.Units;
using Microsoft.Xna.Framework;
// Physics world position (e.g. from your physics update)
var worldPos = new LengthVector2(
Length.FromMeters(1.5),
Length.FromMeters(-2.0));
// Convert to screen pixels (64 px per metre)
const double ppm = 64.0;
Vector2 screen = worldPos.ToXnaVector2(LengthUnit.Meter, ppm);
// Convert back (e.g. mouse pick ray → world coords)
LengthVector2 picked = screen.ToLengthVector2(LengthUnit.Meter, ppm);
Camera2 — world-to-screen projection
Camera2 captures a camera's world position, zoom level, and Y-axis convention. Pass it once to WorldToScreen for every entity in the render loop:
using Thunder.UnitsNET.Vectors;
using Thunder.UnitsNET.Vectors.MonoGame;
using Microsoft.Xna.Framework;
// Camera centred on the player, 32 pixels per metre, Y-down (MonoGame default)
var camera = new Camera2(
Position: player.Position,
Scale: PixelScale.PerMeter(32)); // YAxisMode.YDown is the default
var screenSize = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
// Render all entities
foreach (var entity in entities)
{
Vector2 screenPos = camera.WorldToScreen(entity.Position, screenSize);
spriteBatch.Draw(entity.Texture, screenPos, Color.White);
}
// Mouse picking — convert cursor position back to world space
LengthVector2 worldMouse = camera.ScreenToWorld(mouseState.Position.ToVector2(), screenSize);
bool clicked = triggerZone.Contains(worldMouse);
// Scale a world length to pixels (e.g. circle radius for debug draw)
Single pixelRadius = camera.WorldToScreenScale(circle.Radius);
Zoom
Changing the PixelScale is how zoom works — more pixels per world unit means the world appears larger on screen. ZoomBy returns a new Camera2 with the scale multiplied:
// Snap zoom
camera = camera.ZoomBy(2.0); // zoom in 2×
camera = camera.ZoomBy(0.5); // zoom out to half
// Incremental zoom — call each frame while a button is held
camera = camera.ZoomBy(1.05); // +5% per frame
// Non-metre world — two pixels per centimetre
var scale = Length.FromCentimeters(1).ToPixels(2);
var camera = new Camera2(Position: player.Position, Scale: scale);
Smooth zoom
PixelScale.Lerp linearly interpolates between two zoom levels. Calling it every frame with a small t produces smooth, asymptotic zoom — fast at first, slowing as the scale approaches the target:
// State held across frames
PixelScale _currentScale = PixelScale.PerMeter(32);
PixelScale _targetScale = PixelScale.PerMeter(32);
// In your Update loop
void Update(GameTime gameTime)
{
if (scrollUp) _targetScale = _targetScale.ZoomBy(1.1);
if (scrollDown) _targetScale = _targetScale.ZoomBy(0.9);
// smoothSpeed controls how quickly the zoom settles (game-specific tuning)
Double t = gameTime.ElapsedGameTime.TotalSeconds * smoothSpeed;
_currentScale = PixelScale.Lerp(_currentScale, _targetScale, t);
camera = new Camera2(Position: player.Position, Scale: _currentScale);
}
Lerp at t = 0 returns the start scale; t = 1 returns the target; values in between give a proportional blend. The game owns smoothSpeed and _targetScale — the library provides the interpolation math.
Y-axis convention
MonoGame screen space has Y increasing downward. Physics / world space conventionally has Y increasing upward. Camera2 flips Y by default (YAxisMode.YDown). For non-standard setups, pass YAxis: YAxisMode.YUp to the constructor.
Round-trip precision
ScreenToWorld(WorldToScreen(p, size), size) ≈ p within ~1e-5 m. The precision limit comes from float32 screen coordinates; it is more than sufficient for any rendering use case.
Conversion API
2D extensions (XnaVector2Extensions)
| Method | From | To | Notes |
|---|---|---|---|
ToXnaVector2(unit, scale) |
LengthVector2 |
Vector2 |
Components converted to unit, multiplied by scale |
ToXnaVector2(unit, scale) |
DoubleVector2 |
Vector2 |
Direction-only; scale applied |
ToLengthVector2(unit, scale) |
Vector2 |
LengthVector2 |
XNA pixels divided by scale, wrapped in unit |
ToDoubleVector2() |
Vector2 |
DoubleVector2 |
Raw cast; no scaling |
3D extensions (XnaVector3Extensions)
| Method | From | To | Notes |
|---|---|---|---|
ToXnaVector3(unit, scale) |
LengthVector3 |
Vector3 |
Same semantics as 2D |
ToXnaVector3(unit, scale) |
DoubleVector3 |
Vector3 |
|
ToLengthVector3(unit, scale) |
Vector3 |
LengthVector3 |
|
ToDoubleVector3() |
Vector3 |
DoubleVector3 |
Scale-aware overloads
All ToXna* overloads accept an optional scale parameter (default 1.0). Pass your pixels-per-unit constant at the call site rather than storing it as a global, so the conversion intent is explicit in code.
MonoGame dependency note
MonoGame.Framework.DesktopGL is declared as PrivateAssets="all" in this package. You must add your own platform-specific MonoGame package to your game project (e.g. MonoGame.Framework.DesktopGL, MonoGame.Framework.WindowsDX). This package works with any MonoGame platform.
Packages in this family
| 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 is compatible. 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. |
-
net10.0
- Thunder.UnitsNET.Vectors (>= 0.4.0)
- UnitsNet (>= 5.67.0)
-
net8.0
- Thunder.UnitsNET.Vectors (>= 0.4.0)
- UnitsNet (>= 5.67.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Thunder.UnitsNET.Vectors.MonoGame:
| Package | Downloads |
|---|---|
|
Thunder.UnitsNET.Vectors.Geometry.MonoGame
MonoGame/XNA integration for Thunder.UnitsNET.Vectors.Geometry. Converts unit-aware 2D geometry shapes to XNA rendering primitives with explicit scale, keeping physics and rendering units separate. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.0 | 116 | 5/5/2026 |
| 0.7.0-preview37 | 92 | 5/5/2026 |
| 0.7.0-preview36 | 99 | 5/5/2026 |
| 0.7.0-preview35 | 109 | 5/4/2026 |
| 0.6.0-preview34 | 114 | 4/28/2026 |
| 0.6.0-preview33 | 119 | 4/27/2026 |
| 0.6.0-preview32 | 110 | 4/27/2026 |
| 0.5.0 | 122 | 4/23/2026 |
| 0.5.0-preview31 | 110 | 4/28/2026 |
| 0.5.0-preview30 | 129 | 4/28/2026 |
| 0.5.0-preview29 | 111 | 4/28/2026 |
| 0.5.0-preview28 | 108 | 4/28/2026 |
| 0.5.0-preview27 | 119 | 4/28/2026 |
| 0.4.0 | 132 | 4/22/2026 |
| 0.4.0-preview6 | 114 | 4/20/2026 |
| 0.4.0-preview5 | 106 | 4/20/2026 |
| 0.4.0-preview4 | 107 | 4/20/2026 |
| 0.4.0-preview25 | 109 | 4/20/2026 |
| 0.4.0-preview24 | 103 | 4/20/2026 |
| 0.4.0-preview23.1 | 53 | 4/20/2026 |