【UE4】基于Spline的测距功能

基于Spline的测距功能插件

一、功能分析

这里首先分析一下整个插件的功能部件

  • SplineActor—基于Spline的线条显示模块

  • Ranging—对整个插件功能的整体控制

  • DistancePanel—距离显示UI

  • Point—线上的点,集成DistancePanel

  • FunLib—高复用函数集合

    资产状况:

    在这里插入图片描述

由于使用屏幕坐标转世界坐标的方式实现测距功能可能及其复杂,所以这里使用比较直观简便的三维Spline来实现测距功能。

二、制作线上的点Point

1.Point的结构分析

Point是一个拥有StaticMesh和WedgitComponent组件的Actor,StaticMesh我这里使用Shape,Materials是自己做的一个发光材质。

在这里插入图片描述

2.MeshMeterial材质

Materials蓝图:

在这里插入图片描述

3.Point核心函数实现

Point主要实现一个函数两个事件

  • 函数ShowDistance—负责距离显示
  • 事件InitFontInfo—负责获取初始字体信息
  • 事件ShowText—控制距离是否显示

在构造函数需要记录DistancePanel的初始位置信息和初始字体信息。

ConstructScript:记录DistancePanel的初始位置信息和初始字体信息

在这里插入图片描述

InitFontInfo:记录字体的初始信息

在这里插入图片描述

ShowText:设置显示字体的大小。

在这里插入图片描述

Tick函数:SetActorRotation设置点上的文字跟随摄像机旋转使之始终面向摄像机,GetMouseLocation->SetActorLocation->ShowText当SureLocation为false时即未确定点的位置时设置点跟随鼠标移动,当点跟随鼠标移动时不显示距离。

在这里插入图片描述

  • FontInfo:是一个SlateFontInfoStructure结构体用于设置距离显示的字体样式。
  • SureLocation:bool变量,确认点是否已经确定了位置坐标,当点没有确定位置坐标时,点将跟随鼠标移动。
  • InitScale3D:Vector变量,保存DistancePanel的初始大小。
  • SureAdsorb:bool变量,控制闭环吸附,当为true时,起点具有吸附功能,可以将终点吸附到起点位置实现闭环。

ShowDistance:将输入的距离信息显示出来。

在这里插入图片描述

至此点的设计完毕。

三、用于显示的Widget

创建一个UserWidget命名为DistancePanel,DistancePanel比较简单,CanvasPanel下就一个Text即可,只有一个函数UpdateTextScale,然后在EventConstruct中记录Text的初始大小。

EventConstruct:

在这里插入图片描述

UpdateTextScale:更新Text的大小,使Text跟随摄像机距离地板的远近变大变小,以保证Text的大小在视野中保持不变。

在这里插入图片描述

三、使用Spline制作线段

1.SplineActor结构分析

Spline是UE4的样条线组件,Spline是一组点和线的集合,但是Spline的点和线只有在编辑模式下可见,在运行模式下不可见,Spline可以通过选中其中的点按下Alt键并拖动鼠标来添加新的点。

我们需要一个Actor作为Spline的载体,创建一个Actor命名为Spline。Spline的组件结构为:

在这里插入图片描述

  • StaticMesh:使用Shape和自定义的材质,这个Mesh作为起点使用。
  • Spline:样条线组件,此Actor的核心组件。
  • Sphere:球型触发器,用于起点吸附。

2.在编辑模式下实现Spline编辑

在编辑模式下实现样条线的编辑需要在构造函数中实现下面的逻辑:

在这里插入图片描述

核心函数分析:

  • AddSplineMeshComponent:这是一个自定义的封装函数,作用就是提高复用率,

    在这里插入图片描述

StaticMesh决定线的样式,Meterial决定线的颜色;

  • AttachToMeshComponent:将添加的SplineMeshComponent组件设置StaticMesh为父节点;

  • Set Start and End:函数根据Get LocationandTangentatSplinePoint函数获取的起点和终点的位置和切角,将生成的SplineMeshComponent组件附着在上面。

这样我们的Spline样条线就被设置成了我们设定的模样,并且在运行时可见。

在这里插入图片描述

3.运行时动态添加Spline的点

由于在运行模式下无法像在编辑模式下通过Alt键拖动点来添加Spline的点,所以我们需要通过蓝图来实现。这项功能封装在AddPoint函数中。

在这里插入图片描述

AddPoint函数通过输入的坐标位置动态生成Spline的点

  • AddSplinePoint:向Spline中添加新的点;
  • SpawnActorPoint:目的是在Spline的生成的新点的位置处生成一个具象化的Point;
  • Sequence的的Then0分支作用是当生成一个新的Point时,确定上一个Point的位置坐标;
  • PointArray是一个Point类型的数组,用于存储生成的Point的引用,SplineMeshComponentArray是一个SplineMeshComponent类型的数组,用于存储生成的SplineMeshComponent组件的引用,两个数组的作用是方便之后对Point和SplineMeshComponent的操作。
  • AddSplineMeshComponent、AttachToComponent和SetSartandEnd函数作用和构造函数中一样;
  • UpddateTotaldistance函数用于更新距离显示,具体实现在后面介绍。

