KeenEyes.Common
Common components and utilities shared across KeenEyes ECS plugins.
Installation
Add a reference to KeenEyes.Common:
<PackageReference Include="KeenEyes.Common" />
Float Extensions
Extension methods for safe floating-point comparisons. Direct equality checks (==) with floats are unreliable due to precision limitations.
Usage
using KeenEyes.Common;
// Check if a value is approximately zero
float threshold = 0.0000001f;
if (threshold.IsApproximatelyZero())
{
// Treat as zero
}
// Compare two floats for near-equality
float a = 1.0f;
float b = 1.0000001f;
if (a.ApproximatelyEquals(b))
{
// Values are considered equal
}
Methods
| Method | Description |
|---|---|
IsApproximatelyZero() |
Returns true if the absolute value is less than the default epsilon (1e-6f) |
IsApproximatelyZero(float epsilon) |
Returns true if the absolute value is less than the specified epsilon |
ApproximatelyEquals(float other) |
Returns true if the absolute difference is less than the default epsilon |
ApproximatelyEquals(float other, float epsilon) |
Returns true if the absolute difference is less than the specified epsilon |
Default Epsilon
The default epsilon value is 1e-6f (0.000001), which is suitable for most game development scenarios. Access it via:
float epsilon = FloatExtensions.DefaultEpsilon; // 1e-6f
Custom Epsilon
For scenarios requiring different precision, use the overloads that accept a custom epsilon:
// Physics simulation might need tighter tolerance
const float PhysicsEpsilon = 1e-9f;
if (velocity.IsApproximatelyZero(PhysicsEpsilon))
{
// Consider at rest
}
// UI positioning might allow looser tolerance
const float UiEpsilon = 0.01f;
if (positionA.ApproximatelyEquals(positionB, UiEpsilon))
{
// Close enough for UI purposes
}
Common Patterns
Checking thresholds:
// ❌ BAD: Direct comparison
if (activity.SleepThreshold == 0)
// ✅ GOOD: Tolerance-based
if (activity.SleepThreshold.IsApproximatelyZero())
Comparing calculated values:
// ❌ BAD: May fail due to floating-point errors
float calculated = ComputeValue();
if (calculated == expectedValue)
// ✅ GOOD: Handles floating-point imprecision
if (calculated.ApproximatelyEquals(expectedValue))
Physics systems:
public class MovementSystem : SystemBase
{
public override void Update(float deltaTime)
{
foreach (var entity in World.Query<Position, Velocity>())
{
ref var velocity = ref World.Get<Velocity>(entity);
// Check if effectively stopped
if (velocity.Value.Length().IsApproximatelyZero())
{
// Entity is at rest
continue;
}
ref var position = ref World.Get<Position>(entity);
position.Value += velocity.Value * deltaTime;
}
}
}
Edge Cases
The extension methods handle edge cases gracefully:
| Input | IsApproximatelyZero() |
Notes |
|---|---|---|
0f |
true |
Exact zero |
1e-7f |
true |
Below default epsilon |
1e-6f |
false |
At epsilon boundary (exclusive) |
float.NaN |
false |
NaN comparisons return false |
float.PositiveInfinity |
false |
Infinity is never zero |
Transform Components
See Spatial for 2D and 3D transform components.
Velocity Components
Velocity2D
using KeenEyes.Common;
var velocity = new Velocity2D(10f, 5f);
// Get speed (magnitude)
float speed = velocity.Magnitude();
// Get squared magnitude (avoids sqrt, good for comparisons)
float speedSquared = velocity.MagnitudeSquared();
Velocity3D
using KeenEyes.Common;
var velocity = new Velocity3D(10f, 5f, 3f);
float speed = velocity.Magnitude();
float speedSquared = velocity.MagnitudeSquared();
Spatial Bounds
using KeenEyes.Common;
var bounds = new SpatialBounds
{
Min = new Vector3(-5, -5, -5),
Max = new Vector3(5, 5, 5)
};
// Check containment, intersection, etc.
See Spatial and Spatial Partitioning for more details.