Here's how I would do it. First, find the interval in time during which the X-coordinates of the two boxes overlap. You can do this by solving two linear equations in t, representing the times when the X-coordinates are just touching:
- Minimum X of entity 1 at time t = Maximum X of entity 2 at time t
- Maximum X of entity 1 at time t = Minimum X of entity 2 at time t
Let me know if you want help setting that part up!
Now, solve the same problem for the Y-coordinates. If the interval for Y doesn't intersect the interval for X, the boxes don't collide. If the intervals do intersect, take the intersection and keep going.
Solve the problem for the Z-coordinates to get another interval. If the interval for Z doesn't intersect the interval for X and Y, the boxes don't collide. If the intervals do intersect, take the intersection.
Now you have an interval in time [t1, t2] that represents all points in time when all three coordinates of the boxes overlap -- in other words, all points in time when the boxes overlap! So t1 is the point in time when they collide.
(Another approach would be to replace the hitboxes with ellipsoids and solve a quadratic equation like in the other StackOverflow thread. However, the math is actually harder in that case. Using axis-aligned boxes means you can break down the problem into each coordinate independently and stick to linear equations.)
Edit: By request, here's how to set up the linear equations.
struct Entity
{
float x1; // Minimum value of X
float x2; // Maximum value of X
float vx; // Velocity in X
// etc.
};
Entity entity1;
Entity entity2;
// Find the interval during which the X-coordinates overlap...
// TODO: Handle the case Entity1.vx == Entity2.vx!!!
// Solve for Entity1.x1 + t * Entity1.vx = Entity2.x2 + t * Entity2.vx
// t * Entity1.vx - t * Entity2.vx = Entity2.x2 - Entity1.x1
// t * (Entity1.vx - Entity2.vx) = Entity2.x2 - Entity1.x1
float timeXa = (Entity2.x2 - Entity1.x1) / (Entity1.vx - Entity2.vx);
// And the other side...
// Entity1.x2 + t * Entity1.vx = Entity2.x1 + t * Entity2.vx
// t * Entity1.vx - t * Entity2.vx = Entity2.x1 - Entity1.x2
// t * (Entity1.vx - Entity2.vx) = Entity2.x1 - Entity1.x2
float timeXb = (Entity2.x1 - Entity1.x2) / (Entity1.vx - Entity2.vx);
float timeXMin = std::min(timeXa, timeXb);
float timeXMax = std::max(timeXa, timeXb);
Then do the same thing for Y and Z, and intersect the time intervals. Note that I may have made some silly sign errors, and I didn't handle the equal-velocity case, which can cause a division by zero. You'll want to throw some quick unit tests at the final code to make sure that it gives reasonable results.