alca259/monogame-skills

monogame-math

MonoGame math implementation guide covering Vector2/3/4, Matrix, Rectangle, collision detection, camera transforms, and MathHelper utilities.

Vedi sorgente
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

MonoGame Math Implementation Guide

This skill covers math types and patterns in MonoGame. For bounding volume details, see references/math.md.

Vectors

Vector2, Vector3, and Vector4 are value types (structs). Do not allocate them with new inside Update() or Draw() — mutate fields instead.

csharp
// BAD — allocates every frame:
_velocity = new Vector2(_velocity.X + acceleration, _velocity.Y);

// GOOD — mutate in place:
_velocity.X += acceleration;

Common Vector2 operations

csharp
Vector2 a, b;

float length    = a.Length();                          // expensive (sqrt)
float lengthSq  = a.LengthSquared();                  // cheap — use for distance comparisons
float distance  = Vector2.Distance(a, b);              // expensive
float distSq    = Vector2.DistanceSquared(a, b);       // cheap for "is within range X" checks
Vector2 norm    = Vector2.Normalize(a);               // unit vector (new instance)
Vector2 lerped  = Vector2.Lerp(a, b, t);              // linear interpolation, t in [0,1]
Vector2 clamped = Vector2.Clamp(a, min, max);         // per-component clamp
float   dot     = Vector2.Dot(a, b);                  // cos(angle) * |a| * |b|

Direction from angle (radians)

csharp
float angle = MathHelper.ToRadians(45f);
Vector2 dir = new Vector2(MathF.Cos(angle), MathF.Sin(angle));

Rectangle (2D AABB Collision)

Rectangle is a value type. Use it for 2D axis-aligned bounding box (AABB) collision — the most common pattern in 2D games.

csharp
Rectangle playerBounds = new Rectangle((int)_pos.X, (int)_pos.Y, 32, 32);
Rectangle wallBounds   = new Rectangle(100, 100, 64, 64);

bool collides   = playerBounds.Intersects(wallBounds);
bool contains   = wallBounds.Contains(new Point(x, y));

// Overlap area:
Rectangle.Intersect(ref playerBounds, ref wallBounds, out Rectangle overlap);

When hitboxes don't match the sprite size, define the hitbox dimensions as separate constants rather than using texture width/height directly.

Matrix (Transforms)

Matrix is a value type. Build it once per frame in Update() and cache it as a field — do not rebuild in Draw().

csharp
// Translation
Matrix t = Matrix.CreateTranslation(x, y, 0f);

// Scale
Matrix s = Matrix.CreateScale(2f, 2f, 1f);

// Rotation around Z (2D)
Matrix r = Matrix.CreateRotationZ(angleInRadians);

// Combine (order matters: scale × rotation × translation for SRT)
Matrix world = Matrix.CreateScale(scale) *
               Matrix.CreateRotationZ(rotation) *
               Matrix.CreateTranslation(position.X, position.Y, 0f);

2D Camera matrix

csharp
Matrix camera =
    Matrix.CreateTranslation(-_camPos.X, -_camPos.Y, 0f) *
    Matrix.CreateRotationZ(_camRotation) *
    Matrix.CreateScale(_camZoom, _camZoom, 1f) *
    Matrix.CreateTranslation(screenCenterX, screenCenterY, 0f);

Screen-to-world conversion

csharp
// Cache the inverse — don't recompute per call:
_inverseCamera = Matrix.Invert(_cameraMatrix);

Vector2 worldPos = Vector2.Transform(screenPos, _inverseCamera);

MathHelper Utilities

csharp
MathHelper.Clamp(value, min, max)          // clamp float
MathHelper.Lerp(value1, value2, amount)    // linear interpolation
MathHelper.SmoothStep(value1, value2, t)   // smooth S-curve interpolation
MathHelper.ToDegrees(radians)
MathHelper.ToRadians(degrees)
MathHelper.WrapAngle(angle)                // wrap to [-π, π]
MathHelper.Pi                             // 3.14159...
MathHelper.TwoPi                          // 6.28318...
MathHelper.PiOver2                        // π/2

Distance Checks — Fast vs Exact

For "is the enemy within X units?" comparisons, always use `DistanceSquared`:

