游戏开发中的物理之射线投射

news/2024/11/8 9:09:32/

游戏开发中的物理之射线投射

  • 介绍
  • 空间
  • 进入空间
  • Raycast查询
  • 碰撞异常
  • 防撞面罩
  • 屏幕上的3D射线投射

介绍

游戏开发中最常见的任务之一是投射光线(或自定义形状的物体)并检查其撞击。这样就可以进行复杂的行为,AI等。本教程将说明如何在2D和3D中执行此操作。

Godot将所有低级游戏信息存储在服务器中,而场景只是前端。因此,射线投射通常是较低级别的任务。对于简单的射线广播,诸如RayCast和RayCast2D之类的节点 将起作用,因为它们将在每一帧中返回射线广播的结果。

但是,很多时候,光线投射必须是一个更具交互性的过程,因此必须存在一种通过代码进行光线投射的方法。

空间

在物理世界中,戈多特将所有低级碰撞和物理信息存储在一个空间中。可以通过访问CanvasItem.get_world_2d()。space获取当前的2d空间(用于2D物理) 。对于3D,它是Spatial.get_world()。space。

生成的空间RID可以分别在 PhysicsServer和 Physics2DServer中用于3D和2D。

进入空间

Godot物理默认情况下与游戏逻辑在同一线程中运行,但可以设置为在单独的线程上运行以更有效地工作。因此,唯一安全的访问空间时间是在 Node._physics_process() 回调期间。由于空间被锁定,从此功能外部访问它可能会导致错误。

要对物理空间执行查询, 必须使用Physics2DDirectSpaceState 和PhysicsDirectSpaceState。

在2D中使用以下代码:

public override void _PhysicsProcess(float delta)
{var spaceRid = GetWorld2d().Space;var spaceState = Physics2DServer.SpaceGetDirectState(spaceRid);
}

或更直接地:

public override void _PhysicsProcess(float delta)
{var spaceState = GetWorld2d().DirectSpaceState;
}

在3D中:

public override void _PhysicsProcess(float delta)
{var spaceState = GetWorld().DirectSpaceState;
}

Raycast查询

为了执行2D射线广播查询, 可以使用Physics2DDirectSpaceState.intersect_ray()方法 。例如:

public override void _PhysicsProcess(float delta)
{var spaceState = GetWorld2d().DirectSpaceState;// use global coordinates, not local to nodevar result = spaceState.IntersectRay(new Vector2(), new Vector2(50, 100));
}

结果是一个字典。如果射线没有击中任何东西,则字典将为空。如果确实撞到了东西,它将包含碰撞信息:

if (result.Count > 0)GD.Print("Hit at point: ", result["position"]);

result发生碰撞时的词典包含以下数据:

{position: Vector2 # point in world space for collisionnormal: Vector2 # normal in world space for collisioncollider: Object # Object collided or null (if unassociated)collider_id: ObjectID # Object it collided againstrid: RID # RID it collided againstshape: int # shape index of collidermetadata: Variant() # metadata of collider
}

使用Vector3坐标,数据在3D空间中相似。

碰撞异常

射线投射的一个常见用例是使角色能够收集有关其周围世界的数据。这样做的一个问题是,同一个角色具有对撞机,因此,光线将仅检测其父级的对撞机,如下图所示:

../../_images/raycast_falsepositive.png

为了避免自相交,该intersect_ray()函数可以采用可选的第三个参数,该参数是一组异常。这是如何从KinematicBody2D或任何其他碰撞对象节点使用它的示例:

class Body : KinematicBody2D
{public override void _PhysicsProcess(float delta){var spaceState = GetWorld2d().DirectSpaceState;var result = spaceState.IntersectRay(globalPosition, enemyPosition, new object[] { this });}
}

异常数组可以包含对象或RID。

防撞面罩

尽管exception方法可以很好地排除父正文,但是如果您需要大量和/或动态的exception列表,它将变得非常不便。在这种情况下,使用碰撞层/遮罩系统效率更高。

可选的第四个参数intersect_ray()是碰撞蒙版。例如,要使用与父实体相同的蒙版,请使用collision_mask 成员变量:

