原文地址:https://www.cnblogs.com/LynnVon/p/11804286.html

在上一篇文章基本已经将如何做runtime landscape写完了  但后来发现 频繁的生成和删除组件会造成主线程卡顿 而因为要操作gameobject 所以不能异步  经过一番思考 决定 不生成和删除组件  而是改为移动组件

将本来删除的组件移动到要增加的位置  只需要改变位置就可以了

在改变landscapecomponent位置时  要设置为movable   但是设置为movable后landscape就不见了 ,所以只在setrelativetransform时改为movable,设置完位置后再改为static就行了

// RuntimeGenerateTerrain.h
#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "FS_ImageLoader.h"

#include "RuntimeGenerateTerrain.generated.h"

class ALandscapeProxy;
class UMaterialInstanceDynamic;
class UMaterialInstance;
class ULandscapeComponent;

#define LANDSCAPESIZE 31


DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnLandscapeGenerateComplete);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FLIGHTSIM_API URuntimeGenerateTerrain : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	URuntimeGenerateTerrain();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const;

	void StartGenerate();

	void InitLandscapeComponent();

	bool LoadTexture(ULandscapeComponent* C);
	bool AsyncLoadTexture(ULandscapeComponent* C);

	void MoveLandscapeComponent();
	void RemoveLandscapeComponent();
	void UpdateLeftAndRightPoint();

	void SetXYtoComponentMap(ULandscapeComponent* C);
	void RemoveXYtoComponentMap(ULandscapeComponent* C);

	void StartAddComponent();

	void StopAddComponent();

	void CalComponentIndex();

	void ResetComponentIndex();

	int GetComponentIndexX(ULandscapeComponent* C);
	int GetComponentIndexY(ULandscapeComponent* C);
	UFUNCTION()
	void LoadTextureComplete(UTexture2D* texture);



public:
	ALandscapeProxy* mLandscape = nullptr;

	UMaterialInstanceDynamic* GI;
	UMaterialInstance* SounceMaterial;
	TMap<FIntPoint, ULandscapeComponent*> mXYtoComponentMap;

	UPROPERTY(EditAnywhere,BlueprintReadWrite)
	FString MapFileName = FString();

	FOnLandscapeGenerateComplete OnLandscapeGenerateComplete;

