同一节点的碰撞检测和重叠检测? [第2部分]

2024-04-30

的延续上一个问题 https://stackoverflow.com/questions/71608423/collision-detection-and-overlapping-detection-in-same-node/71622366?noredirect=1#comment126602229_71622366

我们到底如何检测碰撞body_set_force_integration_callback?


对于上下文,我们有一个身体RID:

var _body:RID

我们设置了一个回调body_set_force_integration_callback:

Physics2DServer.body_set_force_integration_callback(_body, self, "_body_moved", 0)

func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
    pass

在进一步讨论之前,我想指出的是最后一个参数body_set_force_integration_callback就是我们得到的_user_data。但是,如果我将其设置为nullGodot 不会向调用传递两个参数,在这种情况下我应该定义_body_moved仅与state范围。

戈多将召唤我们的_body_moved如果身体状态处于活动状态(即未睡眠),则每个物理帧。


Note: 我们需要打电话body_set_max_contacts_reported并设置我们想要报告的联系人数量,例如:

Physics2DServer.body_set_max_contacts_reported(_body, 32)

现在,在Physics2DDirectBodyState我们得到联系人,我们可以询问每个联系人的一些信息,包括身体:

func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
    for index in state.get_contact_count():
        var body:RID = state.get_contact_collider(index)
        var instance:Object = state.get_contact_collider_object(index) 

如果它是一个身体PhysicsBody2D, then instance将会拥有它。

如果我们想实现body_entered and body_exited,我们需要跟踪尸体。我将保留实例的字典(即PhysicsBody2D)我将用它来报告get_colliding_bodies too.

然后我们需要跟踪形状body_shape_entered and body_shape_exited,不仅仅是身体。我们可以这样找到它们:

func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
    for index in state.get_contact_count():
        var body:RID = state.get_contact_collider(index)
        var instance:Object = state.get_contact_collider_object(index) 
        var body_shape_index:int = state.get_contact_collider_shape(index)
        var local_shape_index:int = state.get_contact_local_shape(index)

注意他们不是RID。它们是形状在身体中的位置(所以0是身体的第一个形状,1是第二个,依此类推)。这意味着我们无法将形状与物体分开来跟踪,因为如果不知道它们属于哪个物体,它们的形状索引就没有意义。这意味着我们不能像以前那样简单地使用两个主体数组。

另外,如果我们只有一种形状 - 这是之前答案的情况 - 我们可以忽略local_shape_index因为它总是0。在这种情况下我只需要一个Dictionary索引为body:RID of body_shape_index:int.

如果我不接受这个假设,我就很难决定数据结构。

  • 我可以用一个Dictionary索引为body:RID of Dictionary索引为body_shape_index:int of local_shape_index:int,在这种情况下,我需要辅助方法来处理它,这促使我为它创建一个类。
  • 我可以用一个Dictionary索引为body:RID的元组body_shape_index:int and local_shape_index:int。除了没有元组类型,所以我会作弊并使用Vector2.

你知道吗?我会作弊并使用Vector2.

signal body_entered(body)
signal body_exited(body)
signal body_shape_entered(body_rid, body, body_shape_index, local_shape_index)
signal body_shape_exited(body_rid, body, body_shape_index, local_shape_index)

var colliding_instances:Dictionary = {}
var colliding_shapes:Dictionary = {}

func _body_moved(state:Physics2DDirectBodyState, _user_data) -> void:
    var old_colliding_shapes:Dictionary = colliding_shapes
    var new_colliding_shapes:Dictionary = {}
    colliding_shapes = {}
    var instances:Dictionary = {}
    for index in state.get_contact_count():
        # get contact information
        var body:RID = state.get_contact_collider(index)
        var instance:Object = state.get_contact_collider_object(index) 
        var body_shape_index:int = state.get_contact_collider_shape(index)
        var local_shape_index:int = state.get_contact_local_shape(index)
        var vector := Vector2(body_shape_index, local_shape_index)

        # add to instances
        instances[body] = instance

        # add to colliding_shapes
        if not colliding_shapes.had(body):
            colliding_shapes[body] = [vector]
        else:
            colliding_shapes[body].append(vector)

        # remove from old_colliding_shapes or add to new_colliding_shapes
        # there is room for optimization here
        if (
            old_colliding_shapes.has(body)
            and old_colliding_shapes[body].has(vector)
        ):
            old_colliding_shapes[body].erase(vector)
            if old_colliding_shapes[body].size() == 0:
                old_colliding_shapes.erase(body)
        else:
            if not new_colliding_shapes.had(body):
                new_colliding_shapes[body] = [vector]
            else:
                new_colliding_shapes[body].append(vector)    

    for body in old_colliding_shapes.keys():
        # get instance from old dictionary
        var instance:Object = colliding_instances[body]
        # emit
        if not instances.has(body):
            emit_signal("body_exited", body)

        for vector in old_colliding_shapes[body]:
            emit_signal(
                "body_shape_exited",
                body,
                instance,
                vector.x,
                vector.y
            )

    for body in new_colliding_shapes.keys():
        # get instance from new dictionary
        var instance:Object = instances[body]
        # emit
        for vector in old_colliding_shapes[body]:
            emit_signal(
                "body_shape_entered",
                body,
                colliders[body],
                vector.x,
                vector.y
            )

        if not colliding_instances.has(body):
            emit_signal("body_entered", body)

    # swap instance dictionaries
    colliding_instances = instances

