AABB 碰撞解决滑动边

2024-04-18

因此,我目前正在重新发明轮子(并学到很多东西),尝试为我的游戏引擎制作一个简单的物理引擎。我一直在互联网上搜索,尝试(但失败)解决我当前的问题。关于这个主题有很多资源,但我发现的资源似乎都不适用于我的情况。

问题简而言之:当两个矩形碰撞时,碰撞分辨率在某些角上无法按预期工作。失败的方式因矩形的尺寸而异。我正在寻找的是一种“最短重叠”的碰撞解决方案或另一个相当简单的解决方案(我愿意接受建议!)。(向下滚动以获得更好的解释和插图)。

警告:以下代码可能不是很有效......

首先,这是我的物理循环。它只是循环遍历所有游戏实体并检查它们是否与任何其他游戏实体发生碰撞。它效率不高(n^2 等等),但目前有效。

updatePhysics: function(step) {
  // Loop through entities and update positions based on velocities
  for (var entityID in Vroom.entityList) {
    var entity = Vroom.entityList[entityID];
    if (entity.physicsEnabled) {
      switch (entity.entityType) {
        case VroomEntity.KINEMATIC:
          entity.pos.x += entity.vel.x * step;
          entity.pos.y += entity.vel.y * step;
          break;

        case VroomEntity.DYNAMIC:
          // Dynamic stuff
          break;
      }
    }
  }
  // Loop through entities and detect collisions. Resolve collisions as they are detected.
  for (var entityID in Vroom.entityList) {
    var entity = Vroom.entityList[entityID];
    if (entity.physicsEnabled && entity.entityType !== VroomEntity.STATIC) {
      for (var targetID in Vroom.entityList) {
        if (targetID !== entityID) {
          var target = Vroom.entityList[targetID];
          if (target.physicsEnabled) {
            // Check if current entity and target is colliding
            if (Vroom.collideEntity(entity, target)) {
              switch (entity.collisionType) {
                case VroomEntity.DISPLACE:
                  Vroom.resolveTestTest(entity, target);
                  break;
              }
            }
          }
        }
      }
    }
  }
},

这是实际碰撞检测的代码。这似乎也可以正常工作。

collideEntity: function(entity, target) {
  if (entity.getBottom() < target.getTop() || entity.getTop() > target.getBottom() ||  entity.getRight() < target.getLeft() ||  entity.getLeft() > target.getRight()) {
    return false;
  }

  return true;
},

这就是问题开始出现的地方。我希望实体只是被“推”出目标实体,并将速度设置为 0。只要实体和目标都是完美的正方形,这种方法就可以正常工作。如果假设实体(gif 中的玩家人物)是一个矩形,那么当最长边(X 轴)与目标(正方形)碰撞时,碰撞将会“滑动”。如果我交换播放器尺寸,使其又短又宽,那么 Y 轴也会出现同样的问题。

resolveTestTest: function(entity, target) {
  var normalizedX = (target.getMidX() - entity.getMidX());
  var normalizedY = (target.getMidY() - entity.getMidY());
  var absoluteNormalizedX = Math.abs(normalizedX);
  var absoluteNormalizedY = Math.abs(normalizedY);

  console.log(absoluteNormalizedX, absoluteNormalizedY);

  // The collision is comming from the left or right
  if (absoluteNormalizedX > absoluteNormalizedY) {
    if (normalizedX < 0) {
      entity.pos.x = target.getRight();
    } else {
      entity.pos.x = target.getLeft() - entity.dim.width;
    }

    // Set velocity to 0
    entity.vel.x = 0;

    // The collision is comming from the top or bottom
  } else {
    if (normalizedY < 0) {
      entity.pos.y = target.getBottom();
    } else {
      entity.pos.y = target.getTop() - entity.dim.height;
    }

    // Set velocity to 0
    entity.vel.y = 0;
  }

},

Collision on the Y axis works with these shapes GIF

Collision on the X axis slips with these shapes GIF

