Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Fill out your copyright notice in the Description page of Project Settings.
- #pragma once
- #include "CoreMinimal.h"
- #include "GameFramework/Actor.h"
- #include "BallActor.generated.h"
- UCLASS()
- class FORLR2_API ABallActor : public AActor
- {
- GENERATED_BODY()
- public:
- // Sets default values for this actor's properties
- ABallActor();
- UStaticMeshComponent *Mesh;
- UMaterialInstanceDynamic *BallActorMaterial;
- void SetActorRadius(float Radius);
- };
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "BallActor.h"
- // Sets default values
- ABallActor::ABallActor()
- {
- // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
- PrimaryActorTick.bCanEverTick = false;
- PrimaryActorTick.bStartWithTickEnabled = false;
- Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Sphere"));
- Mesh->AttachToComponent(GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::SnapToTarget,
- false));
- ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMesh(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
- static ConstructorHelpers::FObjectFinder<UMaterialInterface> ActorMaterial(
- TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
- BallActorMaterial = UMaterialInstanceDynamic::Create(ActorMaterial.Object, nullptr);
- Mesh->SetStaticMesh(SphereMesh.Object);
- Mesh->SetMaterial(0, BallActorMaterial);
- Mesh->SetCastShadow(false);
- Mesh->SetSimulatePhysics(true);
- }
- void ABallActor::SetActorRadius(float Radius)
- {
- float Scale = Radius / 100 * 2;
- // Установите масштаб мирового пространства Актера.
- SetActorScale3D(FVector(Scale, Scale, Scale));
- }
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "BallsMeshActor.h"
- // Sets default values
- ABallsMeshActor::ABallsMeshActor()
- {
- // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
- PrimaryActorTick.bCanEverTick = false;
- PrimaryActorTick.bStartWithTickEnabled = false;
- static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMesh(
- TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'")
- );
- Mesh = SphereMesh.Object;
- }
- void ABallsMeshActor::InterruptMovement()
- {
- float maxZ = BallsPosition.Z + OuterHeight;
- for (ABallActor *ball : Balls)
- {
- FVector BallLocation = ball->GetActorLocation();
- if (BallLocation.Z > maxZ
- || BallLocation.Z < BallsPosition.Z
- || FMath::Pow(BallLocation.X - BallsPosition.X, 2)
- + FMath::Pow(BallLocation.Y - BallsPosition.Y, 2) > FMath::Pow(OuterRadius, 2))
- {
- ball->Destroy();
- }
- else
- {
- ball->DisableComponentsSimulatePhysics();
- }
- }
- }
- void ABallsMeshActor::CreateBalls(float InnerR, float OuterR, float InnerH, float OuterH, FVector Position,
- float Offset, float BallRadius, float BallDeltaR)
- {
- // ссылка не текущую сцену
- UWorld *MyWorld = GetWorld();
- // радиус внешней стенки
- OuterRadius = OuterR;
- // радиус внутренней стенки
- InnerRadius = InnerR;
- // высота внешней стенки
- OuterHeight = OuterH;
- // высота внутренней стенки
- InnerHeight = InnerH;
- BallsPosition = Position;
- // объем цилиндра, рассчитываемый по внешней стенке
- float OuterVolume = PI * FMath::Pow(OuterR, 2) * OuterH;
- // объем цилиндра, рассчитываемый по внутренней стене
- float InnerVolume = PI * FMath::Pow(InnerR, 2) * InnerH;
- // разница объемов
- const float TargetVolume = OuterVolume - InnerVolume;
- float FilledVolume = 0;
- float ZPosition = OuterH + Offset;
- float MinSpawnRadius = InnerR + BallRadius + BallDeltaR;
- float MaxSpawnRadius = OuterR - BallRadius - BallDeltaR;
- float SpawnRadius = MinSpawnRadius;
- float AddingRadiusSpawn = (BallRadius + BallDeltaR) * 2 + 10;
- float Angle = 0;
- float AddingAngle = 2 * FMath::Asin((BallRadius + BallDeltaR + 10) / SpawnRadius);
- // Резервирует память таким образом, чтобы массив мог содержать по крайней мере числовые элементы.
- Balls.Reserve(TargetVolume / 4.0 / 3.0 * PI * FMath::Pow(BallRadius, 3));
- while (FilledVolume < TargetVolume)
- {
- if (Angle > 2 * PI)
- {
- SpawnRadius += AddingRadiusSpawn;
- if (SpawnRadius > MaxSpawnRadius)
- {
- SpawnRadius = MinSpawnRadius;
- ZPosition += 2 * (BallRadius + BallDeltaR) + 10;
- }
- Angle = 0;
- AddingAngle = 2 * FMath::Asin((BallRadius + BallDeltaR + 10) / SpawnRadius);
- }
- float RandomBallR = FMath::RandRange(BallRadius - BallDeltaR, BallRadius + BallDeltaR);
- ABallActor *Ball = MyWorld->SpawnActor<ABallActor>(
- Position + FVector(SpawnRadius * FMath::Cos(Angle),
- SpawnRadius * FMath::Sin(Angle), ZPosition), FRotator());
- Ball->SetActorRadius(RandomBallR);
- Balls.Add(Ball);
- FilledVolume += 4.0 / 3.0 * PI * FMath::Pow(RandomBallR, 3);
- Angle += AddingAngle;
- }
- }
- // Fill out your copyright notice in the Description page of Project Settings.
- #pragma once
- #include "CoreMinimal.h"
- #include "GameFramework/Actor.h"
- #include "ProceduralMeshComponent.h"
- #include "MyFilter.generated.h"
- UCLASS()
- class FORLR2_API AMyFilter : public AActor
- {
- GENERATED_BODY()
- public:
- // Sets default values for this actor's properties
- AMyFilter();
- UProceduralMeshComponent *Mesh;
- protected:
- void CreateFilterFloor(int Index, float Radius, int Discretization, bool isNormalized, FVector Offset = FVector());
- void CreateFilterWall(int Index, float Radius, float Height, int Discretization, bool isNormalized,
- FVector Offset = FVector());
- public:
- void ConstructFilter(float InnerR, float OuterR, float InnerH, float OuterH,
- FVector Pos, int Discretization);
- };
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "MyFilter.h"
- // Sets default values
- AMyFilter::AMyFilter()
- {
- // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
- PrimaryActorTick.bStartWithTickEnabled = false;
- PrimaryActorTick.bCanEverTick = false;
- Mesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("TriangleMesh"));
- Mesh->AttachToComponent(GetRootComponent(),
- FAttachmentTransformRules(EAttachmentRule::SnapToTarget, false));
- // Определяет, следует ли выполнять физическую обработку вне игрового потока
- Mesh->bUseAsyncCooking = true;
- Mesh->SetCastShadow(false);
- }
- void AMyFilter::CreateFilterWall(int Index, float Radius, float Height, int Discretization, bool isNormalized,
- FVector Offset)
- {
- TArray<FVector> Vertices;
- TArray<int> Triangles;
- TArray<FVector> Normals;
- TArray<FVector2D> UVs;
- TArray<FLinearColor> Colors;
- TArray<FProcMeshTangent> Tangens;
- Vertices.Reserve(Discretization * 2 + 2);
- Triangles.Reserve(Discretization * 2 * 3);
- Normals.Reserve(Discretization * 2 + 2);
- UVs.Reserve(Discretization * 2 + 2);
- Tangens.Reserve(Discretization * 2 + 2);
- Colors.Init(FLinearColor(0.7, 0.7, 1), Discretization * 2 + 2);
- float Angle = 0;
- float DPhi = FMath::DegreesToRadians(360.0 / Discretization);
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Vertices.Add(FVector(Radius * FMath::Cos(Angle), Radius * FMath::Sin(Angle), 0) + Offset);
- Angle += DPhi;
- }
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Vertices.Add(FVector(Radius * FMath::Cos(Angle), Radius * FMath::Sin(Angle), Height) + Offset);
- Angle += DPhi;
- }
- if (isNormalized)
- {
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Triangles.Add((i + 1) % (Discretization + 1));
- Triangles.Add(i + (Discretization + 1));
- Triangles.Add(i);
- Triangles.Add(i + (Discretization + 1));
- Triangles.Add((i + 1) % (Discretization + 1));
- Triangles.Add((i + 1) % (Discretization + 1) + (Discretization + 1));
- }
- } else
- {
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Triangles.Add(i);
- Triangles.Add(i + (Discretization + 1));
- Triangles.Add((i + 1) % (Discretization + 1));
- Triangles.Add((i + 1) % (Discretization + 1) + (Discretization + 1));
- Triangles.Add((i + 1) % (Discretization + 1));
- Triangles.Add(i + (Discretization + 1));
- }
- }
- Angle = 0;
- if (isNormalized)
- {
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Normals.Add(FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0).GetSafeNormal());
- Angle += DPhi;
- }
- } else
- {
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Normals.Add(FVector(-FMath::Cos(Angle), -FMath::Sin(Angle), 0).GetSafeNormal());
- Angle += DPhi;
- }
- }
- for (int i = 0; i < Discretization + 1; ++i)
- {
- UVs.Add(FVector2D(i / (Discretization + 1), 0));
- }
- for (int i = 0; i < Discretization + 1; ++i)
- {
- UVs.Add(FVector2D(i / (Discretization + 1), 1));
- }
- Angle = 0;
- for (int i = 0; i < 2; ++i)
- {
- Angle = 0;
- for (int j = 0; j < Discretization + 1; ++j)
- {
- FVector Normal = FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0).GetSafeNormal();
- Tangens.Add(FProcMeshTangent(Normal.X, Normal.Y, Normal.Z));
- Angle += DPhi;
- }
- }
- Mesh->CreateMeshSection_LinearColor(Index, Vertices, Triangles, Normals, UVs, Colors, Tangens, true);
- }
- void AMyFilter::CreateFilterFloor(int Index, float Radius, int Discretization, bool isNormalized, FVector Offset)
- {
- TArray<FVector> Vertices;
- TArray<int> Triangles;
- TArray<FVector> Normals;
- TArray<FVector2D> UVs;
- TArray<FLinearColor> Colors;
- TArray<FProcMeshTangent> Tangents;
- Vertices.Reserve(Discretization + 1);
- Triangles.Reserve((Discretization - 2) * 3);
- float Angle = 0;
- float DPhi = FMath::DegreesToRadians(360.0 / Discretization);
- for (int i = 0; i < Discretization + 1; ++i)
- {
- Vertices.Add(FVector(Radius * FMath::Cos(Angle), Radius * FMath::Sin(Angle), 0) + Offset);
- Angle += DPhi;
- }
- if(isNormalized)
- {
- for (int i = 0; i < Discretization - 1; ++i)
- {
- Triangles.Add(0);
- Triangles.Add(i + 1);
- Triangles.Add(i + 2);
- }
- } else
- {
- for (int i = 0; i < Discretization - 1; ++i)
- {
- Triangles.Add(i + 2);
- Triangles.Add(i + 1);
- Triangles.Add(0);
- }
- }
- Normals.Init(FVector(0, 0, (isNormalized ? -1 : 1)), Discretization + 1);
- UVs.Reserve(Discretization + 1);
- Angle = 0;
- for(int i = 0; i < Discretization + 1; ++i)
- {
- UVs.Add(FVector2D(0.5 + FMath::Cos(Angle) / 2, 0.5 + FMath::Sin(Angle) / 2));
- Angle += DPhi;
- }
- Colors.Init(FLinearColor(0.7, 0,7, 0.7), Discretization + 1);
- Tangents.Reserve(Discretization + 1);
- Angle = 0;
- for (int i = 0; i < Discretization + 1; ++i)
- {
- FVector Normal = FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0).GetSafeNormal();
- Tangents.Add(FProcMeshTangent(Normal.X, Normal.Y, Normal.Z));
- Angle += DPhi;
- }
- Mesh->CreateMeshSection_LinearColor(
- Index, Vertices, Triangles, Normals, UVs, Colors, Tangents, true);
- }
- void AMyFilter::ConstructFilter(float InnerR, float OuterR, float InnerH, float OuterH, FVector Pos, int Discretization)
- {
- SetActorLocation(Pos);
- CreateFilterFloor(0, OuterR, Discretization, false, FVector(0, 0, 0));
- CreateFilterFloor(1, InnerR, Discretization, true, FVector(0, 0, InnerH));
- CreateFilterFloor(2, InnerR, Discretization, false, FVector(0, 0, OuterH));
- CreateFilterWall(3, OuterR, OuterH, Discretization, true,
- FVector(0, 0, 0));
- CreateFilterWall(4, InnerR, OuterH - InnerH, Discretization, false,
- FVector(0, 0, InnerH));
- }
- // Fill out your copyright notice in the Description page of Project Settings.
- #pragma once
- #include "CoreMinimal.h"
- #include "BallsMeshActor.h"
- #include "MyFilter.h"
- #include "GameFramework/Actor.h"
- #include "MainComponent.generated.h"
- UCLASS()
- class FORLR2_API AMainComponent : public AActor
- {
- GENERATED_BODY()
- public:
- // Sets default values for this actor's properties
- AMainComponent();
- // внешний радиус цилиндра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float OuterRadius;
- // высота внешней стенки цилиндра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float OuterHeight;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float DeltaHeight;
- // внешний радиус цининдра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float InnerRadius;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- int Discretization;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float ActorBallRadius;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float BallsOffsetZ;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float BallDeltaRadius;
- ABallsMeshActor *Balls;
- AMyFilter *MyFilter;
- bool IsActorStopped;
- protected:
- // Called when the game starts or when spawned
- virtual void BeginPlay() override;
- public:
- void InterruptSimulation();
- // Called every frame
- virtual void Tick(float DeltaTime) override;
- };
- // Fill out your copyright notice in the Description page of Project Settings.
- #pragma once
- #include "CoreMinimal.h"
- #include "BallsMeshActor.h"
- #include "MyFilter.h"
- #include "GameFramework/Actor.h"
- #include "MainComponent.generated.h"
- UCLASS()
- class FORLR2_API AMainComponent : public AActor
- {
- GENERATED_BODY()
- public:
- // Sets default values for this actor's properties
- AMainComponent();
- // внешний радиус цилиндра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float OuterRadius;
- // высота внешней стенки цилиндра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float OuterHeight;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float DeltaHeight;
- // внешний радиус цининдра
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- float InnerRadius;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cylinder")
- int Discretization;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float ActorBallRadius;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float BallsOffsetZ;
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ball")
- float BallDeltaRadius;
- ABallsMeshActor *Balls;
- AMyFilter *MyFilter;
- bool IsActorStopped;
- protected:
- // Called when the game starts or when spawned
- virtual void BeginPlay() override;
- public:
- void InterruptSimulation();
- // Called every frame
- virtual void Tick(float DeltaTime) override;
- };
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "MainComponent.h"
- // Sets default values
- AMainComponent::AMainComponent()
- {
- // 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;
- PrimaryActorTick.bStartWithTickEnabled = true;
- SetRootComponent(
- CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent")));
- }
- void AMainComponent::InterruptSimulation()
- {
- IsActorStopped = true;
- }
- // Called when the game starts or when spawned
- void AMainComponent::BeginPlay()
- {
- Super::BeginPlay();
- if (Discretization < 3)
- {
- return;
- }
- UWorld *World = GetWorld();
- MyFilter = World->SpawnActor<AMyFilter>(AMyFilter::StaticClass());
- MyFilter->ConstructFilter(InnerRadius, OuterRadius, DeltaHeight, OuterHeight,
- GetActorLocation(), Discretization);
- Balls = World->SpawnActor<ABallsMeshActor>(ABallsMeshActor::StaticClass());
- Balls->CreateBalls(InnerRadius, OuterRadius, OuterHeight - DeltaHeight, OuterHeight, GetActorLocation(),
- BallsOffsetZ, ActorBallRadius, BallDeltaRadius);
- }
- // Called every frame
- void AMainComponent::Tick(float DeltaTime)
- {
- Super::Tick(DeltaTime);
- if (IsActorStopped)
- {
- Balls->InterruptMovement();
- }
- }
Add Comment
Please, Sign In to add comment