Ice Wall: Open meshes

In a previous post, I asked how to create a circular ice wall that also acts as the boundary of my map, but no one answered. So I tried doing it myself, and I kind of succeeded.

And here’s the code—thanks to ChatGPT!

IceWallRing.cpp:


 “IceWallRing.h”


 “Components/SplineComponent.h”

 “Components/SplineMeshComponent.h”

 “Engine/StaticMesh.h”

AIceWallRing::AIceWallRing()
{
PrimaryActorTick.bCanEverTick = false;

Spline = CreateDefaultSubobject<USplineComponent>(TEXT("Spline"));
Spline->SetMobility(EComponentMobility::Movable);
RootComponent = Spline;

}

void AIceWallRing::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);

// Editor preview seed
const int32 PreviewSeed = RandomSeed == 0 ? 12345 : RandomSeed;
BuildWall(PreviewSeed);

}

void AIceWallRing::BeginPlay()
{
Super::BeginPlay();

// New game / new play session seed
RuntimeSeed = RandomSeed == 0 ? FMath::Rand() : RandomSeed;

BuildWall(RuntimeSeed);

}

void AIceWallRing::ClearWallMeshes()
{
TArray<USplineMeshComponent*> OldMeshes;
GetComponents(OldMeshes);

for (USplineMeshComponent* OldMesh : OldMeshes)
{
    if (OldMesh)
    {
        OldMesh->DestroyComponent();
    }
}

}

void AIceWallRing::BuildWall(int32 Seed)
{
if (!Spline || WallMeshes.Num() == 0 || PointCount < 3)
{
return;
}

ClearWallMeshes();

Spline->ClearSplinePoints(false);

// Create circle points
for (int32 i = 0; i < PointCount; i++)
{
    const float Angle = ((float)i / (float)PointCount) * 360.f;

    const float X = FMath::Cos(FMath::DegreesToRadians(Angle)) * Radius;
    const float Y = FMath::Sin(FMath::DegreesToRadians(Angle)) * Radius;

    Spline->AddSplinePoint(FVector(X, Y, 0.f), ESplineCoordinateSpace::Local, false);
}

Spline->SetClosedLoop(true, false);
Spline->UpdateSpline();

FRandomStream RandomStream(Seed);

// Create wall segments
for (int32 i = 0; i < PointCount; i++)
{
    const int32 NextIndex = (i + 1) % PointCount;

    const FVector Start = Spline->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::Local);
    const FVector End = Spline->GetLocationAtSplinePoint(NextIndex, ESplineCoordinateSpace::Local);

    const FVector StartTangent =
        Spline->GetTangentAtSplinePoint(i, ESplineCoordinateSpace::Local) * 0.25f;

    const FVector EndTangent =
        Spline->GetTangentAtSplinePoint(NextIndex, ESplineCoordinateSpace::Local) * 0.25f;

    USplineMeshComponent* Mesh = NewObject<USplineMeshComponent>(this);
    Mesh->CreationMethod = EComponentCreationMethod::UserConstructionScript;
    Mesh->SetMobility(EComponentMobility::Movable);

    int32 MeshIndex = RandomStream.RandRange(0, WallMeshes.Num() - 1);
    Mesh->SetStaticMesh(WallMeshes[MeshIndex]);
    Mesh->SetForwardAxis(ESplineMeshAxis::X);

    // BLOCK PLAYER
    Mesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
    Mesh->SetCollisionResponseToAllChannels(ECR_Block);

    Mesh->AttachToComponent(Spline, FAttachmentTransformRules::KeepRelativeTransform);
    Mesh->RegisterComponent();

    Mesh->SetStartAndEnd(Start, StartTangent, End, EndTangent, true);
}

}

IceWallRing.h:

#pragma once


 “CoreMinimal.h”

 “GameFramework/Actor.h”

 “IceWallRing.generated.h”

class USplineComponent;
class UStaticMesh;

UCLASS()
class ICEWALLPROJECT_API AIceWallRing : public AActor
{
GENERATED_BODY()

public:
AIceWallRing();

virtual void OnConstruction(const FTransform& Transform) override;
virtual void BeginPlay() override;

private:
void BuildWall(int32 Seed);
void ClearWallMeshes();

public:
UPROPERTY(EditAnywhere, Category = “Ice Wall”)
float Radius = 1500.f;

UPROPERTY(EditAnywhere, Category = "Ice Wall")
int32 PointCount = 8;

UPROPERTY(EditAnywhere, Category = "Ice Wall")
TArray<UStaticMesh*> WallMeshes;

// 0 = generate a new seed when the game starts
UPROPERTY(EditAnywhere, Category = "Ice Wall|Random")
int32 RandomSeed = 0;

private:
UPROPERTY()
USplineComponent* Spline = nullptr;

int32 RuntimeSeed = 0;

};

Now, as you can see, it works, but it’s also a total failure. Editing the shape of the wall meshes causes them to spawn distorted and broken. Whatever material I use, it appears repetitive—especially since my wall has a radius of 50,000 and a point count of 275, and the wall meshes have a height of 50,000. I did, however, buy the following meshes:

So here’s the new plan: use these amazing (and expensive) open meshes as a second layer on top of my wall, blending them with it to achieve the desired look (like the Game of Thrones wall of ice). But I’m extremely lazy and don’t have the patience to design all of this along the entire wall. Is there a way to automate it, or should I come up with another plan?

PLEASE HELPPPPP

Basically, get one good rock, that you blow up to 100 times it’s normal size, and the geometry still looks ok, and either write a blueprint to place them, or use PCG.

You put them in a circle, but set their rotations as random on all axes, that will give a pretty good ice wall effect.

Also, you might need to re-code the material to use world aligned textures, to avoid them becoming too low res.

Hey there @cherbzzz! I agree with Clockwork here, and I would recommend PCG as well. You can use it to spread meshes along this wall relatively easily.

Here’s a PCG course leading with a video relevant for specifically placing objects on meshes in a controlled way: