Eurekiel: Math Playground is a collection of interactive math and geometry visual tests built on a custom C++ engine. I created this project to implement and validate core game math concepts through real-time visualization, covering 2D parametric curves, fixed timestep physics simulation, 3D raycasting against multiple primitive shapes, and a full convex polygon scene editor with spatial partitioning optimization. Each module runs as a standalone test scene with live parameter tweaking and visual debugging through a custom ImGui tooling layer.
Module Architecture
graph TD
subgraph App["App (Game Mode Manager)"]
GM[EGameMode Selector]
end
subgraph Modules["8 Visual Test Modules"]
C2D[Game2DCurves]
PM[Game2DPachinkoMachine]
NP[GameNearestPoint]
RD[GameRaycastVsDiscs]
RLS[GameRaycastVsLineSegments]
RA[GameRaycastVsAABBs]
R3D[GameRaycastVsShapes3D]
RP[GameRaycastVsPlane3D]
end
subgraph Common["Shared Components"]
E[Entity Base]
P[Prop: 3D Shape Container]
P3D[Test3DShapePlayer]
end
subgraph Engine["Custom C++ Engine"]
Math[Math Library]
Render[Renderer]
Input[Input System]
Debug[Debug Render System]
end
GM --> Modules
Modules --> Common
Common --> Engine
2D Curves: Bezier, Hermite, and Easing Functions
I implemented a full 2D parametric curve system supporting cubic Bezier curves, cubic Hermite splines, and over a dozen easing functions (quadratic through 6th order, SmoothStep, SmootherStep, Hesitate variants). Each curve type renders in real time with configurable subdivision counts, and the control points are interactively draggable for immediate visual feedback.
This module exercises core skills in parametric math evaluation, vertex buffer generation from mathematical functions, and building intuitive debug visualization for curve editing.
2D Pachinko Machine with Fixed Timestep Physics
I built a 2D Pachinko machine simulation with a deterministic fixed timestep physics loop. The core update runs at a fixed 5ms tick rate, accumulating frame delta time and stepping physics in uniform increments to guarantee consistent collision behavior regardless of frame rate.
The physics pipeline handles ball to ball elastic collisions using velocity decomposition into normal and tangential components, ball to bumper collisions against multiple shape types (Disc2, Capsule2, OBB2), and wall bounce with configurable elasticity coefficients. Collision detection uses distance squared comparisons to avoid unnecessary square root operations.
Raycast vs 3D Shapes
I implemented raycast intersection tests against five 3D primitive types: Sphere, AABB3, OBB3, ZCylinder, and Plane3. Each shape is wrapped in a Prop entity that holds the geometry data and a prebuilt vertex buffer for rendering. The ray is cast from a first person camera, and the system iterates all props to find the nearest intersection point, rendering impact position and surface normal at the hit location.
The raycast pipeline returns a RaycastResult3D containing impact position, surface normal, and distance, enabling accurate visual feedback for debugging and validation.
Raycast Optimization and Nearest Point Queries
I applied several optimization strategies to the raycast system. The primary technique is a nearest hit first traversal that tracks the closest intersection distance across all tested shapes, allowing early rejection of farther candidates. Distance comparisons use squared magnitude (GetDistanceSquared) to eliminate square root calls in the hot path. For the 3D test scene, a ray lock mode freezes the ray direction so the user can orbit the camera to inspect hit points and normals from any angle.
The nearest point module computes closest points on 2D shapes (discs, line segments, capsules, AABBs, OBBs, triangles) from an arbitrary query point, providing a visual testbed for proximity queries commonly used in collision response and AI navigation.
Convex Polygon Scene Editor
I built a 2D convex polygon scene editor that supports interactive creation, manipulation, and raycast testing of N convex polygons in a shared scene. Each polygon is stored in polar coordinate form (vertex angles relative to center plus a shared base radius), which guarantees convexity by construction. The editor supports two draw modes toggled with F2: a translucent fill mode where overlapping regions form compound concave silhouettes, and an opaque fill mode with layered rendering.
The scene provides full interactive control. Users can drag objects with the mouse, rotate and scale around the cursor position, and dynamically double or halve the object count at runtime. A visible ray is always rendered in the scene, and pressing T triggers a batch raycast test of configurable size (default 1024 rays) with millisecond timing output for performance benchmarking.
Single Object Debug Mode
When the scene contains only one polygon, the editor activates a detailed debug visualization. It renders the convex hull face planes as extended lines color coded by normal direction (red for upward facing, green for downward, gray for horizontal). The ray intersection analysis shows all plane entry and exit points, the penetration segment through the polygon interior, and the final closest hit point with surface normal arrow.
This mode exercises the full raycast math pipeline in an isolated, inspectable environment, making it straightforward to validate the correctness of plane intersection calculations and normal computation.
Bit Region Spatial Partitioning
To optimize batch raycasting against large polygon counts, I implemented three spatial partitioning strategies behind a common ISpatialPartition interface: brute force baseline, bit region grid, and BVH tree.
The bit region approach divides the world into an M x N grid (up to 32 cells, fitting in a single uint32_t). Each polygon’s bounding disc is mapped to a bitmask indicating which cells it occupies. During raycast, a FastVoxel traversal algorithm walks the ray through the grid and produces a bitmask of visited cells. A bitwise AND between the ray mask and each polygon mask quickly filters candidates, eliminating most polygons without any geometric intersection test.
The BVH implementation recursively splits objects along the longest axis into a binary tree with configurable leaf capacity. Ray queries traverse only nodes whose AABB intersects the ray, pruning large subtrees early.
Both strategies combine with a bounding disc early out that rejects polygons whose enclosing circle does not intersect the ray, adding another layer of culling before the expensive convex hull intersection test.
flowchart TD
A[Batch Raycast Request] --> B{Spatial Partition Type}
B -->|None| C[Test All Polygons]
B -->|Bit Regions| D[FastVoxel Ray Traversal]
B -->|BVH| E[Recursive AABB Query]
D --> F[Bitmask AND Filter]
F --> G[Candidate Polygons]
E --> G
C --> G
G --> H{Bounding Disc Early Out?}
H -->|Miss| I[Skip]
H -->|Hit| J[Convex Hull Raycast]
J --> K[Track Nearest Hit]
ImGui Debug Editor
I built a comprehensive ImGui control panel on top of the engine’s ImGui subsystem, providing real-time parameter editing and debug visualization for the entire convex scene system. The editor is organized into five tabbed sections: Scene (object count, random seed, transform speeds), Colors (fill, edge, hover, and drag state colors), Raycast (batch test configuration and optimization strategy selection), Debug (visualization toggles for bounding discs, spatial partitions, and face planes), and Controls (keyboard binding reference).
A persistent left side debug overlay displays live metrics including object count, ray count, current draw mode, active spatial partition type, optimization flags, last batch test timing with hit rate, FPS, and mouse world coordinates. The overlay uses a semi-transparent background and auto-sizes to content.
Dedicated optimization sub-panels expose tuning parameters for each spatial partition type. The BitRegions panel allows adjusting grid dimensions and FastVoxel step size. The BVH panel shows tree depth, node count, and lets users configure the maximum leaf object capacity. All changes take effect immediately, enabling rapid A/B comparison of optimization strategies during batch testing.
Design Philosophy
Modular Test Scenes — Each math concept lives in its own self contained module with a dedicated game class, making it trivial to add new visual tests without touching existing code. The EGameMode enum and factory pattern in App::CreateGame() keep module registration clean and extensible.
Fixed Timestep Determinism — The Pachinko simulation deliberately separates rendering from physics by accumulating frame time and consuming it in fixed increments. This guarantees reproducible collision behavior across different hardware and frame rates, a fundamental technique for any physics dependent gameplay.
Strategy Pattern for Optimization — The spatial partitioning system uses a common ISpatialPartition interface with swappable implementations (None, BitRegions, BVH). Users can cycle through strategies at runtime with F9 and immediately compare batch raycast performance, turning optimization into a measurable, visual exercise rather than guesswork.
Data-Driven Scene Configuration — All scene parameters (object counts, colors, optimization settings, debug flags) are exposed through ImGui and stored in a centralized config. This keeps the core simulation code free of hardcoded values and allows rapid iteration without recompilation.
Optimization by Measurement — Rather than applying blanket optimizations, the raycast system targets the actual bottleneck: per frame intersection tests against every shape. Squared distance comparisons, bounding disc early outs, and spatial partitioning reduce unnecessary computation where it matters most, without sacrificing code clarity.
Visual Debugging as a First Class Feature — Every module renders its internal state (normals, impact points, control points, velocity vectors, spatial partition grids, bounding discs) directly in the viewport. This approach treats debug visualization not as an afterthought but as the primary interface for validating mathematical correctness.