My Solution

I really liked the trigger count idea, so I put it on both the MovingPlatform and the PlatformTrigger.

This fixes a bug where, player A steps on the trigger, player B steps on the same trigger, player B leaves the trigger, and the trigger is deactivated, but player A is still on the trigger.

Also because I’m using the game time to drive a sine(), I have an accumulator variable AliveTime that only counts up when the platform is active.

Moving Platform:
// Copyright © 2018 Robert A. Wallis, All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "MovingPlatform.generated.h"

/**
 * Static object that automatically moves.
 */
UCLASS()
class SHIPPY_API AMovingPlatform : public AStaticMeshActor
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, Category=Platform, Meta=(MakeEditWidget=true))
	FVector TargetLocation;

	UPROPERTY(EditAnywhere, Category=Platform)
	float Speed = 1.0f;

	UPROPERTY(EditAnywhere, Category=Platform)
	int MovingTriggerCount = 1;

private:
	FVector OriginalLocation;
	float AliveTime = 0;

	AMovingPlatform(const FObjectInitializer& ObjectInitializer);
	
	void BeginPlay() override;
	
	void Tick(float deltaSeconds) override;

	void TickMovePlatform();

};


// Fill out your copyright notice in the Description page of Project Settings.

#include "MovingPlatform.h"


AMovingPlatform::AMovingPlatform(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = true;
	SetMobility(EComponentMobility::Movable);
}

void AMovingPlatform::BeginPlay()
{
	Super::BeginPlay();
	OriginalLocation = GetActorLocation();
	if (HasAuthority()) {
		SetReplicates(true);
		SetReplicateMovement(true);
		TickMovePlatform();
	}
}

void AMovingPlatform::Tick(float deltaSeconds)
{
	Super::Tick(deltaSeconds);
	if (!HasAuthority())
		return;

	if (MovingTriggerCount > 0) {
		AliveTime += deltaSeconds;
		TickMovePlatform();
	}
}

void AMovingPlatform::TickMovePlatform()
{
	auto t = (sin(AliveTime * Speed) + 1.0f) * 0.5;
	auto location = OriginalLocation + (TargetLocation * t);
	SetActorLocation(location, false);
}

Platform Trigger:

#pragma once

#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "MovingPlatform.generated.h"

/**
 * Static object that automatically moves.
 */
UCLASS()
class SHIPPY_API AMovingPlatform : public AStaticMeshActor
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, Category=Platform, Meta=(MakeEditWidget=true))
	FVector TargetLocation;

	UPROPERTY(EditAnywhere, Category=Platform)
	float Speed = 1.0f;

	UPROPERTY(EditAnywhere, Category=Platform)
	int MovingTriggerCount = 1;

private:
	FVector OriginalLocation;
	float AliveTime = 0;

	AMovingPlatform(const FObjectInitializer& ObjectInitializer);
	
	void BeginPlay() override;
	
	void Tick(float deltaSeconds) override;

	void TickMovePlatform();

};

#include "PlatformTrigger.h"
#include "MovingPlatform.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"


// Sets default values
APlatformTrigger::APlatformTrigger()
{
	// 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;

	TriggeringVolume = CreateDefaultSubobject<UBoxComponent>(FName("TriggeringVolume"));
	StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(FName("StaticMesh"));

	RootComponent = StaticMesh;
	TriggeringVolume->SetupAttachment(RootComponent);
}

// Called when the game starts or when spawned
void APlatformTrigger::BeginPlay()
{
	Super::BeginPlay();
	if (HasAuthority()) {
		TriggeringVolume->OnComponentBeginOverlap.AddDynamic(this, &APlatformTrigger::OnOverlapBegin);
		TriggeringVolume->OnComponentEndOverlap.AddDynamic(this, &APlatformTrigger::OnOverlapEnd);
	}
}

// Called every frame
void APlatformTrigger::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

void APlatformTrigger::ActivateTrigger()
{
	for (auto& platform : Platforms) {
		platform->MovingTriggerCount ++;
	}
}

void APlatformTrigger::DeactivateTrigger()
{
	for (auto& platform : Platforms) {
		platform->MovingTriggerCount --;
	}
}

void APlatformTrigger::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (!HasAuthority())
		return;

	if (TriggerCount == 0) { // someone triggered it for the first time
		ActivateTrigger();
	}
	TriggerCount ++;
}

void APlatformTrigger::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (!HasAuthority())
		return;

	TriggerCount --;
	if (TriggerCount == 0) { // the last person has stepped out of the trigger
		DeactivateTrigger();
	}
}
1 Like

Nice fix, stolen.

So making a TriggerCount int,
then in OnOverlapBegin() putting

if (TriggerCount < 1)
{
     //other stuff
}
TriggerCount++;

and in OnOverlapEnd()

TriggerCount--;
if (TriggerCount < 1)
{
     //other stuff
}
2 Likes

Privacy & Terms