package mindustry.entities; import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.gen.*; /** * Class for predicting shoot angles based on velocities of targets. */ public class Predict{ private static final Vec2 vec = new Vec2(); private static final Vec2 vresult = new Vec2(); /** * Calculates of intercept of a stationary and moving target. Do not call from multiple threads! * @param srcx X of shooter * @param srcy Y of shooter * @param dstx X of target * @param dsty Y of target * @param dstvx X velocity of target (subtract shooter X velocity if needed) * @param dstvy Y velocity of target (subtract shooter Y velocity if needed) * @param v speed of bullet * @return the intercept location */ public static Vec2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v){ dstvx /= Time.delta; dstvy /= Time.delta; float tx = dstx - srcx, ty = dsty - srcy; // Get quadratic equation components float a = dstvx * dstvx + dstvy * dstvy - v * v; float b = 2 * (dstvx * tx + dstvy * ty); float c = tx * tx + ty * ty; // Solve quadratic Vec2 ts = quad(a, b, c); // Find smallest positive solution Vec2 sol = vresult.set(dstx, dsty); if(ts != null){ float t0 = ts.x, t1 = ts.y; float t = Math.min(t0, t1); if(t < 0) t = Math.max(t0, t1); if(t > 0){ sol.set(dstx + dstvx * t, dsty + dstvy * t); } } return sol; } public static Vec2 intercept(Position src, Position dst, float v){ return intercept(src, dst, 0, 0, v); } public static Vec2 intercept(Position src, Position dst, float offsetx, float offsety, float v){ float ddx = 0, ddy = 0; if(dst instanceof Hitboxc h){ ddx += h.deltaX(); ddy += h.deltaY(); } if(src instanceof Hitboxc h){ ddx -= h.deltaX(); ddy -= h.deltaY(); } return intercept(src.getX(), src.getY(), dst.getX() + offsetx, dst.getY() + offsety, ddx, ddy, v); } /** * See {@link #intercept(float, float, float, float, float, float, float)}. */ public static Vec2 intercept(Hitboxc src, Hitboxc dst, float v){ return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.deltaX() - src.deltaX()/(2f* Time.delta), dst.deltaY() - src.deltaX()/(2f* Time.delta), v); } private static Vec2 quad(float a, float b, float c){ Vec2 sol = null; if(Math.abs(a) < 1e-6){ if(Math.abs(b) < 1e-6){ sol = Math.abs(c) < 1e-6 ? vec.set(0, 0) : null; }else{ vec.set(-c / b, -c / b); } }else{ float disc = b * b - 4 * a * c; if(disc >= 0){ disc = Mathf.sqrt(disc); a = 2 * a; sol = vec.set((-b - disc) / a, (-b + disc) / a); } } return sol; } }