-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathLandChunk.cpp
More file actions
201 lines (164 loc) · 7.09 KB
/
Copy pathLandChunk.cpp
File metadata and controls
201 lines (164 loc) · 7.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Fill out your copyright notice in the Description page of Project Settings.
#include "LandChunk.h"
#include "CharmingCraft/Core/Bus/GameEventHandler.h"
#include "CharmingCraft/Core/Log/Logging.h"
#include "CharmingCraft/Core/Resource/Lib/GenerateTraceLibrary.h"
#include "CharmingCraft/Object/Class/Core/CharmingCraftInstance.h"
#include "Engine/StaticMeshActor.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
ALandChunk::ALandChunk()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Scene Component"));
SceneComponent->SetRelativeLocation(FVector(0, 0, 0));
RootComponent = SceneComponent;
BottomLayer = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Bottom Layer"));
MiddleLayer = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Middle Layer"));
TopLayer = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Top Layer"));
// (X=0.000000,Y=-1000.000000,Z=0.000000)
TopLayer->SetRelativeLocation(FVector(0,-1000,0));
TopLayer->SetRelativeScale3D(FVector(10,10,3));
MiddleLayer->SetRelativeLocation(FVector(0,-1000,-400));
MiddleLayer->SetRelativeScale3D(FVector(10,10,4));
BottomLayer->SetRelativeLocation(FVector(0,-1000,-700));
BottomLayer->SetRelativeScale3D(FVector(10,10,3));
BottomLayer->SetupAttachment(RootComponent);
MiddleLayer->SetupAttachment(RootComponent);
TopLayer->SetupAttachment(RootComponent);
}
void ALandChunk::PostEditMove(bool bFinished)
{
Super::PostEditMove(bFinished);
if (bFinished)
{
FVector Min, Max;
TopLayer->GetLocalBounds(Min, Max);
const FVector Scale = TopLayer->GetRelativeScale3D();
ChunkPoints.Empty();
const FVector Size = Max * Scale - Min;
NumberCell_X = UE4::SSE::CeilToInt32(Size.X / GridSize);
NumberCell_Y = UE4::SSE::CeilToInt32(Size.Y / GridSize);
ChunkPoints.Reserve(NumberCell_X * NumberCell_Y); // Reserve capacity upfront
GridCell_X = NumberCell_X - 1;
GridCell_Y = NumberCell_Y - 1;
FVector ChunkLocation = GetActorLocation();
int32 Point_Z = ChunkLocation.Z;
int32 BasePoint_X = ChunkLocation.X + 50; // Calculate once
int32 BasePoint_Y = ChunkLocation.Y - 50; // Calculate once
for (int index_X = 0; index_X <= GridCell_X; ++index_X)
{
int32 Point_X = index_X * GridSize + BasePoint_X;
for (int index_Y = 0; index_Y <= GridCell_Y; ++index_Y)
{
const int32 Point_Y = (index_Y * GridSize * -1) + BasePoint_Y;
ChunkPoints.Add(FVector(Point_X, Point_Y, Point_Z));
DrawDebugPoint(this->GetWorld(),FVector(Point_X,Point_Y,Point_Z),10,FColor::Yellow,false,10.0f);
}
}
}
}
void ALandChunk::OnResourceEntityBreakEvent(AActor* Breaker, AResourceEntityActor* TargetResourceEntity)
{
UE_LOG(LogChamingCraftCraftResource, Display,
TEXT("[🪨️] Chunk Internal resource actor update\n"
" [C] Chunk = %s\n"
" [R] Resource = %s\n"
" [I] Instigator = %s"), *this->GetName(),
*TargetResourceEntity->ResourceName.ToString(), *Breaker->GetName());
ResourceEntityActorPool.Remove(TargetResourceEntity);
}
float ALandChunk::GetOnGenerateSuccessRate(FBiomeData BiomeDataContext)
{
int32 BiomeIncludeResource = 0;
for (auto ResourceEntity : ResourceEntityActorPool)
{
if (ResourceEntity.GetClass() == BiomeDataContext.ResourceEntityActorClass.Get())
{
BiomeIncludeResource++;
}
}
return 1 - (BiomeIncludeResource / BiomeDataContext.MaxPerBiome);
}
bool ALandChunk::StartBiomeDataTimer()
{
for (auto PerBiomeData : BiomeData)
{
GetWorld()->GetTimerManager().SetTimer(PerBiomeData.ResourceInternalTimer, [this, PerBiomeData]()
{
this->GenerateResource(PerBiomeData);
},
PerBiomeData.RegenerateTick, true);
}
return true;
}
void ALandChunk::GenerateResource(FBiomeData BiomeDataContext)
{
float SuccessRate = GetOnGenerateSuccessRate(BiomeDataContext);
float RandomChance = FMath::FRand();
if (RandomChance > SuccessRate) {
return; // Early exit if the random chance exceeds success rate
}
int32 RandomIndex = FMath::RandRange(0, ChunkPoints.Num() - 1);
FVector SpawnLocation = ChunkPoints[RandomIndex] + FVector(0, 0, 500);
// Generate Random Rotation
float RandomYaw = UGenerateTraceLibrary::GetRandomYawRight();
FTransform SpawnTransform(FRotator(0,RandomYaw,0), SpawnLocation);
TObjectPtr<AResourceEntityActor> ResourceEntityActor = Cast<AResourceEntityActor>(
UGameplayStatics::BeginDeferredActorSpawnFromClass(this, BiomeDataContext.ResourceEntityActorClass, SpawnTransform));
if (!ResourceEntityActor) {
return; // Early exit if actor casting fails
}
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(ResourceEntityActor);
TArray<float> Z_Plane;
bool bValidSpawn = true; // Assume valid spawn until proven otherwise
for (FVector CornerVector : UGenerateTraceLibrary::GetBoxCornerVector(ResourceEntityActor->HitBox)) {
FHitResult HitResult;
bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, CornerVector, CornerVector - FVector(0, 0, 500),
ECC_WorldStatic, CollisionParams);
DrawDebugLine(this->GetWorld(),CornerVector ,CornerVector-FVector(0, 0, 500),FColor::Purple,false,10.0f);
if (bHit) {
Z_Plane.Add(HitResult.Location.Z);
} else {
bValidSpawn = false;
break; // Exit loop early if any corner does not hit
}
}
if (bValidSpawn && UGenerateTraceLibrary::AreAllElementsTheSame(Z_Plane) && Z_Plane.Num() == 4) {
FHitResult SecondTraceHitResult;
bool bHit = GetWorld()->LineTraceSingleByChannel(SecondTraceHitResult, SpawnLocation, ChunkPoints[RandomIndex],
ECC_WorldStatic, CollisionParams);
DrawDebugLine(this->GetWorld(),ChunkPoints[RandomIndex]+ FVector(0, 0, 500),ChunkPoints[RandomIndex],FColor::Yellow,false,10.0f);
if (bHit && (SecondTraceHitResult.GetActor()->IsA(AStaticMeshActor::StaticClass()) ||
(SecondTraceHitResult.GetActor() == this && SecondTraceHitResult.Component == TopLayer))) {
FVector FinalLocation(SecondTraceHitResult.Location);
FTransform FinalTransform(FRotator(0,RandomYaw,0), FinalLocation);
UGameplayStatics::FinishSpawningActor(ResourceEntityActor, FinalTransform);
ResourceEntityActorPool.Add(ResourceEntityActor);
} else {
bValidSpawn = false;
}
} else {
bValidSpawn = false;
}
if (!bValidSpawn) {
if (ResourceEntityActor) {
ResourceEntityActor->Destroy();
}
}
}
// Called when the game starts or when spawned
void ALandChunk::BeginPlay()
{
Super::BeginPlay();
GameEventHandler = Cast<UCharmingCraftInstance>(GetGameInstance())->GamePlayLogicManager;
GameEventHandler->OnResourceEntityBreak.AddDynamic(this, &ALandChunk::OnResourceEntityBreakEvent);
StartBiomeDataTimer();
}
// Called every frame
void ALandChunk::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}