I have created new project with TopDown template and create UObject, that has function for assigning to the Event. Event is placed in PlayerController and executes on space bar. So I am creating this UObject child on BeginPlay of
PlayerController, set binding with event and it works. But after a minute or so - it stops triggering. This happens with Standalone Game (when I am running as DebugGame in Visual Studio 2017) and InEditor. So maybe GC unbounds subscriber? How can I solve it? Here is my delegate declaration, I write it in separate class:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "CustomeEvents.generated.h"
class AETest2PlayerController;
DECLARE_EVENT_OneParam(AEventsResolvingPlayerController, FOnJump, AETest2PlayerController*const);
UCLASS()
class ETEST2_API UCustomeEvents : public UObject
{
GENERATED_BODY()
private:
};
Here is that UObject, which is subscriber:
// Fill out your copyright notice in the Description page of Project Settings.
#include "Processor.h"
#include "Kismet/KismetSystemLibrary.h"
#include "ETest2PlayerController.h"
void UProcessor::SetEventBinding(FOnJump& OnJumpEvent)
{
OnJumpEvent.AddUObject(this, &UProcessor::JumpMe);
}
void UProcessor::JumpMe(AETest2PlayerController*const inPlayerController)
{
UKismetSystemLibrary::PrintString(inPlayerController, " Was Jumped");
}
Here is PlayerController header:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "CustomeEvents.h"
#include "ETest2PlayerController.generated.h"
UCLASS()
class AETest2PlayerController : public APlayerController
{
GENERATED_BODY()
public:
AETest2PlayerController();
protected:
/** True if the controlled character should navigate to the mouse cursor. */
uint32 bMoveToMouseCursor : 1;
class AETest2Character *My_Pawn;
class UProcessor *Processor;
// Event itself
FOnJump OnJump_Event;
////////////////////////////////////////////////////////////////////////
// Begin PlayerController interface
virtual void PlayerTick(float DeltaTime) override;
virtual void SetupInputComponent() override;
// End PlayerController interface
//FORCEINLINE void InvokeJump();
//FORCEINLINE void DoJump() const;
FORCEINLINE void OnJump();
/** Resets HMD orientation in VR. */
void OnResetVR();
/** Navigate player to the current mouse cursor location. */
void MoveToMouseCursor();
/** Navigate player to the current touch location. */
void MoveToTouchLocation(const ETouchIndex::Type FingerIndex, const FVector Location);
/** Navigate player to the given world location. */
void SetNewMoveDestination(const FVector DestLocation);
/** Input handlers for SetDestination action. */
void OnSetDestinationPressed();
void OnSetDestinationReleased();
void BeginPlay() override;
};
and here is Here is PlayerController source file:
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "ETest2PlayerController.h"
#include "AI/Navigation/NavigationSystem.h"
#include "Runtime/Engine/Classes/Components/DecalComponent.h"
#include "Kismet/HeadMountedDisplayFunctionLibrary.h"
#include "ETest2Character.h"
#include "Processor.h"
AETest2PlayerController::AETest2PlayerController()
{
bShowMouseCursor = true;
DefaultMouseCursor = EMouseCursor::Crosshairs;
}
void AETest2PlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
// keep updating the destination every tick while desired
if (bMoveToMouseCursor)
{
MoveToMouseCursor();
}
}
void AETest2PlayerController::SetupInputComponent()
{
// set up gameplay key bindings
Super::SetupInputComponent();
InputComponent->BindAction("SetDestination", IE_Pressed, this, &AETest2PlayerController::OnSetDestinationPressed);
InputComponent->BindAction("SetDestination", IE_Released, this, &AETest2PlayerController::OnSetDestinationReleased);
InputComponent->BindAction("Jump", IE_Pressed, this, &AETest2PlayerController::OnJump);
// support touch devices
InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AETest2PlayerController::MoveToTouchLocation);
InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &AETest2PlayerController::MoveToTouchLocation);
InputComponent->BindAction("ResetVR", IE_Pressed, this, &AETest2PlayerController::OnResetVR);
}
void AETest2PlayerController::OnJump()
{
OnJump_Event.Broadcast(this);
}
void AETest2PlayerController::OnResetVR()
{
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void AETest2PlayerController::MoveToMouseCursor()
{
if (UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled())
{
if (AETest2Character* MyPawn = Cast<AETest2Character>(GetPawn()))
{
if (MyPawn->GetCursorToWorld())
{
UNavigationSystem::SimpleMoveToLocation(this, MyPawn->GetCursorToWorld()->GetComponentLocation());
}
}
}
else
{
// Trace to see what is under the mouse cursor
FHitResult Hit;
GetHitResultUnderCursor(ECC_Visibility, false, Hit);
if (Hit.bBlockingHit)
{
// We hit something, move there
SetNewMoveDestination(Hit.ImpactPoint);
}
}
}
void AETest2PlayerController::MoveToTouchLocation(const ETouchIndex::Type FingerIndex, const FVector Location)
{
FVector2D ScreenSpaceLocation(Location);
// Trace to see what is under the touch location
FHitResult HitResult;
GetHitResultAtScreenPosition(ScreenSpaceLocation, CurrentClickTraceChannel, true, HitResult);
if (HitResult.bBlockingHit)
{
// We hit something, move there
SetNewMoveDestination(HitResult.ImpactPoint);
}
}
void AETest2PlayerController::SetNewMoveDestination(const FVector DestLocation)
{
APawn* const MyPawn = GetPawn();
if (MyPawn)
{
UNavigationSystem* const NavSys = GetWorld()->GetNavigationSystem();
float const Distance = FVector::Dist(DestLocation, MyPawn->GetActorLocation());
// We need to issue move command only if far enough in order for walk animation to play correctly
if (NavSys && (Distance > 120.0f))
{
NavSys->SimpleMoveToLocation(this, DestLocation);
}
}
}
void AETest2PlayerController::OnSetDestinationPressed()
{
// set flag to keep updating destination until released
bMoveToMouseCursor = true;
}
void AETest2PlayerController::OnSetDestinationReleased()
{
// clear flag to indicate we should stop updating the destination
bMoveToMouseCursor = false;
}
void AETest2PlayerController::BeginPlay()
{
Super::BeginPlay();
//OnJump.AddUObject(this, &AEventsResolvingPlayerController::DoJump);
My_Pawn = Cast<AETest2Character>(GetPawn());
Processor = NewObject<UProcessor>();
Processor->SetEventBinding(OnJump_Event);
}