csharp
float rangeSquared = detectionRange * detectionRange;
if (Vector2.DistanceSquared(enemyPos, playerPos) <= rangeSquared)
    Chase();

Only call Vector2.Distance() (which uses sqrt) when you need the actual distance value (e.g., for UI display or audio attenuation).

Bounding Volumes (3D)

Choosing a volume

TypeProsConsBest for
BoundingSphereFastest test (distance vs radii sum). Rotation-independent — no rebuild needed.False positives on long/narrow objects.Rough first-pass culling, bullets, explosions
BoundingBoxTight fit on axis-aligned rectangles. Fast axis-aligned test.Must rebuild on rotation. Worst fit at 45°.Level tiles, non-rotating objects
BoundingFrustumMatches exactly what the camera sees.Expensive to construct — rebuild only on camera move.Visibility culling, skipping off-screen draw calls
RayNo volume — a directed line from a point.Not for volume-vs-volume tests.Mouse picking, raycasting, line-of-sight
PlaneSplits space into front/back.Returns relative position, not contact point.Portal/sector visibility, reflection planes

BoundingSphere and BoundingBox

csharp
var sphere1 = new BoundingSphere(center1, radius1);
var sphere2 = new BoundingSphere(center2, radius2);
bool hit = sphere1.Intersects(sphere2);  // true / false

// ContainmentType: Contains, Intersects, or Disjoint
ContainmentType ct = sphere1.Contains(sphere2);

// Ray against sphere — returns distance or null:
float? dist = ray.Intersects(sphere1);
if (dist.HasValue)
    Vector3 hitPoint = ray.Position + ray.Direction * dist.Value;

// BoundingBox from a set of points (e.g., model vertices):
var box = BoundingBox.CreateFromPoints(vertices);
bool hit = box1.Intersects(box2);

BoundingFrustum — visibility culling

Rebuild whenever the camera view or projection changes. Skip drawing anything that is Disjoint:

csharp
// Rebuild (expensive — once per frame when camera moves):
_frustum = new BoundingFrustum(_camera.View * _camera.Projection);

// Cull in Draw():
foreach (var entity in _entities)
{
    if (_frustum.Contains(entity.BoundingSphere) != ContainmentType.Disjoint)
        entity.Draw(_spriteBatch);
}

Model bounding volumes

The Content Pipeline automatically calculates a BoundingSphere for each ModelMesh. Use it for model-model collision without manual vertex iteration:

csharp
// Check all mesh spheres of two models:
bool ModelsCollide(Model a, Matrix aWorld, Model b, Matrix bWorld)
{
    foreach (ModelMesh meshA in a.Meshes)
    {
        BoundingSphere sA = meshA.BoundingSphere.Transform(aWorld);
        foreach (ModelMesh meshB in b.Meshes)
        {
            BoundingSphere sB = meshB.BoundingSphere.Transform(bWorld);
            if (sA.Intersects(sB)) return true;
        }
    }
    return false;
}

Plane

csharp
// Plane defined by normal + distance from origin:
var plane = new Plane(normal, d);
// Or from three points:
var plane = new Plane(pointA, pointB, pointC);

// Returns PlaneIntersectionType: Front, Back, or Intersecting
PlaneIntersectionType side = plane.Intersects(sphere);
PlaneIntersectionType side = plane.Intersects(box);

Contains vs Intersects

  • Intersects() stops as soon as any overlap is found — faster, returns bool.
  • Contains() checks whether one object fully encloses another — returns ContainmentType (Contains, Intersects, Disjoint). Slightly slower.

Use Intersects in hot paths (per-frame collision). Use Contains when you need to know if an entity is fully inside a zone (e.g., trigger volumes, frustum culling with LOD).

Curve — Value Interpolation Over Time

Curve maps a float input (time) to a float output (value) via Hermite spline. Use it for easing, non-linear property animation, or any value that needs to change over time without hardcoding every frame.

csharp
var curve = new Curve();
curve.Keys.Add(new CurveKey(0f,   0f));   // at t=0, value=0
curve.Keys.Add(new CurveKey(0.5f, 1f));   // at t=0.5, value=1
curve.Keys.Add(new CurveKey(1f,   0f));   // at t=1, value=0

