ue5 sweeping和碰撞

在 Unreal Engine 中,Sweeping 是一个用于检测物体碰撞的技术,它可以在物体移动时检测它沿着移动路径上是否与其他物体发生碰撞。它主要用于防止物体在移动过程中穿透其他物体,确保物体的移动和碰撞检测更准确。

1. Sweeping 的基本概念

当你在游戏中移动一个物体时,如果直接设置物体的新位置而不进行碰撞检测,物体可能会穿过其他物体(比如墙壁、地板等)。为了防止这种情况发生,可以使用 Sweeping 来在移动物体时检测其沿路径上的碰撞。

Sweeping 的工作原理如下:

  • 当一个物体从一个位置移动到另一个位置时,Sweep 会检测这个物体在它移动路径上的所有位置,寻找任何可能与它发生碰撞的物体。
  • 如果在移动过程中检测到碰撞,Sweep 会返回详细的碰撞信息(如碰撞点、法线、碰撞的物体等)。
  • Sweep 还会将移动过程中的物体放置在碰撞位置之前,以避免穿透。

2. Sweep 的使用场景

  1. 角色移动:角色在行走时检测前方是否有障碍物,防止穿墙或穿地。
  2. 物体运动:检测移动物体(如子弹、飞行物体)是否与其他物体发生碰撞。
  3. 环境交互:例如,门在开关过程中,检测是否有物体挡住了门。

3. 使用 Sweep 的常见函数

Unreal Engine 提供了几种 Sweep 的方法和函数,以下是一些常用的方法:

3.1 AddActorWorldOffset

bool AActor::AddActorWorldOffset(FVector DeltaLocation, bool bSweep, FHitResult* OutHit, ETeleportType Teleport)

  • DeltaLocation:相对于当前世界位置的偏移量。
  • bSweep:如果为 true,则在移动时进行 Sweep 检测。
  • OutHit:如果发生碰撞,该结构体将存储碰撞的信息。
  • Teleport:是否瞬移而不触发事件。
示例:

FHitResult Hit; FVector MoveDelta = FVector(100, 0, 0); // 向前移动 100 单位 AddActorWorldOffset(MoveDelta, true, &Hit); if (Hit.IsValidBlockingHit()) { // 如果检测到碰撞,处理碰撞逻辑 UE_LOG(LogTemp, Warning, TEXT("Hit something: %s"), *Hit.GetActor()->GetName()); }

3.2 SetActorLocation
 

cpp

复制代码

bool AActor::SetActorLocation(FVector NewLocation, bool bSweep, FHitResult* OutHit, ETeleportType Teleport)

  • NewLocation:目标位置。
  • bSweep:如果为 true,在移动到新位置时进行 Sweep 检测。
  • OutHit:如果发生碰撞,该结构体将存储碰撞的信息。
  • Teleport:是否瞬移而不触发事件。
示例:

