private void MovementPrediction(ref PredictionOutput result, PredictionInput input) { var target = input.Unit; var cosTheta = Vector2.Dot(target.Direction2D(), input.ToUnitDirection2D()); var targetRelativePosition = target.Position2D() - input.RangeCheckFrom.ToVector2(); var targetRelativeVelocity = -Math.Sign(cosTheta) * target.Velocity2D(); var a = Vector2.Dot(targetRelativeVelocity, targetRelativeVelocity) - (float)Math.Pow(input.Speed, 2); var b = Vector2.Dot(targetRelativeVelocity, targetRelativePosition) * 2f; var c = Vector2.Dot(targetRelativePosition, targetRelativePosition); var discriminant = b * b - 4.0f * a * c; var impactTime = 2f * c / (float)(Math.Sqrt(discriminant) - b); if (float.IsNaN(impactTime)) { result.Hitchance = HitChance.OutOfRange; var speed = input.Speed - Math.Sign(cosTheta) * target.MoveSpeed; impactTime = (float)Math.Sqrt(c) / speed; } result.UnitPosition = target.Position3D() + target.Velocity3D() * impactTime; result.CastPosition = target.Position3D() + target.Velocity3D() * impactTime; }