OpenGL相机碰撞检测:实现仅限制碰撞方向移动的解决方案求助
解决OpenGL相机碰撞仅限制碰撞方向移动的问题
核心思路是把每个轴的移动单独拆分处理,先预判移动后的位置,再根据碰撞结果决定是否应用该方向的移动,而不是碰撞后直接停止所有方向的移动。这样就能实现仅限制碰撞轴、其他方向正常通行的效果。
第一步:重构碰撞检测逻辑(新增预判位置检测函数)
我们需要一个辅助函数,用来判断相机移动到某个目标位置时是否会和AABB碰撞,而不是检测当前位置:
// 判断相机在目标位置是否与指定AABB碰撞 fun isCameraPositionColliding(targetPos: Vector3f, quad: Renderable?): Boolean { val quadPos = quad?.getPosition() ?: return false val collisionX = targetPos.x <= quadPos.x + maxX && targetPos.x >= quadPos.x + minX val collisionY = targetPos.y <= quadPos.y + maxY && targetPos.y >= quadPos.y + minY val collisionZ = targetPos.z <= quadPos.z + maxZ && targetPos.z >= quadPos.z + minZ return collisionX && collisionY && collisionZ } // 如果需要检测多个碰撞体,可用这个版本 fun isCameraPositionColliding(targetPos: Vector3f, colliders: List<Renderable>): Boolean { for (quad in colliders) { val quadPos = quad.getPosition() ?: continue val collisionX = targetPos.x <= quadPos.x + maxX && targetPos.x >= quadPos.x + minX val collisionY = targetPos.y <= quadPos.y + maxY && targetPos.y >= quadPos.y + minY val collisionZ = targetPos.z <= quadPos.z + maxZ && targetPos.z >= quadPos.z + minZ if (collisionX && collisionY && collisionZ) { return true } } return false }
第二步:修改相机移动函数,实现分轴控制
把原来的直接移动逻辑拆分成每个轴独立处理,先计算移动后的位置,检测无碰撞后再应用移动:
fun moveCamera(dt: Float, t: Float) { this.dt = t - lastFrame lastFrame = t.toFloat() val s = 2.0f val cameraSpeed = dt * s camera.parent = null // 获取相机当前位置,作为目标位置的初始值 val currentPos = camera.getPosition() var targetPos = Vector3f(currentPos.x, currentPos.y, currentPos.z) // 处理X轴移动(J左移) if (window.getKeyState(GLFW.GLFW_KEY_J)) { targetPos.x -= cameraSpeed // 预判移动后是否碰撞,碰撞则回滚X轴位置 if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) { targetPos.x = currentPos.x } } // 处理X轴移动(L右移) else if (window.getKeyState(GLFW.GLFW_KEY_L)) { targetPos.x += cameraSpeed if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) { targetPos.x = currentPos.x } } // 处理Z轴移动(K向前/向后,保持你原来的逻辑) if (window.getKeyState(GLFW.GLFW_KEY_K)) { targetPos.z -= cameraSpeed if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) { targetPos.z = currentPos.z } } // 最后将验证后的目标位置应用到相机 camera.setPosition(targetPos) }
逻辑说明
- 每个轴的移动独立计算,互不干扰:比如X轴碰撞时,Z轴的移动依然可以正常执行
- 采用预判位置检测,避免相机已经穿入碰撞体后再修正的卡顿问题
- 如果需要支持多个碰撞墙,只需把
wallModule1x1Renderable换成碰撞体列表,调用多碰撞体版本的检测函数即可
内容的提问来源于stack exchange,提问作者Momo
相关产品推荐
相关产品推荐