AddPoint函数在AddPointEvent事件中调用。

在这里插入图片描述

  • GetMouseLocation是FunLib库中的一个函数负责获取鼠标坐在的屏幕坐标转换成空间坐标。

在这里插入图片描述

4.实时更新样条线

实时更新样条线的功能封装在UpdateCurrentSplinePoint函数中。

在这里插入图片描述

UpdateCurrentSplinePoint函数在SplineActor的Tick函数中调用,每帧删除前一个Spline的点,在新的坐标位置下添加一个新的Spline的点,由于Point是跟随鼠标移动的,所以通过这个操作在宏观上的表现就是Spline的点在跟随鼠标一点,之所以使用这种方式,是因为Spline中的点似乎没办法直接修改位置。

每帧设置好位置之后再重新渲染一遍Mesh组件,就达到如下效果了:

在这里插入图片描述

这样在运行状态下编辑Spline样条线就制作完成了。

四、实时更新距离

实时更新距离的功能封装在UpdateTotalDistance函数下。

在这里插入图片描述

  • Ranging变量就是Ranging类型,存储Ranging的引用,在重新计算总距离前先将存储中距离的变量TotalDistance清零;
  • 然后一次取PointArray中的Point来计算Point与Point之间的距离,0号索引的Point较为特殊需要与其他索引的Point分开计算,因为0号索引的Point需要与SplineActor的位置计算距离;
  • ShowDistance函数封装在Point类中,负责将输入的距离显示出来。

显示总距离专门创建了一个DistancePanel来显示。

在这里插入图片描述

在这里插入图片描述

  • HiddenTotalDistance控制总距离是否显示。

到这里基本的功能就基本实现了,下面实现一些必要的附加功能。

五、封装Ranging类

由于SplineActor类是插件的核心类,不宜对外开放调用接口,且SplineActor类自身拥有Mesh,直接拖入场景中会显示Mesh,效果不佳,所以在SplineActor之外再封装一成没有Mesh的Ranging是十分必要的,有Ranging类提供对外调用的接口。

Ranging类的封装函数和变量:
在这里插入图片描述

  • SetupRanging:启动测距,在鼠标所在位置生成SplineActor;

    在这里插入图片描述

  • AddPoint:封装SplineActor中的AddPointEvent事件;

在这里插入图片描述

  • EndRanging:结束测距,封装ActorSpline的DeleteLastPoint函数,函数的具体实现在之后介绍;

在这里插入图片描述

  • Remove:删除所有的点线,封装SplineActor的RemoveAllPoint函数,函数的具体实现在之后介绍;

    在这里插入图片描述

  • SplineActor:存储SplineActor的引用;

  • TotalDistance:存储总距离的值;

  • DistanceUint:显示总距离时的单位;

  • K:存储SplineActor中DistancePanel随相机距离变化大小的变化倍率;我这里设定的值为0.0002。

文字随相机距离变化的函数实现封装在Ranging的UpdeteDistancePanelScale事件中,事件在Ranging的Tick函数中调用。

在这里插入图片描述

六、保持Point的DistancePanel组件的大小不变

为了保证观感效果,Point的显示距离的DistancePanel组件的大小应该跟随相机的远近保持保持一定的大小,以保证相机贴近地面时,文字不会过大,相机原理地面时文字不过过小而看不见。

实现原理就在Ranging的UpdateDistancePanelScale事件中。

七、返回上一步功能

当我们确定点的位置时会出现位置确定错误的情况,所以返回上一步的功能也是十分必要的,具体实现在SplineActor的DeleteLastPoint函数中。

在这里插入图片描述

原理是移除上一个Spline的点和其匹配的Point、SplineMeshComponent并删除数组中对应的元素,然后更新一次距离,如果剩下最后一个点时,再撤回就直接将SplineActor删除并把显示总距离的DistancePanel移除,防止再创建SplineActor时再生成一个DiatancePanel而出现两个DistancePanel。

八、移除所有的点

当测距完成后需要清除所有的点,所以此功能也是必要的,具体实现在SplineActor的RemoveAllPoint中。

在这里插入图片描述

九、起点吸附功能

起点吸附是为了实现闭环。具体实现在SplineActor的EventActorBeginOverlap事件中。

在这里插入图片描述

原理就是当SplineActor的Sphere触发器检测到Point时将此Point的坐标设置到起点的坐标处。

九、整体效果预览

在这里插入图片描述