Hi guys!
I’m really stuck here with this problem.
You see, I have a AActor class here where I’m trying to use std::call_once inside the constructor. In the editor, I have created a BP based on this class, and I have placed three instances of it. But when I start the game, the procedure that was given to std::call_once isn’t called once. I tried to do something else, created a macro and used atomics to do the same thing, but with no success. What I’m doing wrong here?
here is the class code:
FPSObjectiveActor.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FPSCharacter.h"
#include <functional>
#include <mutex>
#include <atomic>
#include "FPSObjectiveActor.generated.h"
typedef std::function<void()> CallbackFunction;
class USphereComponent;
class AFPSCharacter;
UCLASS()
class FPSGAME_API AFPSObjectiveActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AFPSObjectiveActor();
protected:
AFPSCharacter* _playerCharacter;
CallbackFunction _callback;
/** <GAMEDEV> Static mesh component */
UPROPERTY(VisibleAnywhere, Category = "Components")
UStaticMeshComponent* _meshComp;
/** <GAMEDEV> Collision component */
UPROPERTY(VisibleAnywhere, Category = "Components")
USphereComponent* _sphereComp;
// <GAMEDEV> Particle system component
UPROPERTY(EditDefaultsOnly, Category = "Effects")
UParticleSystem* _pickUpFX;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void PlayEffects(); /
void setCallback(CallbackFunction _cb);
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// <GAMEDEV> Method used to notify when this actor overlaps another one
virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
};
FPSObjectiveActor.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSObjectiveActor.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Kismet/GameplayStatics.h"
#include "FPSCharacter.h"
#include <mutex>
#include <atomic>
//#define CALLBACK_CALLED (]() {static bool is_first_time = true; auto was_first_time = is_first_time; is_first_time = false; return was_first_time; })
#define CALLBACK_CALLED ]()->bool {static std::atomic<bool> first_time(true); return first_time.exchange(false); }
// Sets default values
AFPSObjectiveActor::AFPSObjectiveActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
_meshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
_meshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
RootComponent = _meshComp;
_sphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
_sphereComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
_sphereComp->SetCollisionResponseToAllChannels(ECR_Ignore);
_sphereComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
_sphereComp->SetupAttachment(_meshComp);
/*if(CALLBACK_CALLED) {
auto& _tmp = _playerCharacter;
setCallback(&_tmp]() { return _tmp->PrintObjectiveMessage(); });
}*/
std::once_flag _wasCallbackExecuted;
std::call_once(
_wasCallbackExecuted,
[this]() {
auto& _tmp = _playerCharacter;
setCallback(&_tmp]() { return _tmp->PrintObjectiveMessage(); });
}
);
//auto& _tmp = _playerCharacter;
//setCallback(&_tmp]() { return _tmp->PrintObjectiveMessage(); });
}
void AFPSObjectiveActor::PlayEffects()
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), _pickUpFX, GetActorLocation());
}
void AFPSObjectiveActor::setCallback(CallbackFunction _cb)
{
_callback = _cb;
UE_LOG(LogTemp, Warning, TEXT("Callback bound"));
}
// Called when the game starts or when spawned
void AFPSObjectiveActor::BeginPlay()
{
Super::BeginPlay();
PlayEffects();
}
// Called every frame
void AFPSObjectiveActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AFPSObjectiveActor::NotifyActorBeginOverlap(AActor* _otherActor)
{
Super::NotifyActorBeginOverlap(_otherActor);
_playerCharacter = Cast<AFPSCharacter>(_otherActor);
if (_playerCharacter) {
PlayEffects();
_playerCharacter->_bIsCarryingObjective = true;
_callback();
Destroy();
}
}
Here is an image containing the result after using the std::cal:once approach, you can the yellow phrases inside the output window, there are three of them:
And here is an image containing the result after I uncomment the macro and the IF statement:
In both cases, what I’m doing wrong?
Any help will be greatly appreciated!
Thanks!