class Body : KinematicBody2D
{public override void _PhysicsProcess(float delta){var spaceState = GetWorld2d().DirectSpaceState;var result = spaceState.IntersectRay(globalPosition, enemyPosition,new object[] { this }, CollisionMask);}
}

有关如何设置碰撞遮罩的详细信息,请参见代码示例。

屏幕上的3D射线投射

将光线从屏幕投射到3D物理空间对于拾取对象很有用。不需要这样做,因为 CollisionObject 有一个“ input_event”信号,可以让您知道何时单击它,但是如果有手动操作的愿望,请按以下步骤操作。

要从屏幕投射光线,您需要一个Camera 节点。ACamera可以采用两种投影模式:透视和正交。因此,必须同时获得射线的起点和方向。这是因为origin在正交模式下会normal发生变化,而在透视模式下会 发生变化:

../../_images/raycast_projection.png

要使用相机获取它,可以使用以下代码:

private const float rayLength = 1000;public override void _Input(InputEvent @event)
{if (@event is InputEventMouseButton eventMouseButton && eventMouseButton.Pressed && eventMouseButton.ButtonIndex == 1){var camera = (Camera)GetNode("Camera");var from = camera.ProjectRayOrigin(eventMouseButton.Position);var to = from + camera.ProjectRayNormal(eventMouseButton.Position) * rayLength;}
}

请记住,在期间_input(),该空间可能被锁定,因此实际上该查询应在中运行_physics_process()


http://www.ppmy.cn/news/786766.html

相关文章

Ray Casting:光线投射

本次作业完成的是通过正交相机投影ray casting方式渲染,得到一个场景中有若干个球形的图片,并以深度测试后直接显示色彩和简单限制深度后显示两种方式来显示。 目录 原理 结果 github连接 原理 在不考虑二次反射和多次反射的情况下,Ray cas…

Cesium无人机实时视频投射及关键点拍照展示

最近做了这个无人机实时视频投射的功能,其中介入了实时无人机的坐标数据、姿态以及视频流。 说下思路: 其中锥体用了自定义的geometry,视频面用的是polygon给的video材质,坐标用了samplepositionproperty进行储存,姿态…

系统架构设计师笔记第29期:人工智能技术

人工智能(Artificial Intelligence,AI)是指使机器能够模拟和展现人类智能的一门学科和技术。它涉及构建智能系统,使其能够感知、理解、学习、推理、决策和交互,以解决复杂的问题并执行各种任务。 人工智能的目标是使机…

算法刷题Day 29 递增子序列+全排列+全排列II

Day 29 回溯算法 491. 递增子序列 如果直接像下面这样写的话,会出错,出错的案例类似: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9nrEEc2S-1688623883770)(LC491-递增子序列LC.assets/image-20230703201315…

教你用手机模拟加密门禁卡-不用电脑,不ROOT手机

目标:将门禁卡、考勤卡、会员卡、停车卡、电梯卡等等各种卡模拟进手机里,模拟后可用手机代替刷卡,无需root,不用电脑 ## 背景介绍:1、前言  目前,IC卡已被广泛应用于身份识别、金融消费、安全认证等领域。…

android 判断有无sim卡,Android判断手机里是否有SIM卡

由于项目的需要,要判断手机里是否有sim卡。在网上找了一下资料结果发现,网上的资料很多都是一样的,都是判断sim卡的状态,把代码添加进去后发现不能满足需求。然后就自己看了一下文档。代码如下。 /** * author CX- * 判断 是否含有…

小米NFC手机复制加密IC门禁卡

几年没有发过任何文字信息了。闲来无事发一个NFC手机复制加密门禁卡的教程 思路: 第一步通过破解加密的门禁卡得到dump文件,获取卡号。修改dump文件只保留0扇区0块的内容也就是卡号,通过读卡器写入一张卡空白卡。这时就得到了一张未加密的白卡了。手机NFC可以模拟这张未加密…

Android手机无法识别SD卡的处理方法

1. 首先将SD卡放到读卡器中2. 使用Windows磁盘检查工具检查,选择“自动修复文件系统错误”,如果检查出有错误,再查一遍,直到提示“您的磁盘没有问题”。注:磁盘检查工具位置:SD卡的盘符上右键>属性>工…