我该怎么做才能解决这个打滑问题?在过去的 5 天里,我一直在努力解决这个问题,所以如果有人能帮助我朝正确的方向前进,我将不胜感激!

谢谢 :)

- 编辑: -

如果仅沿左侧或右侧的一个方向移动,也会发生滑动。

-- 编辑 2 工作代码:--请参阅下面我的回答以获取工作代码的示例!


您犯的重要逻辑错误是这一行:

if (absoluteNormalizedX > absoluteNormalizedY) {

仅当两个实体都是正方形时这才有效。

考虑 X 滑动示例的近乎极端情况:如果它们几乎在拐角处接触:

虽然图有点夸张,但是可以看出absoluteNormalizedX < absoluteNormalizedY在这种情况下 - 您的实现将继续解决垂直碰撞,而不是预期的水平碰撞。


另一个错误是,无论碰撞发生在哪一侧,您始终将相应的速度分量设置为零:只有当速度分量与碰撞法线方向相反时,才必须将其归零,否则您将无法移开从表面上看。


克服这个问题的一个好方法是在进行碰撞检测时也记录碰撞面:

collideEntity: function(entity, target) {
   // adjust this parameter to your liking
   var eps = 1e-3;

   // no collision
   var coll_X = entity.getRight() > target.getLeft() && entity.getLeft() < target.getRight();
   var coll_Y = entity.getBottom() > target.getTop() && entity.getTop() < target.getBottom();
   if (!(coll_X && coll_Y)) return 0;

   // calculate bias flag in each direction
   var bias_X = entity.targetX() < target.getMidX();
   var bias_Y = entity.targetY() < target.getMidY();

   // calculate penetration depths in each direction
   var pen_X = bias_X ? (entity.getRight() - target.getLeft())
                      : (target.getRight() - entity.getLeft());
   var pen_Y = bias_Y ? (entity.getBottom() - target.getUp())
                      : (target.getBottom() - entity.getUp());
   var diff = pen_X - pen_Y;

   // X penetration greater
   if (diff > eps)
      return (1 << (bias_Y ? 0 : 1));

   // Y pentration greater
   else if (diff < -eps) 
      return (1 << (bias_X ? 2 : 3));

   // both penetrations are approximately equal -> treat as corner collision
   else
      return (1 << (bias_Y ? 0 : 1)) | (1 << (bias_X ? 2 : 3));
},

updatePhysics: function(step) {
   // ...
            // pass collision flag to resolver function
            var result = Vroom.collideEntity(entity, target);
            if (result > 0) {
              switch (entity.collisionType) {
                case VroomEntity.DISPLACE:
                  Vroom.resolveTestTest(entity, target, result);
                  break;
              }
            }
   // ...
}

为了提高效率,使用位标志而不是布尔数组。然后解析器函数可以重写为:

resolveTestTest: function(entity, target, flags) {
  if (!!(flags & (1 << 0))) {  // collision with upper surface
      entity.pos.y = target.getTop() - entity.dim.height;
      if (entity.vel.y > 0)  // travelling downwards
         entity.vel.y = 0;
  } 
  else
  if (!!(flags & (1 << 1))) {  // collision with lower surface
      entity.pos.y = target.getBottom();
      if (entity.vel.y < 0)  // travelling upwards
         entity.vel.y = 0;
  }

  if (!!(flags & (1 << 2))) {  // collision with left surface
      entity.pos.x = target.getLeft() - entity.dim.width;
      if (entity.vel.x > 0)  // travelling rightwards
         entity.vel.x = 0;
  } 
  else
  if (!!(flags & (1 << 3))) {  // collision with right surface
      entity.pos.x = target.getRight();
      if (entity.vel.x < 0)  // travelling leftwards
         entity.vel.x = 0;
  }
},

请注意,与您的原始代码不同,上面还允许corners碰撞 - 即沿着两个轴解析速度和位置。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AABB 碰撞解决滑动边 的相关文章

  • 使用 Javascript 防止刷新“跳转”

    我注意到 如果您在一个页面上并且向下滚动了很多 如果您刷新页面 大多数浏览器会将您跳回到您的位置 有什么办法可以防止这种情况发生吗 我研究了两个选项 但在 Webkit Firefox 上都不一致 window scrollTo 0 1 h
  • JavaScript 中工厂函数与构造函数的性能比较

    所以 当我们有一个简单的构造函数时 function Vec x y this x x this y y 还有一个工厂类似物 function VecFactory x y return x x y y 性能具有可比性 100000000
  • 如何使用 Fabric js 以编程方式自由绘制?

    使用 Fabric js 构建多人涂鸦 尝试使用 Fabric js 实现多人涂鸦 想法是当 U1 在画布上绘制时 我们将点推送到 RTDB 并在客户端上获取这些点 并以编程方式在两个客户端中绘制笔画 您可以将画布的数据保存在path cr
  • 解析 Angular2 中的 xml 以在视图中呈现

    我是否需要解析 xml 以从 xml 获取数据以在 html 中呈现 我目前正在使用获取本地 xml 文件http get请求并在控制台日志中显示 xml 文件中的所有信息 我认为它只是在读取它 问题是如何在angular2中将xml转换为
  • IIFE 和 call 的区别

    之间有区别吗 function call this and function or var MODULE function this hello world call MODULE and var MODULE function m m h
  • 表单验证后 isValid 保持 false

    我有一个自定义验证函数 但即使它没有返回错误 表单仍然无效 我将以下属性传递给 Formik validate import files gt return import files values length 0 import files
  • jquery $('id').text 带粗体

    我有一个 jquery 可以更改链接的文本 如下所示 if urlfind gt 0 linkurl text More info 和 HTML a href a 我试图为此链接添加粗体 但添加 b More Info b 让它们在文本本身
  • parseInt() 和 Number() 有什么区别?

    How do parseInt https developer mozilla org en US docs Web JavaScript Reference Global Objects parseInt and Number https
  • 将数组传递给 include() javascript

    我试图找出一个字符串是否包含存储在数组中的多个字符串 includes 所以我尝试过 let string hello james console log string includes hello james 但它被返回为false 当我
  • Cloudflare Worker 缓存 API 出现问题

    我现在花了无数的时间尝试让缓存 API 来缓存一个简单的请求 我让它在中间工作过一次 但忘记向缓存键添加一些内容 现在它不再工作了 不用说 cache put 没有指定请求是否实际被缓存的返回值并不完全有帮助 我只能进行反复试验 有人可以给
  • TinyMCE 选择文本并使用 javascript 激活链接对话

    我正在尝试编写一个自动化 使用黄瓜 水豚 硒 测试 它将在tinymce框中选择一些文本 单击链接按钮 然后打开链接选择页面 但链接按钮仅在选择某些文本时才变为活动状态 所以第一轮 tinyMCE activeEditor selectio
  • 如何将对象传递给 onclick 事件[重复]

    这个问题在这里已经有答案了 可能的重复 Javascript 循环内的事件处理程序 需要闭包吗 https stackoverflow com questions 341723 event handlers inside a javascr
  • 在模型对象上设置属性?

    Hi 我正在构建 ASP NET MVC 站点并遇到了问题 在我的项目中 我得到了一个 modelview 类 其中包含几个属性 例如 public class myModelView public int MyProperty1 get
  • 如何将java数组列表转换为javascript数组? [复制]

    这个问题在这里已经有答案了 我们如何将 String 对象的 java arraylist 转换为 javascript 数组 这就是我正在做的事情 但我正在寻找更好的方法来做到这一点 我不想迭代数组列表 var myArray
  • 根据用户投票移动 div

    我是新来的 但我喜欢这个网站 我检查了其他类似的问题 但没有看到我要找的东西 我是一名音乐家 有一段时间我一直在做 每日之歌 每天写一首小歌 我想将歌曲发布为 div 在里面 li 在 div 中 我只想要一个简单的 mp3 播放器和一个
  • 有没有办法在不托管网站的情况下呈现网站并共享它?

    我正在为一个项目创建一个 repl it 网站 问题是我的老师要求不要发布该网站 这意味着我无法使用 repl it 来托管它 我想知道是否有任何方法可以制作可以通过 Google Chrome 查看的网站副本 而无需连接到主机 我有所有的
  • 使用node和multer将图像上传到heroku不起作用

    我正在尝试使用 Node 后端将图像文件上传到 Heroku 我可以使其工作 同样的过程在本地主机测试中工作得很好 但是在将我的项目部署到 Heroku 并测试它之后 过程和文件中出现错误不会上传 后端 let storage multer
  • ES6 - 有没有一种优雅的方法来导入所有命名导出而不是默认导出?

    我正在寻找一种优雅的方法来导入所有命名导出 而不必导入默认导出 在一个文件中 我导出许多命名常量以及默认值 myModule js const myDefault my default export const named1 named1
  • 展平数组中的对象

    大家好 我从响应中获取了一系列对象 我需要将所有学生对象展平为简单的学生姓名 但不确定如何进行 任何帮助将不胜感激 数组示例 students id 123456 name Student Name active true students
  • 如何在禁用按钮上启用 Bootstrap 工具提示?

    我需要在禁用的按钮上显示工具提示 并在启用的按钮上删除它 目前 它的工作原理是相反的 扭转这种行为的最佳方法是什么 rel tooltip tooltip

随机推荐

  • 如何将输入参数作为以逗号分隔的字符串或 DB2 中 IN 子句的列表传递

    我是存储过程的新手 我有一个疑问 我需要将输入参数作为以逗号分隔的字符串或 DB2 中 IN 子句的列表传递 请参阅下面的示例程序 CREATE PROCEDURE TEST SP IN listofUsername SPECIFIC TE
  • iOS 上可写的目录位置有哪些?

    我无法在 Apple iOS SDK 上找到有关哪些目录可写 哪些目录不适合您的应用程序的信息 我只假设NSCachesDirectory and NSDocumentDirectory是可写的 但其他的怎么样 比如NSApplicatio
  • 无法分配给属性:“$text”是不可变的

    我想在 SwiftUI 中创建一个自定义文本字段来处理第一响应者 但我在代码中遇到此错误并且结构是不可变的我不知道该怎么办 struct CustomTextField UIViewRepresentable class Coordinat
  • 使用 make 构建多个二进制文件

    我想创建一个 Makefile 在父目录中 来调用其他几个 Makefile 在子目录中 这样我就可以通过仅调用一个父 Makefile 来构建多个二进制文件 每个项目子目录一个 我的研究因在递归 Makefile 上找到大量内容而受到阻碍
  • 从同一文件和不同文件调用nodejs函数

    Model js 文件具有以下条目 exports update function tag view date 并调用该函数 例如 update test 1213 11 10 2014 它抛出以下错误 update test 1213 1
  • 如何将 ffplay 作为无窗口进程运行?

    我正在运行 ffplay 作为后台进程 它向我的主 UI 进程提供图像数据 我已经设定 SDL VIDEODRIVER dummy 抑制 SDL 窗口中显示的 ffplay 视频 问题是 即使不显示视频输出窗口 ffplay 进程仍然显示为
  • GNU C++ 如何检查 -std=c++0x 何时生效?

    我的系统编译器 gcc42 可以很好地满足我想要的 TR1 功能 但尝试支持除系统之外的较新编译器版本 尝试访问 TR1 标头时会出现 error 要求 std c 0x 选项 因为它如何与图书馆或类似的集线器接口 usr local li
  • IntelliJ 调试器:连接但不会注意到代码何时遇到断点

    我尝试使用 IntelliJ IDEA 11 1 Ultimate 调试应用程序服务器 WebLogic 调试器配置以前有效 我没有更改任何内容 发生的情况是 IntelliJ 告诉我 连接到目标虚拟机 地址 snip 9009 传输 so
  • 黑色视频 CAAnimation 和 AVFoundation AVAssetExportSession

    我是整个 AVFoundation 视频编辑电路的新手 我当前的测试应用程序是一个双屏幕应用程序 第一个屏幕执行 AVFoundation 视频录制 1 mov 第二个屏幕可让您查看视频并使用 CAAnimation 在其上添加一些标题 1
  • Windows 窗体中的本机外观(类似资源管理器)主菜单

    除了使用 MenuStrip 之外 还有其他方法在 C 中创建主菜单吗 它看起来与标准资源管理器菜单不相似 我在这里做错了什么吗 我只想要标准应用程序主菜单 例如浏览器菜单 听起来您想要一个尊重操作系统主题的菜单 MainMenu 类将执行
  • 使用 Android 应用程序访问 SIM 卡?

    我想知道是否可以使用 Android 应用程序访问 SIM 卡 你可以像这样获取 IMEI 但这是你想要的吗 只是一个例子 mTelephonyMgr TelephonyManager getSystemService Context TE
  • API 平台 - 我应该使用哪种方法来创建没有实体的自定义操作

    我是 API 平台的新手 我认为这很棒 但我找不到任何示例如何创建不基于任何实体的自定义端点 有很多基于实体的示例 通常都是关于 CRUD 的 但是自定义操作呢 我需要使用一些与任何实体无关的自定义参数通过数据库创建自定义搜索 例如 我想接
  • ASP中,位运算符左移和右移

    有谁知道左移和右移运算符示例吗 我是 ASP 新手 我发现了位运算符 例如 AND OR NOT 等等 对于 vbscript 左移是通过乘法完成的 即 var 2 左移一个位置 var 4 左移两个位置等 右移是通过除法完成 即 var
  • Zend Framework 2 的多个表

    我是 Zend Framework 2 的新手 我成功完成了 ZF2 的专辑教程 现在我想仅显示数据库中多个表中的某些数据 我有一个简单的数据库设置 其中包含表格 例如人员 书籍 状态等 数据库应该做什么并不重要 我想知道是否有一个教程可以
  • 从 C 代码获取当前使用的文件描述符的计数

    是否有 C API 可以获取 系统范围内当前使用的文件描述符 当前进程当前使用的文件描述符 对于当前进程计数 您可以使用getrlimit获取文件描述符限制 然后迭代从 0 到该限制的所有整数并尝试调用fcntl与F GETFD命令 它只会
  • PubNub:将所有已发布消息记录到我的数据库的正确方法是什么

    记录每条已发布消息并将其保存到我的服务器数据库的正确方法是什么 我能想到的有两种选择 使用PubNub功能发布事件后并将消息转发到专用记录器通道 服务器将订阅该频道并将到达的消息保存到数据库 这里又产生一个问题 当我在PubNub函数中将消
  • 使用 ActiveRecord 和 Rails 3 进行复杂 JOIN

    我有以下型号 class User lt ActiveRecord Base has many memberships has many groups through gt memberships end class Group lt Ac
  • 如何在 C# 中旋转标签? [复制]

    这个问题在这里已经有答案了 我想显示一个旋转 90 度的标签 这样我就可以将它们中的一堆作为标题放在表格的顶部 是否有捷径可寻 您需要编写自己的控件或使用自定义控件 A 代码项目 http en wikipedia org wiki The
  • Qt 和 Google 地球 API

    是否可以使用 Google Earth 在 Qt 中开发应用程序 例如 我想在我的应用程序中通过 QtGL 将地球 如谷歌地球 显示为球体 很明显 您可以在 Qt 中使用 google Earth api 我想分享一个秘密 Google E
  • AABB 碰撞解决滑动边

    因此 我目前正在重新发明轮子 并学到很多东西 尝试为我的游戏引擎制作一个简单的物理引擎 我一直在互联网上搜索 尝试 但失败 解决我当前的问题 关于这个主题有很多资源 但我发现的资源似乎都不适用于我的情况 问题简而言之 当两个矩形碰撞时 碰撞