FHitResult Hit; FVector TargetLocation = GetActorLocation() + FVector(100, 0, 0); SetActorLocation(TargetLocation, true, &Hit); if (Hit.IsValidBlockingHit()) { // 如果检测到碰撞,处理碰撞逻辑 UE_LOG(LogTemp, Warning, TEXT("Hit something: %s"), *Hit.GetActor()->GetName()); }

3.3 SweepSingleByChannel

SweepSingleByChannel 是用于进行复杂碰撞检测的函数,它允许你指定一个通道来进行检测,并返回碰撞的详细信息。

bool UWorld::SweepSingleByChannel( FHitResult& OutHit, const FVector& Start, const FVector& End, const FQuat& Rot, ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam )

  • OutHit:存储碰撞的详细信息。
  • StartEnd:检测的起点和终点。
  • Rot:检测时使用的旋转。
  • TraceChannel:用于检测的碰撞通道。
  • CollisionShape:检测时使用的碰撞形状(如球体、盒子、胶囊体等)。
示例:

FHitResult Hit; FVector Start = GetActorLocation(); FVector End = Start + FVector(100, 0, 0); // 向前移动 100 单位 // 定义一个碰撞形状(球体) FCollisionShape CollisionShape; CollisionShape.SetSphere(50.0f); // 设置球体半径 // 执行 Sweep 检测 bool bHit = GetWorld()->SweepSingleByChannel( Hit, Start, End, FQuat::Identity, // 不旋转 ECC_Visibility, // 使用 Visibility 通道 CollisionShape ); if (bHit) { // 处理碰撞 UE_LOG(LogTemp, Warning, TEXT("Hit something: %s"), *Hit.GetActor()->GetName()); }

4. Sweep 检测的结果

Sweep 检测发生碰撞时,返回的 FHitResult 结构体会包含以下信息:

  • HitActor:碰撞到的物体。
  • ImpactPoint:碰撞发生的位置。
  • ImpactNormal:碰撞面的法线方向。
  • bBlockingHit:是否是阻挡性的碰撞。
  • Time:碰撞发生的时间(相对于移动的进程,0 到 1 之间的值)。

5. 使用 Sweep 的注意事项

  1. 碰撞体设置

    • 确保参与 Sweep 的物体有正确的碰撞体和碰撞通道设置。否则,Sweep 无法检测到碰撞。
  2. Sweep 的性能问题

    • Sweep 检测比简单的 SetActorLocation 更耗费性能,尤其是检测复杂形状时。因此在频繁调用 Sweep 时需要谨慎,避免性能下降。
  3. 旋转的影响

    • 如果物体在 Sweep 检测中包含旋转(如 SweepSingleByChannel 中的 FQuat),检测结果会受到影响,要注意检测方向和形状的关系。

6. 蓝图中使用 Sweep

在蓝图中,Sweep 相关节点通常用于检测物体移动过程中的碰撞:

  • Set Actor Location (Sweep):设置物体位置时进行 Sweep 检测。
  • Add Actor World Offset (Sweep):相对于当前位置移动物体时进行 Sweep 检测。

7. 总结

  • Sweep 是一种在物体移动时进行碰撞检测的方法,用于防止物体穿透其他物体。
  • 可以使用 SetActorLocationAddActorWorldOffsetSweepSingleByChannel 等函数进行 Sweep 检测。
  • 检测结果存储在 FHitResult 中,包含碰撞物体、碰撞位置、碰撞法线等信息。
  • 在使用 Sweep 时要注意碰撞体的设置和检测的通道,确保检测到需要的碰撞。

1. 碰撞体的设置

碰撞体(Collision Component)定义了物体的物理边界,用于检测物体之间的碰撞和重叠。常见的碰撞体组件有:

  • Box Component(盒体碰撞)
  • Sphere Component(球体碰撞)
  • Capsule Component(胶囊体碰撞)
  • Mesh Component(网格碰撞,可以是简单或复杂的网格形状)
1.1 在 C++ 中设置碰撞体

在 C++ 代码中,可以为 Actor 或 Component 设置碰撞体。以下是一个设置胶囊体碰撞的例子:

#include "Components/CapsuleComponent.h" // 在构造函数中创建并初始化碰撞体 AMyActor::AMyActor() { // 创建胶囊体碰撞组件 CapsuleComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComponent")); CapsuleComponent->InitCapsuleSize(42.f, 96.f); // 设置胶囊体半径和高度 CapsuleComponent->SetCollisionProfileName(TEXT("Pawn")); // 设置碰撞配置 // 将胶囊体设为根组件 RootComponent = CapsuleComponent; }

1.2 在蓝图中设置碰撞体
  1. 选择 Actor 或 Component

    • 打开需要设置碰撞体的 ActorComponent 蓝图。
    • Components 面板中选择需要设置碰撞的组件(例如 StaticMeshComponentBoxComponent 等)。
  2. 设置碰撞属性

    • Details 面板中,找到 Collision 分类。
    • 设置 Collision Presets 为适当的预设(例如 BlockAllOverlapAllNoCollision 等)。
    • 如果需要自定义碰撞,可以点击 Custom,然后单独设置 Collision EnabledObject TypeCollision Responses
  3. 调整碰撞体形状和大小

    • 对于基本碰撞组件(例如盒体、球体、胶囊体),可以在 Details 面板中设置它们的大小、半径和高度。
    • 对于网格组件(如 StaticMeshComponent),可以设置 Collision Complexity 来选择简单碰撞(使用基本形状)或复杂碰撞(使用网格的精确形状)。

2. 碰撞通道(Collision Channels)

碰撞通道定义了不同物体之间的碰撞响应关系。每个物体都有一个 Object Type 和一个 Collision Response,这决定了它与其他物体的交互方式。

2.1 Object Type(对象类型)

Object Type 定义了物体的类型,例如 WorldStaticWorldDynamicPawnVehicle 等。这些类型用于标识物体在碰撞检测中扮演的角色。

2.2 Collision Response(碰撞响应)

Collision Response 定义了物体对其他通道的反应方式,有以下几种响应类型:

  • Block(阻挡):物体将阻挡其他物体,并发生物理碰撞。
  • Overlap(重叠):物体将与其他物体重叠,但不会发生物理碰撞。
  • Ignore(忽略):物体将忽略其他物体,不会发生任何碰撞或重叠事件。
2.3 在 C++ 中设置碰撞通道

#include "Components/BoxComponent.h" // 在构造函数中创建并初始化碰撞体 AMyActor::AMyActor() { // 创建盒体碰撞组件 BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComponent")); BoxComponent->SetBoxExtent(FVector(50.f, 50.f, 50.f)); // 设置盒体大小 // 设置碰撞响应配置 BoxComponent->SetCollisionProfileName(TEXT("Custom")); BoxComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); // 启用碰撞检测和物理模拟 BoxComponent->SetCollisionObjectType(ECC_WorldDynamic); // 设置对象类型为动态物体 // 设置不同通道的碰撞响应 BoxComponent->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block); // 对静态物体阻挡 BoxComponent->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); // 对 Pawn 重叠 BoxComponent->SetCollisionResponseToAllChannels(ECR_Ignore); // 对所有其他通道忽略 RootComponent = BoxComponent; }

4. 检测通道的使用

在进行 Line TraceSweepOverlap 检测时,可以指定使用的检测通道(Trace ChannelCollision Channel),以便只检测特定类型的物体。

4.1 Line Trace 的使用

FHitResult HitResult; FVector Start = GetActorLocation(); FVector End = Start + FVector(1000, 0, 0); // 线段终点 FCollisionQueryParams Params; Params.AddIgnoredActor(this); // 忽略自己 // 使用 Visibility 通道进行检测 bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, Params); if (bHit) { UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName()); }

4.2 Sweep 的使用

FHitResult HitResult; FVector Start = GetActorLocation(); FVector End = Start + FVector(500, 0, 0); // 终点 FCollisionShape CollisionShape; CollisionShape.SetSphere(50.0f); // 设置碰撞形状(球体) // 使用 PhysicsBody 通道进行 Sweep 检测 bool bHit = GetWorld()->SweepSingleByChannel(HitResult, Start, End, FQuat::Identity, ECC_PhysicsBody, CollisionShape); if (bHit) { UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName()); }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值