// Smooth tangents automatically (call after adding all keys):
curve.ComputeTangents(CurveTangent.Smooth);

// Evaluate at any time:
float value = curve.Evaluate(t);  // t can be outside [0,1] — controlled by loop type

Control what happens outside the defined range with PreLoop / PostLoop:

csharp
curve.PreLoop  = CurveLoopType.Constant;    // hold first/last value
curve.PostLoop = CurveLoopType.Cycle;       // repeat
curve.PostLoop = CurveLoopType.Oscillate;   // ping-pong
curve.PostLoop = CurveLoopType.Linear;      // extrapolate linearly
curve.PostLoop = CurveLoopType.CycleOffset; // repeat, accumulating the total delta

Step (discontinuous) transitions:

csharp
// Use CurveContinuity.Step to snap instead of interpolate between two keys:
curve.Keys.Add(new CurveKey(0.5f, 1f, 0f, 0f, CurveContinuity.Step));

Typical patterns:

csharp
// Ease-in / ease-out for a move animation (0→1 over duration):
float _elapsed;
float _duration = 0.4f;

float Progress => MathHelper.Clamp(_elapsed / _duration, 0f, 1f);
float EasedPos  => _easeCurve.Evaluate(Progress);

// Camera shake intensity that decays over 0.3 s:
// Keys: (0, 1), (0.3, 0)  →  ComputeTangents(CurveTangent.Smooth)
float shakeAmount = _shakeCurve.Evaluate(_shakeTimer);

Curve only interpolates scalars. For Vector2/Vector3 paths, use one Curve per component (X and Y separately).

Rules

  • Use DistanceSquared for range/proximity checks — avoid sqrt in hot paths.
  • Never write new Vector2(...) inside Update() or Draw() — mutate fields or use static helpers.
  • Cache Matrix.Invert(camera) as a field, not recomputed per frame.
  • Rectangle intersection gives you an overlap region — use it to resolve push-out collision response.
  • 2D rotations use float in radians; Quaternion is only for 3D.
dallo stesso repository

Altri Skills

Tutti gli Skills
alca259
Community

monogame-audio

MonoGame audio implementation guide covering SoundEffect vs Song, SoundEffectInstance pooling, volume/pitch control, 3D audio, DynamicSoundEffectInstance, WAV streaming via TitleContainer, microphone recording, and memory management rules. Use this skill whenever the user asks about playing sounds, background music, audio effects, looping audio, 3D positional sound, sound pools, microphone input, recording audio, raw WAV loading, InstancePlayLimitException, or any audio-related implementation in

installazioni
2
GitHub Stars
2
Aggiornato
22 set
alca259
Community

monogame-camera-modes

MonoGame 3D camera mode patterns — Fixed, Fixed Tracking, First Person, Third Person (with spring), Top-Down Fixed, and Top-Down Tracked. Use this skill whenever the user asks about camera modes, first person camera, third person camera, top-down camera, tracking camera, camera spring, follow camera, or how to implement a specific camera behaviour in a 3D game — even if they just say "I want the camera to follow the player" or "how do I make a first person / third person / top-down view".

installazioni
2
GitHub Stars
2
Aggiornato
22 set
alca259
Community

monogame-ecs

MonoGame component system (ECS) guide using GameBehaviour / GameEntity / GameWorld. Use this skill whenever the user mentions entities, components, behaviours, game objects, spawning/destroying actors, querying entities by type or interface, or asks how to structure game logic in MonoGame without deep class inheritance.

installazioni
2
GitHub Stars
2
Aggiornato
22 set
alca259
Community

monogame-effects

MonoGame custom effects guide covering MGFX runtime, stock effects (BasicEffect, SpriteEffect, etc.), cross-platform shader compilation (HLSL vs GLSL), shader model targets, preprocessor symbols, and portability pitfalls. Use this skill whenever the user asks about custom effects, MGFX, stock effects, cross-platform shaders, shader model compatibility, porting a shader to MonoGame, preprocessor conditionals in .fx files, or gets compilation errors with shaders — even if they just say "my shader

installazioni
2
GitHub Stars
2
Aggiornato
22 set