CI / build-test (push) Failing after 1m8s
Add MrGameEng.AI utility-AI module; format codebase with CSharpier New MrGameEng.AI module (ResponseCurve, Consideration, UtilityAction, UtilityAi selector, Blackboard) plus CSharpier formatting applied across the whole engine. Documents the CSharpier convention in CLAUDE.md. @
92 lines
2.9 KiB
C#
92 lines
2.9 KiB
C#
using Microsoft.Xna.Framework;
|
|
using MrGameEng.Graphics;
|
|
using Xunit;
|
|
|
|
namespace MrGameEng.Graphics.Tests;
|
|
|
|
public class CullingTests
|
|
{
|
|
[Fact]
|
|
public void BoundingCircle_UnrotatedTopLeftOrigin_CenterIsRegionCenter()
|
|
{
|
|
var transform = Transform2D.At(new Vector2(100f, 200f));
|
|
|
|
var (center, radius) = CullingMath.SpriteBoundingCircle(transform, 32f, 32f, Vector2.Zero);
|
|
|
|
Assert.Equal(new Vector2(116f, 216f), center);
|
|
Assert.Equal(0.5f * MathF.Sqrt(32f * 32f * 2f), radius, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void BoundingCircle_CenterOrigin_CenterIsPosition()
|
|
{
|
|
var transform = Transform2D.At(new Vector2(50f, 50f));
|
|
|
|
var (center, _) = CullingMath.SpriteBoundingCircle(
|
|
transform,
|
|
64f,
|
|
32f,
|
|
new Vector2(32f, 16f)
|
|
);
|
|
|
|
Assert.Equal(new Vector2(50f, 50f), center);
|
|
}
|
|
|
|
[Fact]
|
|
public void BoundingCircle_Scale_GrowsRadius()
|
|
{
|
|
var transform = new Transform2D(Vector2.Zero, scale: new Vector2(2f, 2f));
|
|
|
|
var (_, radius) = CullingMath.SpriteBoundingCircle(transform, 10f, 10f, Vector2.Zero);
|
|
|
|
Assert.Equal(0.5f * MathF.Sqrt(800f), radius, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void BoundingCircle_RegionOverload_MatchesSizeOverload_ForUniformScale()
|
|
{
|
|
var region = new Texture2DRegion(null!, new Rectangle(0, 0, 48, 24));
|
|
var transform = new Transform2D(
|
|
new Vector2(10f, 20f),
|
|
rotation: 0.6f,
|
|
scale: new Vector2(1.5f, 1.5f)
|
|
);
|
|
var origin = new Vector2(5f, 7f);
|
|
|
|
var (centerA, radiusA) = CullingMath.SpriteBoundingCircle(transform, 48f, 24f, origin);
|
|
var (centerB, radiusB) = CullingMath.SpriteBoundingCircle(in transform, region, origin);
|
|
|
|
Assert.Equal(centerA.X, centerB.X, 3);
|
|
Assert.Equal(centerA.Y, centerB.Y, 3);
|
|
Assert.Equal(radiusA, radiusB, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void BoundingCircle_RegionOverload_IsConservative_ForNonUniformScale()
|
|
{
|
|
var region = new Texture2DRegion(null!, new Rectangle(0, 0, 100, 10));
|
|
var transform = new Transform2D(Vector2.Zero, scale: new Vector2(1f, 3f));
|
|
|
|
var (_, exact) = CullingMath.SpriteBoundingCircle(transform, 100f, 10f, Vector2.Zero);
|
|
var (_, conservative) = CullingMath.SpriteBoundingCircle(
|
|
in transform,
|
|
region,
|
|
Vector2.Zero
|
|
);
|
|
|
|
Assert.True(conservative >= exact);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(50f, 50f, true)] // inside
|
|
[InlineData(-4f, 50f, true)] // touching from the left (radius 5)
|
|
[InlineData(-20f, 50f, false)] // far left
|
|
[InlineData(50f, 130f, false)] // far below
|
|
public void CircleIntersectsRect_DetectsOverlap(float x, float y, bool expected)
|
|
{
|
|
var rect = new RectF(0f, 0f, 100f, 100f);
|
|
|
|
Assert.Equal(expected, CullingMath.CircleIntersectsRect(new Vector2(x, y), 5f, rect));
|
|
}
|
|
}
|