func get_colliding_bodies() -> Array:
    return colliding_instances.values()

变量old_colliding_shapes从已知会发生碰撞的形状开始,在迭代中我们将删除我们看到的每个形状。所以最后,它的形状曾经发生过碰撞,但现在不再发生了。

变量new_colliding_bodies开始为空,在迭代中我们添加未从中删除的每个形状old_colliding_shapes,所以最后它有我们之前不知道的碰撞形状。

请注意old_colliding_shapes and new_colliding_bodies是互斥的。如果一个物体在一个物体中,那么它就不在另一个物体中,因为我们只是将物体添加到new_colliding_bodies当它不在old_colliding_shapes。但由于它们有形状而不是身体,所以两者都可以出现身体。这就是为什么我需要额外的检查来发出"body_exited" and "body_entered".

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

同一节点的碰撞检测和重叠检测? [第2部分] 的相关文章

  • 【Godot】对 Godot 节点设计的思考

    对 Godot 中节点设计的思考 单个节点的功能设计的想法 xff0c 体会 Godot 的设计思想 低耦合 设计单个节点可复用的节点时 xff0c 调用方法尽量只对当前节点可获取到的变量或方法进行使用 xff0c 比如我写一个可以控制 K
  • 【Godot 4.0】一个简单的匿名方法的使用lambda

    Godot 4 0 beta3 Godot 4 0 中添加了 lambda 表达式 xff0c 匿名方法等很多方便的特性 xff0c 这里我写个用于扫描目录下所有文件的功能 可以看到代码非常简洁 span class token keywo
  • Godot Engine:GDScript 4.X中语法的变化(2020年8月4日 更新)

    文章目录 4 X版 GDScript范例支持注解属性 xff08 Properties xff09 的定义格式await关键字代替yield加入super关键字去除了多级调用问题小结 4 X版 GDScript范例 支持注解 从4 x开始
  • Godot 4 应用 - 图形绘制

    花了两天时间 做了一个初步的图形软件效果 先占个坑 以后再叙
  • Godot 4 源码分析 - 文件读入编码处理

    今天需要读入xml文件进行处理 结果读入一个带中文的文件时 出错了 当然程序还能运行 但编译器一直报错 而且XML解析也不正确 单步调试发现读入的内容出现乱码 具体逻辑 String FileAccess get as text bool
  • 关于在windows使用msys2 + mingw + gcc/g++ 编译godot的笔记

    关于在windows使用msys2 mingw gcc g 编译godot的笔记 编译参数 1 target release debug release debug 2 多线程参数 j数字 3 profile是自定义构建参数 可以启用或者禁
  • 如何创建没有 setter 函数的 getter 函数?

    我的脚本中有多个导出的变量 每当更改一个变量时 我想调用一个通用的 getter 并让值自动设置 tool export float var sample1 setget smthn changed export float var sam
  • 合并多个精灵节点?

    例如 假设我有 2 个精灵节点 但也可以超过 2 个 如下所示 每个人都有自己独立的图像我想要的是将它们组合起来并用单个图像创建一个新的精灵节点 在工具模式下 like this 也许可以通过使用Image 毫无疑问涉及计算 或者也许使用一
  • 如何检测 Godot 中的碰撞?

    我有3个场景 一个名为 KinematicBody2D tscn 的 KinematicBody2D 节点 该场景是一个玩家在屏幕上从左向右移动 我还有一个名为 mob tscn 的场景 它是一个igidbody2d节点 这个场景只有精灵和
  • (Godot 引擎)用 Tilemap 瓷砖填充 2D 多边形

    我在 Godot 引擎中遇到一个无法解决的问题 怎么可能 在代码中 用图块填充 Polygon2D 区域 我尝试过获得点位置 使用 2D for 循环遍历线的顶点 但我无法理解这一点 这是我期待的结果的模型 我有解决方案 有一点 hacky
  • 在 Area2D 中覆盖 KinematicBody2D 运动?

    I m trying to create a windy area within which the player would be pushed continuously to the left lt 到目前为止 这就是我想出的Windy
  • 如何在 GDScript 中实现结构?

    GDScript 中是否有相当于 C 结构 类的东西 例如 struct Player string Name int Level 戈多3 1 1gdscript不支持structs 但使用可以实现类似的结果classes dict or
  • 如何在Godot 4.0游戏引擎中实现可组合的角色/技能系统?

    我目前正在使用 Godot 尝试 MOBA 风格游戏的原型 我正在努力寻找一种管理角色及其技能的方法 所有角色都将具有相似的属性 姓名 生命值 奔跑速度 力量等 然而 所有角色的技能都会有所不同 尽管有些角色非常相似 例如基于投射物的技能将
  • 在 godot 游戏引擎中使用不同的编程语言?

    我想要将不同的编程语言绑定到 Godot 游戏引擎 有关于这个主题的指导文件或视频吗 例如 这个项目是如何完成的 戈多锈 https github com godot rust godot rust 如果我能学习基础知识 我就能成功地用不同
  • 安卓:应用程序未安装

    这里是新手 我用Godot游戏引擎制作了我的第一个游戏并成功导出到android 复制到我的手机上 它安装并运行良好 几个小时后 我做了一些更改并再次导出 再次复制了 apk 但现在当我尝试安装它时 它没有完成安装 我多次尝试更改导出设置
  • 如何在戈多中使刚体跳跃而不赋予其飞行能力

    我本来会使用运动体 但我想将现实生活中的物理添加到我的 2d 对象中 但似乎我可以通过多次按向上键来飞行 extends RigidBody2D var velocity Vector2 ZERO const GRAVITY 35 cons
  • 如何克服 Godot 将按钮字体更改为默认颜色的问题?

    我正在使用 Godot 4 我在容器中手动创建了很多按钮 我在主场景中设置了一个颜色变量 tempcol 当我单击带有 tempcol 设置的按钮时 比如 Color Red 按钮的字体颜色更改为白色 似乎是默认字体颜色 但是当我单击另一个
  • 传递Physics2DShapeQueryParameters 层进行检查

    我目前正在为我的 2D 自上而下游戏开发一个构建系统 最后一步是检查是否有任何物体 例如树或玩家 阻碍了物品的放置 经过一些研究后 我发现使用Physics2DShapeQueryParameters 是正确的方法 我唯一的问题是我不知道如
  • 同一节点的碰撞检测和重叠检测? [第2部分]

    的延续上一个问题 https stackoverflow com questions 71608423 collision detection and overlapping detection in same node 71622366
  • 关闭 Godot 中的游戏

    我正在使用 Godot 创建网页游戏 为了关闭游戏 我尝试使用 get tree quit 如果我在 IDE 上使用它 它就可以工作 当我在我的服务器上尝试它时 导出项目后 它不起作用 我确信导出设置没问题 我怎样才能关闭游戏 并且 如何添

