我的专栏目录:
小IVan:专题概述及目录![图标](https://i-blog.csdnimg.cn/blog_migrate/d6ea8e09530a242b2ee5802be9b6a242.png)
先上效果吧:
![v2-ce8e1d330589a959109e5486f21775b5_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/4a3edb8cc0b989b42cc5521115b2dd30.jpeg)
![v2-04fa4919ac70baab002b78ecfedafce0_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/9ff9d9f6b6095d62d41a15b051b852a4.jpeg)
我们有一个工具界面,和一项具体的生成功能,逻辑是在EditorTime中完成的
如果是在构造函数中做生成逻辑有几大缺点:
(1)生成是在构造函数执行的,虽然只在物体构建的时候才执行,但是还是有一次消耗。
(2)需要控制构造顺序,假设藤蔓2的位置和藤蔓1的位置是有关系的且相互影响,上面那个解决方案就无法实现了。
而我的方案完美解决了这两个问题,因为我把构造逻辑放到了EditorTime里,这样,藤蔓在Runtime的时候使用的就是静态数据了。
首先我们需要写个工具,来把Spline的计算放到EditorTime去,这样Runtime使用的就是静态数据了。
![v2-50fd0a98cdf688a556f522a2c10646fd_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/bdb45ed1bdb838f3984f5db59ab8b516.jpeg)
首先来捋一下步骤
(1)首先我们要有一个特殊的类,来给我们的工具来操作
(2)我们需要有一个操作这个类型的物体的工具
(3)我们需要完成这个工具操作这个特殊类的方法
第一步我们先从Actor派生一个类出来
![v2-078a5ca7517346448ed3f8c9a8824a9b_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/72a637575c9beea4f1db9060117e11e9.jpeg)
![v2-ff191e379f8b83266dfde7227194534c_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/81d59ad8432dd3ddb0d2fa63daa81ded.jpeg)
这个类里面有个splinecomponent,但是我们人工操作它并且拖拽SplinePoint太麻烦,所以我们用工具来生成spline的这些点
第二步:
是我们的工具类(下面是工具类头文件)
![v2-e3bba1eeb12e57e277db161185cdfe30_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/369cfdd3ff9c813ef395d6e7d3c57612.jpeg)
一部分是我们工具的按钮,一部分是工具需要的方法
首先在construct函数中画出我们的工具UI
![v2-a4d5b6bf6836adbc0d17dd3932affd90_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/814668e9f2d4b5c6a99d8551ca68b87d.jpeg)
void SRoadTool::Construct(const FArguments& InArgs)
{
ChildSlot
[
SNew(SVerticalBox)
//-------------------------------------------//
+ SVerticalBox::Slot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(SBox)
.HeightOverride(20.0f)
.WidthOverride(120.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("TextDefaultValue0", "SplinePointNum :"))
]
]
+ SHorizontalBox::Slot()
[
SNew(SBox)
.HeightOverride(20.0f)
.WidthOverride(60.0f)
[
SNew(SSpinBox<int32>)
.MaxValue(100)
.MinValue(0)
.OnValueChanged(this, &SRoadTool::OnSliderChanged)
]
]
]
//-------------------------------------------//
+ SVerticalBox::Slot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(SBox)
.HeightOverride(20.0f)
.WidthOverride(60.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("TextDefaultValue1", "SplineSecLength :"))
]
]
+ SHorizontalBox::Slot()
[
SNew(SSpinBox<float>)
.MaxValue(200.0f)
.MinValue(0)
.OnValueChanged(this, &SRoadTool::OnSliderSecLengthChanged)
]
]
//-------------------------------------------//
+ SVerticalBox::Slot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
SNew(SBox)
.HeightOverride(20.0f)
.WidthOverride(120.0f)
[
SAssignNew(ButtonPtr, SButton)
.OnClicked(this, &SRoadTool::OnButtonClicked)
.Text(LOCTEXT("Test", "GenerateSpline"))
]
]
+ SHorizontalBox::Slot()
[
SNew(SBox)
.HeightOverride(20.0f)
.WidthOverride(120.0f)
[
SAssignNew(ButtonPtr, SButton)
.OnClicked(this, &SRoadTool::OnResetSplineButtonClicked)
.Text(LOCTEXT("Test2", "ResetSpline"))
]
]
]
//---------------------------------------------//
];
}
然后是实现绑定按钮的点击的回调函数
![v2-2413045817658064cb2e0be950e61ab0_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/1a5bc5ed2b07925e8d0e7730ae81fafd.jpeg)
![v2-21693ab42a95b54e784dc7821aad555b_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/988e76be1afbdb1b3904df362765b389.jpeg)
第三步:
完成工具类的功能性函数
void SRoadTool::GenerateSpline()
{
for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It)
{
AActor* Actor = Cast<AActor>(*It);
Actor->Modify();
ARoad* road = Cast<ARoad>(Actor);
if (road == nullptr) return;
if (road->RoadPoints.Num() < 1) return;
//find the first point of spline
FHitResult hitresult;
RayTracingHit(road->GetActorLocation(), FVector(0, 0, -1), 100.0f, hitresult, road);
road->RoadPoints[0] = hitresult.ImpactPoint;
FVector LastPointLoc = hitresult.ImpactPoint;
FVector RayStart = hitresult.ImpactPoint;
FVector LastRayHitNorm = hitresult.ImpactNormal;
for (int32 i = 1; i < road->RoadPoints.Num(); i++)
{
FVector ForwardVec = FVector::CrossProduct(road->GetActorRightVector(), LastRayHitNorm);
RayStart = ForwardVec * RoadSecLength + LastPointLoc + LastRayHitNorm * 50;
bool bHit = RayTracingHit(RayStart, -LastRayHitNorm, 100.0f, hitresult, road);
if (bHit == false)
{
RayTracingHit_Sphere(LastPointLoc, -LastRayHitNorm, 100.0f, hitresult, road);
}
road->RoadPoints[i] = hitresult.ImpactPoint;
LastPointLoc = hitresult.ImpactPoint;
LastRayHitNorm = hitresult.ImpactNormal;
}
road->GetRoadSpline()->SetSplinePoints(road->RoadPoints, ESplineCoordinateSpace::World, true);
}
}
![v2-85a1eba2a69c27497e0a0350df05b2f7_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/b42ca2f60267bbe4fc891921c33ea1be.png)
我们用射线检测场景的情况然后把点布上去即可。这样我们就完成了在EditorTime的计算,RunTime的时候使用的是EditorTime的静态数据。
Enjoy it!