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();
}
}