private:
	bool bAddComponent:1;
	int ComponentIndexX1 = -1;
	int ComponentIndexY1 = -1;
	int ComponentIndexX2 = -1;
	int ComponentIndexY2 = -1;
	FVector ForeLocation = FVector::ZeroVector;
	FVector2D LeftBottom = FVector2D(0,0);
	FVector2D RightTop = FVector2D(LANDSCAPESIZE,LANDSCAPESIZE);

	TArray<ULandscapeComponent*> DeleteComponents;
	TArray<ULandscapeComponent*> ReadyForTextureMID;

	




};

  

  1
  2 /*!
  3  * file RuntimeGenerateTerrain.cpp
  4  *
  5  * author Hailiang Feng
  6  * date 2019/11/01 9:45
  7  *
  8  *
  9  */
 10 #include "RuntimeGenerateTerrain.h"
 11 #include "Kismet/GameplayStatics.h"
 12 #include "LandscapeComponent.h"
 13 #include "LandscapeInfo.h"
 14 #include "LandscapeProxy.h"
 15 #include "EngineUtils.h"
 16 #include "Materials/MaterialInstanceConstant.h"
 17 #include "RenderingThread.h"
 18 #include "FS_Utils.h"
 19 #include "Components/TextRenderComponent.h"
 20 #include "LandscapeInfoMap.h"
 21 #include "Guid.h"
 22 #include "LandscapeHeightfieldCollisionComponent.h"
 23 #include "UnrealMathUtility.h"
 24 #include "Async.h"
 25 #include "FS_ImageLoader.h"
 26 
 27 
 28  // Sets default values for this component's properties
 29 URuntimeGenerateTerrain::URuntimeGenerateTerrain()
 30 {
 31     // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
 32     // off to improve performance if you don't need them.
 33     PrimaryComponentTick.bCanEverTick = true;
 34     bReplicates = true;
 35     bAddComponent = false;
 36     // ...
 37     static ConstructorHelpers::FObjectFinder<UMaterialInstance> _material(TEXT("MaterialInstanceConstant'/Game/FlightSim/material/M_GoogleBASE_Inst.M_GoogleBASE_Inst'"));
 38     if (_material.Succeeded())
 39     {
 40         SounceMaterial = _material.Object;
 41     }
 42 
 43 }
 44 
 45 // Called when the game starts
 46 void URuntimeGenerateTerrain::BeginPlay()
 47 {
 48     Super::BeginPlay();
 49 
 50     StartGenerate();
 51 }
 52 
 53 // Called every frame
 54 void URuntimeGenerateTerrain::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
 55 {
 56     Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
 57 
 58     // ...    
 59     
 60     if (!mLandscape)return;
 61     CalComponentIndex();
 62     if (bAddComponent)
 63     {
 64         StopAddComponent();
 65         RemoveLandscapeComponent();
 66         MoveLandscapeComponent();
 67 
 68     }
 69 }
 70 
 71 void URuntimeGenerateTerrain::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
 72 {
 73 }
 74 
 75 void URuntimeGenerateTerrain::StartGenerate()
 76 {
 77     GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Red, FString("Runtime Landscape Generate Start"));
 78     UE_LOG(LogFlightSim, Log, TEXT("Runtime Landscape Generate Start"));
 79 
 80     FString levelName = UGameplayStatics::GetCurrentLevelName(this);
 81     if (levelName.Equals(FString("Level_China")))
 82     {
 83         MapFileName = FString("FileName_China");
 84         MapFileName = FString("Texture2D'/Game/GoogleMap/ChinaImage1/");
 85     }
 86     if (levelName.Equals(FString("Level_Farm")))
 87     {
 88         MapFileName = FString("Texture2D'/Game/GoogleMap/Level_Farm/");
 89     }
 90 
 91     // ...
 92     UWorld* world = GetWorld();
 93     check(world);
 94     TArray<AActor*> _actor;
 95     UGameplayStatics::GetAllActorsOfClass(GetWorld(), ALandscapeProxy::StaticClass(), _actor);
 96     if (_actor.Num() > 0)
 97     {
 98         mLandscape = (ALandscapeProxy*)_actor[0];
 99     }
