飞行模拟开发:如何判断两机动飞行器拦截计算时无法实现拦截?
飞行模拟拦截点计算的可行性判断方案
我数学基础薄弱,仅掌握基础三角学,18个月前在他人帮助下将一套拦截计算公式改写为Lua代码,用于飞行模拟项目中实现拦截机对保持航向的目标机的拦截点计算。该代码基于FPS游戏中移动目标射击提前量计算的教程,原参考代码与我的Lua实现如下:
-- 参考的C++原型代码 -- Point intercept(Point const &shooter, double bullet_speed, Point const &target, Vector const &target_velocity) -- { -- double a = bullet_speed*bullet_speed - target_velocity.dot(target_velocity); -- double b = -2*target_velocity.dot(target-shooter); -- double c = -(target-shooter).dot(target-shooter); -- return target+largest_root_of_quadratic_equation(a,b,c)*target_velocity; -- } -- 我的Lua实现 local targetMINUSInterceptor = TVF.VecSubtract(interceptorVec3Point, targetVec3Point) local targetVelocityDotProduct = TVF.VecDot(targetVelocityAsVec3, targetVelocityAsVec3) local a = interceptorSpeedAsNumber * interceptorSpeedAsNumber - targetVelocityDotProduct local b = -2 * TVF.VecDot(targetVelocityAsVec3, targetMINUSInterceptor) local c = -TVF.VecDot(targetMINUSInterceptor, targetMINUSInterceptor) local result = TVF.VecAdd(targetVec3Point, (TVF.MultiplyVectorByNumber(targetVelocityAsVec3, TVF.GetLargestRootOfQuadraticEquation(a,b,c))))
这套代码在拦截可行的场景下运行正常,但当拦截无法实现时(例如目标机向西飞行,拦截机在目标机东侧向东飞行,且拦截机速度不足以追上),会输出无实际意义的位置向量。现在需要通过计算判断拦截是否可行,添加分支逻辑提示玩家调整目标航向或速度。
拦截可行性判断方法(通俗版)
我们的代码本质是在解「拦截所需时间t」的二次方程,只有当方程有正实数解时,拦截才是可行的:
- 先计算二次方程的判别式:
discriminant = b*b - 4*a*c - 分情况判断:
- 如果
discriminant < 0:方程没有实数解,说明无论怎么飞都追不上,拦截完全不可能 - 如果
discriminant >= 0:算出方程的两个根(也就是两个可能的拦截时间t),只有当至少有一个t是正数时,拦截才可行(取最大的那个正t用来计算拦截点) - 特殊情况:如果
a=0,说明拦截机和目标机的速度大小完全一样,这时候只有当目标机和拦截机方向完全一致,且拦截机在目标机后方(能追上的位置)时,才存在拦截点,否则也无法拦截
- 如果
修改后的Lua代码(带判断逻辑)
local targetMINUSInterceptor = TVF.VecSubtract(interceptorVec3Point, targetVec3Point) local targetVelocityDotProduct = TVF.VecDot(targetVelocityAsVec3, targetVelocityAsVec3) local a = interceptorSpeedAsNumber * interceptorSpeedAsNumber - targetVelocityDotProduct local b = -2 * TVF.VecDot(targetVelocityAsVec3, targetMINUSInterceptor) local c = -TVF.VecDot(targetMINUSInterceptor, targetMINUSInterceptor) -- 计算判别式,判断拦截可行性 local discriminant = b*b - 4*a*c local interceptPossible = false local validTime = nil if discriminant >= 0 then -- 获取二次方程的两个根 local root1, root2 = TVF.GetQuadraticRoots(a, b, c) -- 找正的根,取最大的那个(对应实际有效的拦截时间) local positiveRoots = {} if root1 > 0 then table.insert(positiveRoots, root1) end if root2 > 0 then table.insert(positiveRoots, root2) end if #positiveRoots > 0 then validTime = math.max(unpack(positiveRoots)) interceptPossible = true end end if interceptPossible then -- 计算拦截点 local result = TVF.VecAdd(targetVec3Point, TVF.MultiplyVectorByNumber(targetVelocityAsVec3, validTime)) -- 后续处理拦截点逻辑 else -- 提示玩家拦截不可行 print("拦截无法实现,请调整目标机的航向或速度重试") -- 或者执行其他提示逻辑 end
补充函数实现
需要补充二次方程求根函数,直接添加到你的TVF工具集里即可:
function TVF.GetQuadraticRoots(a, b, c) if a == 0 then -- 退化为一次方程,返回唯一解 return -c/b, -c/b end local sqrtDisc = math.sqrt(b*b - 4*a*c) local root1 = (-b + sqrtDisc)/(2*a) local root2 = (-b - sqrtDisc)/(2*a) return root1, root2 end
内容的提问来源于stack exchange,提问作者iOSProgrammingIsFun
相关产品推荐
相关产品推荐

