First of all, I’m a beginner, i just build a button by my self. But i notice that my button is not working smoothly enough.
The main function of the button is to be pressed when the character steps on it or jumps on it, and to bounce back when the character walks away.
I use two BoxComponent to build the button.
The base of the button is fixed, and the main pressing and bouncing action is accomplished by the button top.
ButtonBaseComponent = CreateDefaultSubobject<UBoxComponent>("Button Base");
ButtonTopComponent = CreateDefaultSubobject<UBoxComponent>("Button Top");
The main logic is when player character overlap with the button top, the button top go down. when the overlap end, the button top go up. And to avoid when the button top go up lead to overlap again which will cause dead loop, i set a cooldown delay and two variable like muteX to make sure the button in the right position.
The problem is if the cooldown delay is too large, the button might won’t go up when player character leave. If it is too small, it works well with the player character but not with NPC whose jump implementation is quite different from player’s.
The last part is the concrete code.
void AButtonActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (ButtonPosition == 0 && !ButtonIsMoving) {
ButtonIsMoving = true;
if (ClickSound != nullptr)
{
UGameplayStatics::PlaySoundAtLocation(this, ClickSound, OverlappedComponent->GetComponentLocation(), 1, FMath::RandRange(0.4f, 1.3f), 0.f, ClickSoundAttenuation);
}
FVector MoveDirection(0.0f, 0.0f, -1.0f);
float MoveDistance = 12.6f;
MoveComponent(OverlappedComponent, MoveDirection, MoveDistance);
GetWorld()->GetTimerManager().SetTimer(MovingDownTimerHandle, this, &AButtonActor::MoveDown, CoolDownDelay, false);
}
}
void AButtonActor::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (ButtonPosition == -1 && !ButtonIsMoving) {
ButtonIsMoving = true;
FVector MoveDirection(0.0f, 0.0f, 1.0f);
float MoveDistance = 12.6f;
MoveComponent(OverlappedComponent, MoveDirection, MoveDistance);
GetWorld()->GetTimerManager().SetTimer(MovingUpTimerHandle, this, &AButtonActor::MoveUp, CoolDownDelay, false);
}
}
void AButtonActor::MoveComponent(UPrimitiveComponent* Component, FVector MoveDirection, float MoveDistance)
{
FVector RelativeLocation = Component->GetRelativeLocation();
FVector NewRelativeLocation = RelativeLocation + MoveDirection * MoveDistance;
Component->SetRelativeLocation(NewRelativeLocation);
}
// change the variables
void AButtonActor::MoveUp()
{
ButtonPosition++;
ButtonIsMoving = false;
}
void AButtonActor::MoveDown()
{
ButtonPosition--;
ButtonIsMoving = false;
}