100     if (mLandscape)
101     {
102         mLandscape->LandscapeMaterial = SounceMaterial;
103         mLandscape->bUseDynamicMaterialInstance = true;
104         for (ULandscapeComponent* C : mLandscape->LandscapeComponents)
105         {
106             LoadTexture(C);
107             SetXYtoComponentMap(C);
108         }
109 
110     }
111     if (OnLandscapeGenerateComplete.IsBound())
112     {
113         OnLandscapeGenerateComplete.Broadcast();
114     }
115 
116 }
117 
118 bool URuntimeGenerateTerrain::LoadTexture(ULandscapeComponent* C)
119 {
120     //GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,FString("RuntimeGenerateTerrain LoadTexture"));
121 
122     for (int i = 0; i < C->MaterialInstancesDynamic.Num(); i++)
123     {
124         UMaterialInstanceDynamic* MID = C->MaterialInstancesDynamic[i];
125         int XIndex = GetComponentIndexY(C);
126         int YIndex = GetComponentIndexX(C);
127 
128 
129         //FString _fileName = UFS_Utils::GetTerrainConfigSection(MapFileName);
130         FString _fileName = MapFileName;
131 
132         /*  GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,FString("FileNameSection = ")+MapFileName+FString("---Filename=")+_fileName);
133           if (_fileName.IsEmpty())
134           {
135               _fileName = FString("Texture2D'/Game/GoogleMap/ChinaImage1/");
136           }*/
137           /*int rowOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("rowOffset")));
138           int columnOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("columnOffset")));*/
139         int rowOffset = 1;
140         int columnOffset = 1;
141         _fileName.Append(FString::FromInt(XIndex + rowOffset));
142         _fileName.Append(FString("/"));
143         _fileName.Append(FString::FromInt(YIndex + columnOffset));
144         _fileName.Append(FString("."));
145         _fileName.Append(FString::FromInt(YIndex + columnOffset));
146         _fileName.Append(FString("'"));
147         UTexture2D* texture = LoadObject<UTexture2D>(NULL, *_fileName);
148         if (texture)
149         {
150             MID->SetTextureParameterValue(FName("Texture"), texture);
151         }
152         else
153         {
154             return false;
155         }
156     }
157     return true;
158 
159 }
160 
161 bool URuntimeGenerateTerrain::AsyncLoadTexture(ULandscapeComponent* C)
162 {
163 
164     ReadyForTextureMID.Add(C);
165 
166     for (int i = 0; i < C->MaterialInstancesDynamic.Num(); i++)
167     {
168         UMaterialInstanceDynamic* MID = C->MaterialInstancesDynamic[i];
169         int XIndex = GetComponentIndexX(C);
170         int YIndex = GetComponentIndexY(C);
171         FIntPoint ComponentIndex = FIntPoint(XIndex, YIndex);
172         FString _fileName = FString("H:/MapDownload/FlightMap/googlemaps/Terrain_1/18/");
173         int rowOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("rowOffset")));
174         int columnOffset = FCString::Atoi(*UFS_Utils::GetTerrainConfigSection(FString("columnOffset")));
175         _fileName.Append(FString::FromInt(XIndex + rowOffset));
176         _fileName.Append(FString("/"));
177         _fileName.Append(FString::FromInt(YIndex + columnOffset));
178         _fileName.Append(FString("."));
179         _fileName.Append(FString::FromInt(YIndex + columnOffset));
180         _fileName.Append(FString("'"));
181         _fileName = FString("C:/MapDownload/test/12.jpg");
182 
183 
184         UFS_ImageLoader* loader = UFS_ImageLoader::LoadImageFromDiskAsync(this, _fileName);
185         if (loader)
186         {
187             loader->OnLoadCompleted().AddDynamic(this, &URuntimeGenerateTerrain::LoadTextureComplete);
188         }
189     }
190     return true;
191 }
192 
193 void URuntimeGenerateTerrain::MoveLandscapeComponent()
194 {
195     ReadyForTextureMID.Empty();
196 
197     for (int32 ComponentIndexY = ComponentIndexY1; ComponentIndexY <= ComponentIndexY2; ComponentIndexY++)
198     {
199         for (int32 ComponentIndexX = ComponentIndexX1; ComponentIndexX <= ComponentIndexX2; ComponentIndexX++)
200         {
201             ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY));
202             if (!LandscapeComponent)
203             {
204                 // Add New component...
205                 FIntPoint ComponentBase = FIntPoint(ComponentIndexX, ComponentIndexY)*mLandscape->ComponentSizeQuads;
206 
207                 if (DeleteComponents.Num() > 0)
208                 {
209                     LandscapeComponent = DeleteComponents.Top();
210                     LandscapeComponent->SetMobility(EComponentMobility::Movable);
211                     LandscapeComponent->SetRelativeLocation(FVector(ComponentBase.X, ComponentBase.Y, 0));
212                     LandscapeComponent->SetMobility(EComponentMobility::Static);
213                     SetXYtoComponentMap(LandscapeComponent);
214 
215                     LoadTexture(LandscapeComponent);
216 
217                     DeleteComponents.RemoveSingleSwap(LandscapeComponent);
218                 }
219             }
220         }
221     }
222 
223     UpdateLeftAndRightPoint();
224 
225     UE_LOG(LogTemp, Warning, TEXT("LeftBottom = %s,RightTop = %s"), *LeftBottom.ToString(), *RightTop.ToString());
226     UE_LOG(LogTemp, Warning, TEXT("X1 = %s,X2 = %s"), *FString::FromInt(ComponentIndexX1), *FString::FromInt(ComponentIndexX2));
227     UE_LOG(LogTemp, Warning, TEXT("Y1 = %s,Y2 = %s"), *FString::FromInt(ComponentIndexY1), *FString::FromInt(ComponentIndexY2));
228     //结束本次增加
229     ResetComponentIndex();
230 }
231 
232 void URuntimeGenerateTerrain::RemoveLandscapeComponent()
233 {
234     DeleteComponents.Empty();
235     //删除远处的component
236     //X正向 加
237 
238     int Xnum = ComponentIndexX2 - ComponentIndexX1 + 1;
239     if (ComponentIndexX1 > RightTop.X)
240     {
241 
242         for (int32 y = LeftBottom.Y; y <= RightTop.Y; y++)
243         {
244             for (int32 x = LeftBottom.X; x < LeftBottom.X + Xnum; x++)
245             {
246                 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y));
247                 if (LandscapeComponent)
248                 {
249                     DeleteComponents.Add(LandscapeComponent);
250                 }
251 
252             }
253         }
254 
255     }
256     //x 负方向 加
257     if (ComponentIndexX2 < LeftBottom.X)
258     {
259         for (int32 y = LeftBottom.Y; y <= RightTop.Y; y++)
260         {
261             for (int32 x = RightTop.X; x > RightTop.X - Xnum; x--)
262             {
263                 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y));
264                 if (LandscapeComponent)
265                 {
266                     DeleteComponents.Add(LandscapeComponent);
267                 }
268 
269             }
270         }
271 
272     }
273     //Y方向 
274     int Ynum = ComponentIndexY2 - ComponentIndexY1 + 1;
275     if (ComponentIndexY1 > RightTop.Y)
276     {
277         for (int32 x = LeftBottom.X; x < (RightTop.X + 1); x++)
278         {
279             for (int32 y = LeftBottom.Y; y < LeftBottom.Y + Ynum; y++)
280             {
281                 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y));
282                 if (LandscapeComponent)
283                 {
284                     DeleteComponents.Add(LandscapeComponent);
285                 }
286 
287             }
288         }
289 
290     }
291     if (ComponentIndexY2 < LeftBottom.Y)
292     {
293         for (int32 x = LeftBottom.X; x < (RightTop.X + 1); x++)
294         {
295             for (int32 y = RightTop.Y; y > RightTop.Y - Ynum; y--)
296             {
297                 ULandscapeComponent* LandscapeComponent = mXYtoComponentMap.FindRef(FIntPoint(x, y));
298                 if (LandscapeComponent)
299                 {
300                     DeleteComponents.Add(LandscapeComponent);
301                 }
302 
303             }
304         }
305     }
306     for (ULandscapeComponent* DeleteComponent : DeleteComponents)
307     {
308         if (!DeleteComponent)continue;
309 
310         RemoveXYtoComponentMap(DeleteComponent);
311     }
312 }
313 
314 void URuntimeGenerateTerrain::UpdateLeftAndRightPoint()
315 {
316     //更新左下及右上的坐标
317     if (ComponentIndexX1 > RightTop.X)
318     {
319         LeftBottom.X = ComponentIndexX1 - LANDSCAPESIZE;
320         RightTop.X = ComponentIndexX2;
321     }
322     if (ComponentIndexX2 < LeftBottom.X)
323     {
324 
325         LeftBottom.X = ComponentIndexX1;
326         RightTop.X = LANDSCAPESIZE + ComponentIndexX1;
327     }
328     //Y方向 
329     if (ComponentIndexY1 > RightTop.Y)
330     {
331         RightTop.Y = ComponentIndexY2;
332         LeftBottom.Y = ComponentIndexY1 - LANDSCAPESIZE;
333     }
334     if (ComponentIndexY2 < LeftBottom.Y)
335     {
336 
337         LeftBottom.Y = ComponentIndexY1;
338         RightTop.Y = LANDSCAPESIZE + ComponentIndexY1;
339 
340     }
341 }
342 
343 void URuntimeGenerateTerrain::SetXYtoComponentMap(ULandscapeComponent* C)
344 {
345 
346     int XIndex = GetComponentIndexX(C);
347     int YIndex = GetComponentIndexY(C);
348     mXYtoComponentMap.Add(FIntPoint(XIndex, YIndex), C);
349 }
350 
351 void URuntimeGenerateTerrain::RemoveXYtoComponentMap(ULandscapeComponent* C)
352 {
353 
354     int XIndex = GetComponentIndexX(C);
355     int YIndex = GetComponentIndexY(C);
356     mXYtoComponentMap.Remove(FIntPoint(XIndex, YIndex));
357 }
358 
359 void URuntimeGenerateTerrain::StartAddComponent()
360 {
361     bAddComponent = true;
362 }
363 
364 void URuntimeGenerateTerrain::StopAddComponent()
365 {
366     bAddComponent = false;
367 }
368 
369 void URuntimeGenerateTerrain::CalComponentIndex()
370 {
371 
372     int XOffset = GetOwner()->GetActorLocation().X - ForeLocation.X;
373     int YOffset = GetOwner()->GetActorLocation().Y - ForeLocation.Y;
374     bool bXChange = false;
375     bool bYChange = false;
376     if (FMath::Abs(XOffset) > mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X)
377     {
378         if (XOffset > 0)
379         {
380             int Xnum = XOffset / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X);
381             ComponentIndexX1 = RightTop.X + 1;
382             ComponentIndexX2 = RightTop.X + Xnum;
383 
384         }
385         else
386         {
387             int Xnum = FMath::Abs(XOffset) / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().X);
388             ComponentIndexX2 = LeftBottom.X - 1;
389             ComponentIndexX1 = LeftBottom.X - Xnum;
390 
391         }
392         bXChange = true;
393     }
394     else
395     {
396         ComponentIndexX1 = LeftBottom.X;
397         ComponentIndexX2 = RightTop.X;
398     }
399 
400     if (FMath::Abs(YOffset) > mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y)
401     {
402         if (YOffset > 0)
403         {
404             int Ynum = YOffset / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y);
405             ComponentIndexY1 = RightTop.Y + 1;
406             ComponentIndexY2 = RightTop.Y + Ynum;
407         }
408         else
409         {
410             int Ynum = FMath::Abs(YOffset) / (mLandscape->ComponentSizeQuads * mLandscape->GetActorScale().Y);
411             ComponentIndexY2 = LeftBottom.Y - 1;
412             ComponentIndexY1 = LeftBottom.Y - Ynum;
413         }
414         bYChange = true;
415     }
416     else
417     {
418         ComponentIndexY1 = LeftBottom.Y;
419         ComponentIndexY2 = RightTop.Y;
420     }
421 
422     if (bXChange || bYChange)
423     {
424         StartAddComponent();
425         ForeLocation = GetOwner()->GetActorLocation();
426 
427     }
428 
429 
430 }
431 
432 void URuntimeGenerateTerrain::ResetComponentIndex()
433 {
434     ComponentIndexX1 = -1;
435     ComponentIndexX2 = -1;
436     ComponentIndexY1 = -1;
437     ComponentIndexY2 = -1;
438 }
439 
440 int URuntimeGenerateTerrain::GetComponentIndexX(ULandscapeComponent* C)
441 {
442     return  C->GetRelativeTransform().GetLocation().X / mLandscape->ComponentSizeQuads;
443 }
444 
445 int URuntimeGenerateTerrain::GetComponentIndexY(ULandscapeComponent* C)
446 {
447     return C->GetRelativeTransform().GetLocation().Y / mLandscape->ComponentSizeQuads;
448 }
449 
450 void URuntimeGenerateTerrain::LoadTextureComplete(UTexture2D* texture)
451 {
452 
453     if (!texture)return;
454 
455     //GEngine->AddOnScreenDebugMessage(-1,3,FColor::Red,texture->GetName());
456     //if (ReadyForTextureMID.Num()>0)
457     //{
458     //    ULandscapeComponent* c = ReadyForTextureMID.Top();
459     //    UMaterialInstanceDynamic* mid = c->MaterialInstancesDynamic.Top();
460     //    mid->SetTextureParameterValue(FName("Texture"),texture);
461     //    ReadyForTextureMID.RemoveSingleSwap(c);
462     //}
463 }