I’ve already done this when I was playing around.
- Create a brush that you can draw over your scene.
- Create a component you can attach to every actor that you want to be parallax
- Store the spawn location of your actor (mine is in StartLocation of my ACharacterClass)
With those 3 things done, add this to the brush code
// In your brush.cpp
// Called every frame
void ADTMDimensionVolume::Tick(float DeltaTime)
{
Super::Tick( DeltaTime );
AdatumCharacter* player = Cast<AdatumCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn());
// Dont do this if we cant get a pawn to work against
if (player == nullptr )
return;
FVector PlayerVelocity = player->GetVelocity();
FVector PlayerOffset = player->StartLocation - player->GetActorLocation();
for (UDTMParallaxComponent* pComp : ParallaxActors)
{
FVector relLoc = pComp->GetOwner()->GetActorLocation();
relLoc.X = pComp->StartLocation.X + (PlayerOffset.X * pComp->AttachedLayer.Speed.X);
relLoc.Z = pComp->StartLocation.Z - (PlayerOffset.Z * pComp->AttachedLayer.Speed.Y);
pComp->GetOwner()->SetActorLocation(relLoc);
}
}
void ADTMDimensionVolume::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
UDTMParallaxComponent* dtmComp = Cast<UDTMParallaxComponent>(OtherComp);
if (dtmComp != NULL)
{
// Add me to the parallax list
AddParallaxActor(dtmComp);
return;
}
}
}
void ADTMDimensionVolume::AddParallaxActor(UDTMParallaxComponent* ParallaxComponent)
{
// Add the actor to the overall list
ParallaxActors.AddUnique(ParallaxComponent);
ParallaxActors.Sort(ADTMDimensionVolume::ParallaxSorter);
// Store the actor in the correct layer
if (ParallaxLayers.IsValidIndex(ParallaxComponent->ParallaxLayer))
{
ParallaxComponent->AttachedLayer = ParallaxLayers[ParallaxComponent->ParallaxLayer];
}
}
bool ADTMDimensionVolume::ParallaxSorter(const UDTMParallaxComponent& ip1, const UDTMParallaxComponent& ip2)
{
return (ip1.ParallaxLayer > ip2.ParallaxLayer);
}
// relevant info for the brush.h file
USTRUCT()
struct FParallaxLayer {
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere)
FVector2D Speed;
};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Parallax)
TArray<FParallaxLayer> ParallaxLayers;
// component.cpp
// Called when the game starts
void UDTMParallaxComponent::BeginPlay()
{
Super::BeginPlay();
StartLocation = GetOwner()->GetActorLocation();
TArray<AActor*> ItemList;
GetOwner()->GetOverlappingActors(ItemList, ADTMDimensionVolume::StaticClass());
for (auto item : ItemList)
{
ADTMDimensionVolume* vol = Cast<ADTMDimensionVolume>(item);
vol->AddParallaxActor(this);
}
// ADTMWorldSettings* WorldSettings = Cast<ADTMWorldSettings>(GetWorld()->GetWorldSettings());
// WorldSettings->GetParallaxManager()->AddParallaxActor(this);
}
// relevant bits for the component.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Parallax)
int32 ParallaxLayer;
UPROPERTY(VisibleAnywhere)
FParallaxLayer AttachedLayer;
virtual void DestroyComponent(bool bPromoteChildren) override;
FVector StartLocation;
Now when your game starts anything with a component inside the brush will register with the brush, and the brush will shift them all about based on which layer you put them in and what speed you gave the layer.
Obviously I’ve not given you all the code here, but it should be enough for you to figure out how to get it running. Your idea was already on the right track, I’ve just shown you how to efficiently iterate over only the actors you are interested in making parallax.
Feel free to ask more, or even access to the source. I’m not precious about it as I’ve already discarded it