UE4 简单记录EQS的使用方法

介绍

EQS环境查询 主要是用来从场景环境中获得你想要的满足指定条件的数据,主要是和AI行为树配合使用, 比如获得获得玩家距离最近的位置等等
详细的官网文档 链接

下面是简单的使用方法,目的是寻找一个点,这个点是不被玩家看到,并且距离玩家最近的点

准备

使用EQS需要在EditorSetting中实验功能中开启EQS
在df

步骤
  1. 创建EQS资源
    在这里插入图片描述
  2. 使用Points:Grid 可以生成点阵位置,从中筛选出我们想要的位置(如果对寻找的位置有特殊的需求,也可以自己在c++中重载UEnvQueryGenerator,参考现有的SimpleGrid等

在这里插入图片描述
3. 点击Generate 在右侧的属性中介绍主要几个, 详细的可以参考官方文档
GridHalfSize:环境的范围
SpaceBetween:寻找到的点的间隔
GenerateAround:寻找范围的中心点,默认是运行行为树的ai位置,也可以通过添加继承自EnvQueryContextBlueprintBase,重载其中的Provide SingleActor,返回你想要的actor
在这里插入图片描述
4. 在Generator上右键添加Test,Test分为两类,一种是过滤掉不合适的位置,还有一类是根据条件给不同的位置打分,便于比较不同位置的权重,比如你想要的最远或者最近,下面添加的三个目的分别是 寻找点存在可以抵达玩家位置路径,过滤掉可以看见玩家的位置,距离玩家越近得分越高
在这里插入图片描述
这里说一下Test中通用的几项属性
Test Purpose:使用Filter过滤还是Score打分
Context: 设置目标对象,我这里是EQCContext_Player,自定义的EnvQueryContextBlueprintBase类,返回的是当前的玩家,你也可以自由修改返回的对象
BoolMatch:设置是否满足test条件,简单的说比如使用trace Test,TestPurpse设置为FiterOnly,那么为true的情况,就是代表过滤掉能被玩家看见的位置,false的话就是过滤掉不能被玩家看见的位置
ScoringFactor:作用和上面的差不多,为1的话,那么距离玩家越远,得分权重越高,设置为-1的话,离玩家越近得分权重越高

  1. 在行为树种使用EQS
    在这里插入图片描述
    使用RunEQSQuery,这里要注意右侧一个是BlackboardKey,这里要现在黑板中定义一个Vector类型的键,用来存储我们使用EQS的到的点,还有就是Query Template使用我们刚才创建的EQS资源,还有一个RunMode 默认的话是返回得分权重最高的点,你也可以修改返回其他类型。
测试

上面这些做完基本上就是全部内容了,接下来就是如何方便的观察我们的EQS获得点的权重情况,就是在我们的场景中拖一个EQSTestingPawn用来模拟在改Pawn的位置上使用EQS
在这里插入图片描述
这里要注意需要将TestPawn的Query Template设置为EQS资源
结果就显示出来了,这里说一下 蓝色代表的就是过滤掉的点,参考我们之前的设置,可以看出来蓝色都是可以被左侧玩家看见的位置,所以需要过滤掉,绿色代表得分权重高,红色代表得分权重低,我们这里就是距离玩家越近,得分越高为绿色,距离玩家越远,得分越低为红色

<think>好的,用户的问题是关于在UE5中如何让同一类的多个Actor在随机位置生成,并且每个位置只能生成一个。我需要先理解用户的具体需求。用户可能是在开发游戏时,想要在场景中随机生成道具,比如宝箱、物品等,但又不希望它们重叠在一起,确保每个位置只有一个实例。这个问题涉及到UE5中的生成系统和位置随机化的方法。 首先,我应该考虑UE5中常用的生成Actor的方法,比如使用Spawn Actor from Class节点。然后,如何生成随机位置?通常可以使用导航网格(NavMesh)来获取可行走的位置,或者使用体积(Volume)来定义生成区域。用户可能需要一个可移动的生成点,或者固定的几个点中随机选择。 但用户提到的是“指定几个相同类的actor”,可能是指多个属于同一类的Actor需要被生成在不同的位置。这里的关键是确保每个生成的位置唯一,不会重复。可能的解决方案包括: 1. 预先定义一组生成点,然后从中随机选择,每次选择后移除该点,避免重复使用。这适用于固定数量的生成位置。 2. 使用算法在运行时动态生成随机位置,并检查该位置是否已经被占用,或者与其他Actor的位置保持一定距离。这可能需要碰撞检测或空间划分的方法,如使用Grid来划分区域,随机选择格子,然后在该格子内随机生成位置。 对于第一种方法,可以使用数组来存储所有可用的生成点,每次随机选择一个,然后从数组中移除,确保下次不会选到同一个。例如,使用一个SpawnPoint数组,每次生成时随机索引,取出后删除该索引的元素。 对于第二种方法,可能需要使用BoxExtent或Sphere生成随机点,然后使用Overlap检查来判断该位置是否已经有其他Actor存在。如果存在,则重新生成,直到找到可用位置。不过这种方法在密集区域可能会有性能问题,尤其是在生成大量Actor时。 另外,UE5中的EQS(环境查询系统)可能也是一个好的解决方案,它可以根据多种条件生成适合的位置,并避免重叠。不过EQS的学习曲线可能较高,对于新手来说可能需要更多步骤。 用户可能需要一个简单且高效的解决方案,不需要复杂的系统。因此,使用预设的生成点数组可能更直接。或者,使用一个体积(如Box Volume)来随机生成位置,并记录已生成的位置,每次生成时检查距离是否过近。 还需要考虑生成位置的正确性,比如是否在地面以上,是否需要对齐地面等。可能需要使用射线检测来确保生成的位置在场景表面上。 总结可能的步骤: 1. 创建生成点数组或定义生成区域。 2. 随机选择一个位置。 3. 检查该位置是否已被占用或与其他位置保持最小距离。 4. 如果有效,生成Actor并记录该位置。 5. 重复直到生成所需数量或没有可用位置。 需要确保逻辑正确,避免无限循环,尤其是在无法找到有效位置时要有终止条件。此外,性能方面也要考虑,尤其是在大量生成时,检查方法是否高效。 可能还需要使用蓝图或C++实现,但用户可能更倾向于蓝图方案。最后,给出具体的步骤和节点,帮助用户一步步实现。</think>在UE5中,让同类Actor随机生成且不重叠的位置可通过以下步骤实现: --- ### 一、核心思路 1. **预设位置池**:先创建一组候选生成点 2. **随机选择+移除**:每次随机选点后从池中移除该点 3. **动态检测**:或通过物理检测确保生成位置无碰撞 --- ### 二、方法1:预设点位池(推荐新手) #### 步骤实现: 1. **创建生成点数组** - 在场景中放置多个`Empty Actor`作为候选点位 - 在生成控制器蓝图中创建变量: ```cpp TArray<AActor*> SpawnPoints // 存储所有预设点 TArray<AActor*> AvailablePoints // 当前可用点位 ``` 2. **初始化点位池** ```cpp // 在BeginPlay事件中: GetAllActorsOfClass(EmptyActorClass, SpawnPoints) // 收集所有预设点 AvailablePoints = SpawnPoints // 复制初始点位 ``` 3. **随机生成逻辑** ```cpp // 每次生成时执行: if (AvailablePoints.Num() > 0) { int32 RandomIndex = FMath::RandRange(0, AvailablePoints.Num()-1); FVector SpawnLocation = AvailablePoints[RandomIndex]->GetActorLocation(); AvailablePoints.RemoveAt(RandomIndex); // 关键:移除已用点位 SpawnActor(YourActorClass, SpawnLocation); } ``` --- ### 三、方法2:动态生成+碰撞检测(适合自由区域) #### 步骤实现: 1. **定义生成区域** - 在场景中添加`Box Collision`组件定义生成范围 2. **生成随机坐标** ```cpp FVector GetRandomPointInBox(UBoxComponent* Box) { FVector Origin = Box->GetComponentLocation(); FVector Extent = Box->GetScaledBoxExtent(); return FMath::RandPointInBox(FBox(Origin - Extent, Origin + Extent)); } ``` 3. **防止重叠检测** ```cpp bool IsLocationValid(FVector Location) { TArray<FOverlapResult> Overlaps; FCollisionQueryParams Params; GetWorld()->OverlapMultiByChannel( Overlaps, Location, FQuat::Identity, ECC_WorldStatic, // 根据需求选择检测通道 FCollisionShape::MakeSphere(50.0f), // 检测半径 Params ); return Overlaps.Num() == 0; } ``` 4. **安全生成循环** ```cpp void SafeSpawn() { for(int i=0; i<MaxAttempts; i++) // 避免无限循环 { FVector CandidateLoc = GetRandomPointInBox(YourBoxComponent); if(IsLocationValid(CandidateLoc)) { SpawnActor(YourActorClass, CandidateLoc); break; } } } ``` --- ### 四、优化建议 1. **地面吸附**:生成后执行射线检测确保接触地面 ```cpp FHitResult HitResult; if(GetWorld()->LineTraceSingleByChannel(HitResult, CandidateLoc + FVector(0,0,1000), CandidateLoc - FVector(0,0,1000), ECC_Visibility)) { CandidateLoc.Z = HitResult.Location.Z + HeightOffset; } ``` 2. **可视化调试**:在编辑器中用`DrawDebugSphere`显示已生成点 3. **对象池管理**:对高频生成需求,建议使用对象池预先创建实例 --- ### 五、最终选择建议 - 固定场景布局 → 选择**方法1**(性能更优) - 开放随机区域 → 选择**方法2**(更灵活) - 大规模生成需求 → 推荐结合EQS系统实现智能寻点
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值