随机推荐

  • 如何在 swift 中实现 Pubnub Access Manager

    我正在研发如何在 swift 中实现 pubnub 访问管理器 经过一些研究 我了解到 Swift SDK 不包含 pubnub grant 我需要使用 pubnub 函数来实现无服务器计算 我在 pubnub 仪表板中创建了一个函数并创建
  • Go 中的格式错误 - %s %v 或 %w

    s v and w可用于格式化 Go 中的错误 将它们转换为字符串 fmt Errorf 它们在 Go 自己的工具中的使用方式似乎有所不同 In cmd go internal get path go https github com go
  • Git 仅拉取一次提交

    其实git仓库和本地文件是一模一样的 但另一个网站距离 5 次提交还很远 所以我有一段时间没有拉了 我也不想这样做 所以现在我想对我的本地文件进行一些更改 然后将其推送到 git 存储库的新提交中 然后只能拉动该一个提交 而不能拉动所有其他
  • 在设计时存储“记录数组”的最佳方式

    我需要在设计时存储一组数据 以便在运行时构造一组组件的内容 像这样的事情 type TVulnerabilityData record Vulnerability TVulnerability Name string Description
  • Java 递增/递减运算符 - 它们的行为方式是什么,功能是什么?

    开始学习Java已经三天了 我有这个程序 但我不明白其中的代码main方法与 and 运营商 我什至不知道该怎么称呼他们 这些操作员的名字 谁能给我解释一下这是怎么回事 class Example public static void ma
  • 如何将字段从主报表传递到表格元素?

    到目前为止 我使用列标题和详细信息带来生成表格 现在我想使用iReport 4 0 2 中的表格元素 我这样尝试过 iReport 将参数从主报表查询传递到表或列表的数据集查询 https stackoverflow com questio
  • 如何制作Applicative的固定长度向量实例?

    最近了解了推广 决定尝试写向量 LANGUAGE DataKinds GADTs KindSignatures module Vector where data Nat Next Nat Zero data Vector Nat gt gt
  • Python 中的字符串、整数和运算符

    如何在运算中使用算术运算符 由用户作为字符串输入 我可以打印操作本身 但我想打印解决方案 这是我的笨拙尝试 Initialise variables x 2 y 3 Prompt the user for an arithmetic ope
  • Python 在打开套接字时可以选择哪个网络适配器吗?

    运行 python 应用程序的目标计算机将具有三个可用的网络接口 一般来说 所有三个网络都会有很大不同 但是三个网络中的两个可能位于相似的网络上 在下面的示例中 我无法控制 ETH 2 上的目标地址 因为它是预先配置的系统 因此我被迫以编程
  • 如何取消js文件的压缩?

    如何取消通过 webpack 工具缩小的 js 文件 缩小之前 function autoslideSlider next slide trigger click window on load function preloader fade
  • 使用不正确的凭据登录时,Jquery Mobile Rails & Devise 加载页面时出错

    我正在掌握 Rails 3 的窍门 并制作了几个可用的应用程序 我是在 Rails 中使用 javascript 或 jquery 的新手 我有一个使用 Rails 3 2 devise 和 cancan 的工作应用程序 然后我将其转换为使
  • npm - EPERM:Windows 上不允许操作

    I ran npm config set prefix usr local 运行该命令后 当尝试在 Windows 操作系统上运行任何 npm 命令时 我不断收到以下信息 Error EPERM operation not permitte
  • 实体框架,高效的NavigationProperty.OfType查询

    我在使用每表类型 TPT 继承在 EF4 中构造有效查询时遇到问题 我有一个名为Episode 并且每个情节可以有多个事件 有几种不同类型的事件都源自称为Event 我想过滤不包含特定类型事件的所有剧集 Episode有一个导航属性 它是其
  • 用于 C# 和 iPhone 应用程序的 MongoDB

    我正处于设计应用程序的初始阶段 该应用程序将具有用 C 实现的后端 该后端将使用 IIS 上托管的 WCF Web 服务为其他平台提供数据 iPhone 就是其中之一 由于是个人项目 所以想用它来学习MongoDB 我已经知道有社区开发的
  • Android:将视图放置在任意位置

    我一直在尝试将视图放置在任意位置 My aim 覆盖 JPG PNG 的某个矩形 给定坐标与 JPG PNG 相关的 还有一些其他视图 例如图库或一些视频 我不想使用绝对布局 因为它已被弃用 因此 我使用relativelayout 定义一
  • CSS 精灵和 IE6

    IE6 支持 CSS 精灵吗 是的 IE 6 支持精灵 但不支持 24 位 PNG 透明度 我使用这个 css hack 为 IE background image url images sprites icons sprite png b
  • 使用 T-SQL FOR XML PATH 删除空 XML 节点

    我在用着FOR XML PATH从 SQL Server 2008R2 中的表构造 XML XML 必须按如下方式构建
  • 设备重启后 UNUserNotificationCenter 通知

    我一直在网上搜索 看看您安排的通知是否会在设备重新启动后被删除 我发现了不同的意见 所以我开始测试它 这是我注意到的 我安排了 10 分钟后的通知 重新启动手机 没有任何反应 但是 昨天我安排了很多通知 其中一些是当天的 尽管从昨天开始我已
  • 如何在 Web 视图中向下滚动时隐藏 ActionBar/Toolbar

    在 Google Chrome 和 Play 商店中 该应用程序可以在滚动时隐藏操作栏 并允许用户方便地浏览 请帮助我这样做 我已经将 onTouchListener 用于 webview 但它不起作用 mWebView setOnTouc
  • 同一节点的碰撞检测和重叠检测? [第2部分]

    的延续上一个问题 https stackoverflow com questions 71608423 collision detection and overlapping detection in same node 71622366