assume sonic unleashed / sonic generations 3d movement system.
can you finish and improve this boost component, btw the soniccharactercomponent is the main component and inside of unreal the main character inherents from that component

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

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "BoostComponent.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SONICUNLEASHEDREMAKE_API UBoostComponent : public UActorComponent
{
	class ASonicCharacterComponent* SonicCharacter;
	GENERATED_BODY()
	//these are the delegates that we will use to play the boost sound and particles
	//these basically are the in blueprint events
	DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnBoostEvent);
	DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAirBoostEvent);
	DECLARE_DYNAMIC_MULTICAST_DELEGATE(FBoostingEvent); // this one will tick every tick that we are boosting
	DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnStopBoostEvent);

	//events to be accessed in the Blueprints
	UPROPERTY(BlueprintAssignable, Category = "Boost")
		FOnBoostEvent OnBoostEvent;
	UPROPERTY(BlueprintAssignable, Category = "Boost")
		FOnAirBoostEvent OnAirBoostEvent;
	UPROPERTY(BlueprintAssignable, Category = "Boost")
		FOnStopBoostEvent OnStopBoostEvent;
	UPROPERTY(BlueprintAssignable, Category = "Boost")
		FBoostingEvent BoostingEvent;

public:	
	// Sets default values for this component's properties
	UBoostComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Boost")
		float BoostPower;

	UFUNCTION(BlueprintCallable, Category = "Boost")
		void BoostPressed();
	UFUNCTION(BlueprintCallable, Category = "Boost")
		void BoostReleased();
	
	void BoostHandler();
	void AirBoosting();
	UFUNCTION(BlueprintCallable, Category = "Boost")
		void EndAirBoostAnimation();
	UFUNCTION(BlueprintCallable, Category = "Boost")
		bool IsAllowedToBoost() const;
	
	UFUNCTION(BlueprintCallable, Category = "Boost")
		void EnableAirBoosting();
	UFUNCTION(BlueprintCallable, Category = "Boost")
		void DisableAirBoosting();
	
	UFUNCTION(BlueprintCallable, Category = "Boost")
	bool IsBoosting() const { return bIsBoosting; }
	float BoostExtraSpeedConstant;

	FTimerHandle AirBoostAnimationTimer;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Boost")
		bool bIsBoosting;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Boost")
		bool bHasAirBoosted; //you will never actually be in the state of airboosting, because it only triggers once

};

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


#include "Sonic/BoostComponent.h"

#include "GameFramework/CharacterMovementComponent.h"
#include "Runtime/SymsLib/syms/core/generated/syms_meta_serial_ext.h"
#include "Sonic/SonicCharacterComponent.h"

// Sets default values for this component's properties
UBoostComponent::UBoostComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
	BoostPower = 100.0f;
	BoostExtraSpeedConstant = 2000.0f;
	bIsBoosting = false; //this is a toggle boolean
	bHasAirBoosted = false;
	
}


// Called when the game starts
void UBoostComponent::BeginPlay()
{
	Super::BeginPlay();
	SonicCharacter = Cast<ASonicCharacterComponent>(GetOwner());
}


// Called every frame
void UBoostComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	BoostHandler();
}

void UBoostComponent::BoostPressed()
{
	//we play sound and particles and camera shake in the blueprint
	//todo check if we can even boost
	//todo add boost meter implementation

	//only boost if we are not currently boosting, to prevent double inputs
	if (bIsBoosting || bHasAirBoosted) return;
	
	if (SonicCharacter->SonicMovement->IsFalling())
	{
		AirBoosting();
		return;
	}
	OnBoostEvent.Broadcast();
	bIsBoosting = true;
	const float MissingSpeedFromMax = SonicCharacter->SonicMovement->GetMaxSpeed() - SonicCharacter->SonicMovement->Velocity.Size();
	const FVector BoostDirection = SonicCharacter->GetActorForwardVector() * MissingSpeedFromMax;
	SonicCharacter->SonicMovement->Velocity += BoostDirection;
	SonicCharacter->SonicMovement->MaxWalkSpeed = SonicCharacter->SonicMovement->GetMaxSpeed() + BoostExtraSpeedConstant;
	SonicCharacter->SonicMovement->StopSlide();
}


void UBoostComponent::BoostHandler()
{
	if (!bIsBoosting)
		return;
	if (!IsAllowedToBoost())
	{
		BoostReleased(); // force release boost if not allowed anymore
		return;
	}
	//boost!
	SonicCharacter->AddMovementInput(SonicCharacter->GetActorForwardVector(), 2.0f);

}

void UBoostComponent::AirBoosting()
{
	bHasAirBoosted = true;
	OnAirBoostEvent.Broadcast();
	const float MissingSpeedFromMax = SonicCharacter->GetCharacterMovement()->GetMaxSpeed() - SonicCharacter->GetCharacterMovement()->Velocity.Size();
	const FVector BoostDirection = SonicCharacter->GetActorForwardVector() * MissingSpeedFromMax;
	SonicCharacter->GetCharacterMovement()->Velocity += BoostDirection;
	//this sets the state to airboosting for 0.3 seconds, so we can play the animation
	SonicCharacter->CurrentState = EFEeSonicCharacterState::AirBoosting;
	GetWorld()->GetTimerManager().SetTimer(AirBoostAnimationTimer, this, &UBoostComponent::EndAirBoostAnimation, 0.3f, false);
	SonicCharacter->HomingAttackComponent->AirDashDisable();
	if (SonicCharacter->CurrentState == EFEeSonicCharacterState::Jumping)
	{
		SonicCharacter->CurrentState = EFEeSonicCharacterState::Falling;
	}


}

void UBoostComponent::EndAirBoostAnimation()
{
	if (SonicCharacter->CurrentState == EFEeSonicCharacterState::AirBoosting)
	{
		SonicCharacter->CurrentState = EFEeSonicCharacterState::Falling;
	}

}


bool UBoostComponent::IsAllowedToBoost() const
{
	//check if we are in the air
	const bool AirCheck = !SonicCharacter->GetCharacterMovement()->IsFalling();
	const bool SpeedCheck = SonicCharacter->GetCharacterMovement()->Velocity.Size() > 500.0f; // todo 500 is the boosting min speed, make it a variable
	return AirCheck && SpeedCheck;
}


void UBoostComponent::BoostReleased()
{
	if (!bIsBoosting)
	{
		return;
	}
	bIsBoosting = false;
	//reset the walk speed
	SonicCharacter->SonicMovement->MaxWalkSpeed = SonicCharacter->SonicMovement->GetMaxSpeed() - BoostExtraSpeedConstant;
	OnStopBoostEvent.Broadcast();
}

inline void UBoostComponent::EnableAirBoosting()
{
	bHasAirBoosted = false;
}

inline void UBoostComponent::DisableAirBoosting()
{
	bHasAirBoosted = true;
}