Spawning character is not triggering my custom volume

I have built a simple Checkpoint system, when the player “died”, I move them back to that Checkpoint.

Only problem is on level start my character spawns inside first Checkpoint and it doesnt call OnOverlapBegin.

Is this expected behaviour? If so or not, what should I be looking to do?

Cheers

look for a function called


 true or false = volume->Encompasses(startpoint);

If this is still in actor file. then you put in your start point as the actor parameter and it will return if your in the volume or not with a bool.

Edit it is in the volume.h file


/** @returns true if a sphere/point (with optional radius CheckRadius) overlaps this volume */
bool EncompassesPoint(FVector Point, float SphereRadius=0.f, float* OutDistanceToPoint = 0) const;

Hey, cheers for this!
I get what you mean, but I’m not sure how to implement.
Is EncompassessPoint() a static function on the volume class?

In my CheckPoint class I’m using BoxComponent to handle my collision. It doesn’t seem to have this function? I can use GetPhysicsVolume() but I’m unable to cast to AVolume, and PhysicsVolume() doesn’t seem to have this function either.

AVolume is extending the ABrush class. and in the brush class you have a BrushComponent. i would make it a Avolume Then you can use the function EncompassessPoint();

then use your volume like so bool YouInVolume = Yourvolume->EncompassesPoint(FVector Point, float SphereRadius=0.f, float* OutDistanceToPoint = 0);
FVector Point, will be your startpoint.location; the other 2 parameters are for your start point collision sphere. read about those and figure out what they are for or just try some numbers in them to test it. I’m just assuming here but startpoint.collisionradius should be the SphereRadius 3rd parameter just use a 0.0 i’m assuming it should work.



bool YouAreInVolume = Yourvolume->EncompassesPoint(startpoint.location, startpoint.collisionradius,  0.0);


Then you can use if(YouAreInVolume) he is in the volume = true; if(!YouAreInVolume) not in volume = false;
Something like that should work. the names i used in the parameters will have to be set to the right words so it will work right not sure what you call you start point and its variables like location. So i just used startpoint.location as an example. It should be something like yourstartpoint.location if yourstartpoint is a ptr then you will want yourstartpoint->location.

Hope this helps get you on your way to getting this working.

Hey, sorry late reply. I do get you here. But I’m still a bit confused.

Are you recommending I put this in my CheckPoint class or MyCharacter class ?

And pending which one, how would I know the properites to pass?

Like if it’s in my CheckPoint class, I’d need to get the character that is touching it on PostBeginPlay ?

And if it’s from MyCharacter’s point of view, I’d need to be able to “find” the current CheckPoint somehow ?

Or have I miss understood you here …?

I myself would put it in the RestartPlayer(AController* NewPlayer); function in your AGameModeBase file. So you can check before you actually spawn. To see if you can spawn there or do what ever you want it to do before you spawn.

If you are wanting to check your spawn place to see if its in the volume. Then you need to use the volume you want to check(Yourvolume->) to run the function EncompassesPoint the parameters will be the spawn point you want to check. If its in that volume, then it will send out a true in the bool. if its not in the volume it will send out a false to the bool YouAreInVolume

Then use YouAreInVolume to do what ever you want to do if its in the volume.




YouAreInVolume ? YourInVolumeDoSomething() : YourNotInVolumeDoSomething();


At line in 1194 in AGameModeBase.cpp file. After this if


 // If a start spot wasn't found,
if (StartSpot == nullptr)
{
// Check for a previously assigned spot
if (NewPlayer->StartSpot != nullptr)
{
StartSpot = NewPlayer->StartSpot.Get();
UE_LOG(LogGameMode, Warning, TEXT("RestartPlayer: Player start not found, using last start spot"));
}
}
} 

You can get your startpoint right there to get its location and radius and right before this line 1204


RestartPlayerAtPlayerStart(NewPlayer, StartSpot);

is where i would do it all.

I did your parameters for you, you will need to get Yourvolume and write what happens if start is in it or not.


bool YouAreInVolume = Yourvolume->EncompassesPoint(StartSpot->GetActorLocation(), StartSpot->GetCapsuleComponent()->CapsuleRadius, 0.0);

YouAreInVolume ? YourInVolumeDoSomething() : YourNotInVolumeDoSomething();

void SomeClass::YourInVolumeDoSomething()
{
//do something;
}

void SomeClass::YourNotInVolumeDoSomething()
{
   //do something;
}

Reason for using the spawn point and not the character himself is. Character won’t be there until he actually spawns. The spawn point is there and that is where your character will be when he spawns, so check that point.

I am working on this now, as i need the same code as you. When i get it done. I will post the code all commented for anyone to use if they want or need it. ■■■■ compilers waste so much time. Take 2 years to make a game and 1 year sitting and waiting on the ■■■■ compilers <crazy slow.

Hah, great minds think a like I guess ?

I fully get your approach, but I’m still struggling with how I can reference MyVolume from GameMode.

I was hoping I could do something like (excude the psuedo code):

MyCharacter.cpp



function OnBeginLevel() {
    array actors = GetAllTouchingActors();
    for (actor in actors) {
        if (actor == MyCheckPoint) {
            self.CurrentCheckPoint = CheckPoint;
        }
    }
}


Youre last example shows that in RestartPlayer() I’ve got the SpawnPoint - which is great. But how would I also have a reference to MyCheckPoint.MyVolume vairable?
That’s the aspect of your approach I’m not getting.
How can MyCharacter know about a level object like MyCheckPoint, or how can GameMode know about level objects like MyCheckPoint?

For what it’s worth I’m working on making a fun platformer to play with my friends - similar to Mario 3d World. So all players share 1 camera and run through a level.
Once I’ve got the check point stuff sorted, I need to fix my “shared camera” code - which is being very jittery on line.

There are two ways to get what you are after. I got all the code done to find out about the both ways. You can use a function
EncompassesPoint() or you can use ActorEnteredVolume(). I tested both and both react when spawned in the volume, Which would you like to use? Are you after a spawn protection?

I had to extend the physic volume to get both to work. If you use EncompassesPoint() In the APhysicsVolume i added 3 bools, as i was checking 3 volumes at the same time using that code.



bool bIsACheckPoint;
bool bIsAOBVolume;
bool bIsAWeatherVolume;


Then set each volume to true in its own constructor. If you want to use EncompassesPoint() then you will want the bool for which ever volume you add.

Let me know which you want to use then i can post its code.

Edit: let me get both, i will post both then you can choose what you want to use

This will be for using EncompassesPoint().
In your gametype.h file add in this




#include "GameFramework/PhysicsVolume.h"

DECLARE_LOG_CATEGORY_EXTERN(LogGameType, Log, All);

UCLASS(minimalapi, config=Game)


/** Tries to spawn the player's pawn, at the location returned by FindPlayerStart */
virtual void RestartPlayer(AController* NewPlayer) override;

UFUNCTION()
void CheckIfInVolume(AActor* StartPlace, AController* NewPlayer);

UFUNCTION()
void YouAreInVolume(const APhysicsVolume* VolumeYourIn, AController* NewPlayer);

UPROPERTY(config)
bool bSpawnProtectionOn;


Then in the gametype.cpp file add, and do not super this function, NEW CODE IN RED



void AYourGameMode::RestartPlayer(AController* NewPlayer)
{
UE_LOG(LogGameType, Log, TEXT("AYourGameMode::RestartPlayer() bSpawnProtectionOn = %s"), bSpawnProtectionOn ? TEXT("TRUE") :     TEXT("FALSE"));
    if (NewPlayer == nullptr || NewPlayer->IsPendingKillPending())
    {
       return;
     }

     AActor* StartSpot = FindPlayerStart(NewPlayer);

    // If a start spot wasn't found,
    if (StartSpot == nullptr)
   {
      // Check for a previously assigned spot
     if (NewPlayer->StartSpot != nullptr)
     {
         StartSpot = NewPlayer->StartSpot.Get();
         UE_LOG(LogGameType, Warning, TEXT("RestartPlayer: Player start not found, using last start spot"));
      }
    }
    CheckIfInVolume(StartSpot, NewPlayer);

UE_LOG(LogGameType, Log, TEXT("AYourGameMode::RestartPlayer() bSpawnProtectionOn = %s"), bSpawnProtectionOn ? TEXT("TRUE") : TEXT("FALSE"));
if (bSpawnProtectionOn)
    {
         class AYourCharacter* const SPCharacter = Cast<AYourCharacter>(NewPlayer->GetPawn());
         UE_LOG(LogGameType, Log, TEXT("APerfectHunt2GameMode::RestartPlayer(); SPCharacter = %s"), *SPCharacter->GetName());
       SPCharacter->StartSpawnProtection();//added a bool to control it all
 }
     RestartPlayerAtPlayerStart(NewPlayer, StartSpot);
}


And add also in gametype.cpp



/*Check if in a volume at spawn time.*/
void AYourGameMode::CheckIfInVolume(AActor* StartPlace, AController* NewPlayer)
{
    bool bYouAreInVolume = false;

     //scan volumes to see if you are in one
     for (auto VolumeIter = GetWorld()->GetNonDefaultPhysicsVolumeIterator(); VolumeIter; ++VolumeIter)// <thanks **[TheJamsh](https://forums.unrealengine.com/member/155-thejamsh)** for the help.
     {
         const APhysicsVolume* OurVolume = VolumeIter->Get();

         if (OurVolume != nullptr)
         {
             bYouAreInVolume = OurVolume->EncompassesPoint(StartPlace->GetActorLocation());
         }

         //you are in a volume go edit the character now
        if (bYouAreInVolume)
        {
            YouAreInVolume(OurVolume, NewPlayer);
             break;
         }

     }
     return;
}


And add also in gametype.cpp



void AYourGameMode::YouAreInVolume(const APhysicsVolume* VolumeYouAreIn, AController* NewPlayer)
{
//you are in a volume go edit the character now
    UE_LOG(LogGameType, Log, TEXT("YouAreInVolume(); OurVolume = %s"), *VolumeYouAreIn->GetName());

     GEngine->AddOnScreenDebugMessage(-1, 1.1f, FColor::Green, FString::Printf(TEXT("You are IN The Volume")));
     class AYour2Character* const SPCharacter = Cast<AYour2Character>(NewPlayer->GetPawn());
UE_LOG(LogGameType, Log, TEXT("YouAreInVolume(); SPCharacter = %s"), *SPCharacter->GetName());

      UE_LOG(LogGameType, Log, TEXT("YouAreInVolume() bIsAWeatherVolume = %s"), VolumeYouAreIn->bIsAWeatherVolume ? TEXT("TRUE") :      TEXT("FALSE"));
      UE_LOG(LogGameType, Log, TEXT("YouAreInVolume() bIsACheckPoint = %s"), VolumeYouAreIn->bIsACheckPoint ? TEXT("TRUE") : TEXT("FALSE"));
      UE_LOG(LogGameType, Log, TEXT("YouAreInVolume() bIsAOBVolume = %s"), VolumeYouAreIn->bIsAOBVolume ? TEXT("TRUE") : TEXT("FALSE"));

      if (VolumeYouAreIn->bIsACheckPoint)//Are you in a check point
      {
          //in Check Point do stuff
         GEngine->AddOnScreenDebugMessage(-1, 1.1f, FColor::Green, FString::Printf(TEXT("Your IN The Check Point Volume")));
          //SPCharacter->CPStartSomething();//set Something
      }
      else if (VolumeYouAreIn->bIsAWeatherVolume)//Are you in a Weather Volume
      {
           //in indoor Weather Volume do stuff> shut off rain and snow your indoors
          GEngine->AddOnScreenDebugMessage(-1, 1.1f, FColor::Green, FString::Printf(TEXT("Your IN The Weather Volume")));
           SPCharacter->WeatherStop();//stop the weather
      }
     else if (VolumeYouAreIn->bIsAOBVolume)//Are you in a Out of Bounds Volume
     {
       //get the ob volume so we can set the kill time parameter
       //const AOutOfBoundsVolume* YourVolume = Cast<AOutOfBoundsVolume>(VolumeYouAreIn);
      GEngine->AddOnScreenDebugMessage(-1, 1.1f, FColor::Green, FString::Printf(TEXT("Your IN The Out of Bounds Volume")));

      //Start countdown timer to kill player
      //do not use, as Enteredthevolume() runs also;> use that Enteredthevolume();
      //SPCharacter->OBStartCountDown(YourVolume->killTime, true);
     }
    return;
}


If you want to use the Enteredthevolume(); In your CheckPoint.h file add




YOUR_API DECLARE_LOG_CATEGORY_EXTERN(LogCPVolume, Log, All);

public:
ACheckPointVolume();
~ACheckPointVolume();

// Called when actor enters a volume
virtual void ActorEnteredVolume(class AActor* Other) override;

// Called when actor leaves a volume, Other can be NULL
virtual void ActorLeavingVolume(class AActor* Other) override;


in CheckPoint.cpp file add



#include "Player/YourCharacter.h"

DEFINE_LOG_CATEGORY(LogCPVolume);

ACheckPointVolume::ACheckPointVolume()
{
  bIsACheckPoint = true;
}

//actor touchs the volume
void ACheckPointVolume::ActorEnteredVolume(class AActor* Other)
{
UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume %p is *Other"), Other);
   UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume %s is *Other"), *Other->GetName());
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume() = *Other = %s"), Other ? TEXT("TRUE") : TEXT("FALSE"));

    AYourCharacter* const ToucherCharacter = Cast<AYourCharacter>(Other);//ARE WE A WALKER
UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume %p is *ToucherCharacter"), ToucherCharacter);
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume %s is *ToucherCharacter"), *ToucherCharacter->GetName());
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorEnteredVolume() = *ToucherCharacter = %s"), ToucherCharacter ? TEXT("TRUE") : TEXT("FALSE"));

//keep out projectiles
   if (ToucherCharacter == nullptr)//TYPE_OF_NULLPTR
{
      return;
   }
   else if (ToucherCharacter != nullptr)//true that we are in the volume//TYPE_OF_NULLPTR
   {
      ToucherCharacter->CPStartSomething();
   }
}

//actor untouchs the volume
void ACheckPointVolume::ActorLeavingVolume(class AActor* Other)
{
UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume %p is *Other"), Other);
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume%s is *Other"), *Other->GetName());
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume() = *Other = %s"), Other ? TEXT("TRUE") : TEXT("FALSE"));

     AYourCharacter* const ToucherCharacter = Cast<AYourCharacter>(Other);//ARE WE A WALKER
UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume %p is *ToucherCharacter"), ToucherCharacter);
   UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume %s is *ToucherCharacter"), *ToucherCharacter->GetName());
    UE_LOG(LogCPVolume, Log, TEXT("ACheckPointVolume::ActorLeavingVolume() = *ToucherCharacter = %s"), ToucherCharacter ? TEXT("TRUE") : TEXT("FALSE"));

   //keep out projectiles
    if (ToucherCharacter == nullptr)//TYPE_OF_NULLPTR
    {
       return;
    }
    else if (ToucherCharacter != nullptr)//true that we are in the volume//TYPE_OF_NULLPTR
{
       ToucherCharacter->CPStopSomething();
    }
}


Use which ever you want they both will detect that you have spawned in a volume. I tested both ways yesterday in all 3 volumes and all worked perfect. You will need to add what you want it to do to the character. Then you will have it finished up. If you are after spawn protection let me know, i can post that also if interested.

Actually, no.
I have a CheckPoint system that works as the Character runs through them. But I was hoping I could easily add the first CheckPoint to the PlayerStart of the game, so I could easily use that there.

But I ran into this issue where the Character spawns inside my BoxComponent, and the OnComponentBeginOverlap function is not called.

Thank you for all your codes and help.

Ok yeah, I now see how you’re doing it. Youre looping all PhysicVolumes in the GameWorld with the function GetNonDefaultPhysicsVolumeIterator
This was the part I was miss understanding previously.

So if i’ve understood you correctly, i could use EncompassesPoint(), in GameState, by looping all PhysVols and comparing my StartingOoint with them.
Or, I can use ActorEnteredVolume from a PhysVolume point of view, and this works when an actor is Spawned inside too?

How I’ve approached this so far is: I’ve got my CheckPoint which inherits from Actor. Then I added some components: BoxComponent (collision), Mesh (for ingame visuals).

I was thinking I could replace UBoxComponent in my CheckPoint class with the AVolume?
But I’ve also noticed I can do this:



APhysicsVolume* volume = BoxComponent->GetPhysicsVolume();
volume->ActorEnteredVolume(...);


Is it possible for me to override this function from here? Similar to how you could do in python/js/lua :



APhysicsVolume* volume = BoxComponent->GetPhysicsVolume();
volume.ActorEnteredVolume = function(Actor* Other) {
     // my new code
}


I’m still quite new to c++, is this where “delegates” come in ?:



volume->ActorEnteredVolume.AddDynamic(this, &AWP_Checkpoint::MyCustomFunction);   


Or is the correct thing to do here: inherit my CheckPoint from AVolume, then add my Mesh and then override the ActorEnteredVolume function that way?

  • Edit *
    I can’t seem to do this (due to my miss understanding of delegates I assume):


APhysicsVolume* volume = BoxComponent->GetPhysicsVolume();
volume->ActorEnteredVolume.AddDynamic(this, &AWP_Checkpoint::ActorEnteredVolume);


For what it’s worth, I think you want to use “youre” not “your” ?:
“youre in a volume” (you are in a volume)
“your volume” (this volume belongs to you)

FYI the engine has several issues with spawning and collision, so it isn’t just you. :wink:

Here’s a function we use to determine “is a character inside a trigger volume” that gets called (of course) when spawning. Class inherits from Unreal ATriggerVolume class.

In .h file.



/**
* Return true if player is inside this volume.
*/
bool IsPlayerInside();


In .cpp file:



/**
* Return true if player is inside this volume.
*/
bool AInteractionVolume::IsPlayerInside()
{
  ACharacter* playerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
  if (playerCharacter && IsOverlappingActor(playerCharacter))
  {
      return true;
  }
  return false;
}


because i see you are wanting to go back to the volume. Just use the volume and let its function fire when he spawns. it recognizes that he is in it. Just use the checkpoint. No use to go back to it when you will be in it already, in its own function> ActorEnteredVolume(). Just use the checkpoint. <Unless it is a bug that it recognizing it. In the old version it did not get recognized when spawned in it thru> ActorEnteredVolume(). So you had to check if you spawned in it. When i tested it the other day. Both ways worked which shocked me. As **Shmoopy1701 said **

So who knows maybe down the road it will all change and you have to use the check the spawn and not be able to use ActorEnteredVolume(). If you do not want to use a phsyics volume, you can use what **Shmoopy1701 typed.

As for the English lesson there is no such word> youre. It is you’re for you are. **** I know what they mean. This is not English class.
Good luck with your code.**

Sorry, I didn’t mean to insult. Youre right, this isnt english class. But with how much you’ve helped me, I just wanted to try n be helpful too.
In regards with func/variable names: YourX might be misleading if it should be YoureX, that’s all.

Cheers for your help. I shall try extending my class from Volume and seeing if function is called. BoxComponent has a PhysVolume, but I’m guessing ActorEnteredVolume doesn’t call OnComponentBeginOverlap ?
This is what I’m unsure of, is how to access that function ActorEnteredVolume. As I can’t use a delegate for it.
Would you recommend I inherit from Volume rather than Actor and use the function that way?

@Shmoopy1701 excellent name lol. Your code example, I get, but it would only work for Pawn. If I’m spawning multiplayer players they would each potentially need to know about first check point.
Would you recommend that I instead inherit from Volume ? Or do you know how I can access BoxComponent->GetPhysVolume()->ActorEnteredVolume from my CheckPoint class ?

Cheers guys, both been incredibly helpful !

The way they extend is Actor to brush to volume to physics volume. Brush has the BoxComponent so anything above brush and on will have a BoxComponent. ActorEnteredVolume does not get added until the physics volume. EncompassesPoint() gets added at volume. The scan from world if using EncompassesPoint() needs physic volumes. Anything below the physics volume do not add into the world array. So that you can get get them later on, unless you add them your self into the gamestate. Then you could scan for them from it. Once you have made an array and added them to it.

In the above code it shows how to use ActorEnteredVolume function. I extended the physics volume with my volumes and that is what i used in the above tests. In my volume i put in the ActorEnteredVolume function

You can extend what ever you want, but you will have to know how to achieve what you are after, to get it working. if you are not using existing code functions. then you will have to make everything yourself to achieve what you are after. I would recommend using existing functions. Unless your comfortable writing all your own custom functions to achieve what you are after.

Edit: You keep going back to the BoxComponent. Once you make yourself a checkpoint. and you go into the editor click on volumes on the left and scroll the list you should find your volume in that list to put into your map to size. Once you put it into your map you will need to edit the collision setting on the volume properties for it to actual work right. Did not know if you knew that or not.

@gamepainters
I should have shown my code earlier, to explain why I keep mentioning “BoxComponent” - it’s just that that is the component I originally added, and just wanted to make sure I’m ok to replace it with Volume (as youv’re recommended).
(How are you able to keep code format in the CODE blocks btw?)

WP_CheckPoint.cpp (inherits AActor)



#include "WP_Checkpoint.h"
#include "WaterproofCharacter.h"
#include "Particles/ParticleSystemComponent.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/PhysicsVolume.h"
#include "Components/BoxComponent.h"

// Sets default values
AWP_Checkpoint::AWP_Checkpoint()
{
// 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;


// new collision - replace BoxComponent ?
TouchVolume = CreateDefaultSubobject<AVolume>(TEXT("TouchVolume"));

// set collision
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxCollision"));
BoxComponent->SetBoxExtent(FVector(150, 150, 40), false);
BoxComponent->SetSimulatePhysics(false);
BoxComponent->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);


RootComponent = BoxComponent;

// Add idle mesh
MeshIdle = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation1"));
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshIdleAsset(TEXT("/Game/Checkpoint/sign_sign.sign_sign"));
if (MeshIdleAsset.Succeeded())
{
MeshIdle->SetStaticMesh(MeshIdleAsset.Object);
MeshIdle->SetupAttachment(RootComponent);
}

// Add acitvated mesh
MeshActive = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation2"));
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshActiveAsset(TEXT("/Game/Checkpoint/arrow_arrow_1.arrow_arrow_1"));
if (MeshActiveAsset.Succeeded())
{
MeshActive->SetStaticMesh(MeshActiveAsset.Object);
MeshActive->SetupAttachment(RootComponent);
}

// add explosion FX
static ConstructorHelpers::FObjectFinder<UParticleSystem> Particle2(TEXT("/Game/StarterContent/Particles/P_Explosion.P_Explosion"));
PFXExplosion = Particle2.Object;
}

// Called when the game starts or when spawned
void AWP_Checkpoint::BeginPlay()
{
Super::BeginPlay();

APhysicsVolume* volume = BoxComponent->GetPhysicsVolume();
//volume->ActorEnteredVolume.AddDynamic(this, &AWP_Checkpoint::ActorEnteredVolume);

// Set on overlap
BoxComponent->OnComponentBeginOverlap.AddDynamic(this, &AWP_Checkpoint::OnOverlapBegin);
}


void AWP_Checkpoint::ActorEnteredVolume(AActor* Other)
{

}

void AWP_Checkpoint::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// if this has been activated by any player then dont do it again
if (bActivated || TouchingCharacters.Contains(OtherActor))
return;


// only acitvate for WPCharacter
AWaterproofCharacter* player = Cast<AWaterproofCharacter>(OtherActor);
if (player) {
bActivated = true;

// show particle effect
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), PFXExplosion, GetActorLocation(), FRotator::ZeroRotator, true);

player->HitCheckPoint(this);

TouchingCharacters.AddUnique(player);

MeshActive->SetVisibility(true);
MeshIdle->SetVisibility(false);

}
}




From what youre saying, I think I’d have to make my own CustomVolume, right? Then I can override ActorEntered and handle on Spawn AND on Touch/Overlap ?
And then I repalce BoxComp with that?
Or, should I just have my CheckPoint inherit from Volume and not Actor?

Yes

Extend it from the physics volume. If you want to use ActorEnteredVolume()

In editor top left click file, then new c++ class click that. When that pop up opens in the top right there’s a small box. I think it says show classes, check that then you can scroll thru all the classes so you can choose what to extend from. You need the physics volume. Once you find the Actor class, which is at the top. Click the plus next to it. That will open it, then go to Actor then to brush then to volume then to physics volume. name it what you like and if everything set click create class then you will make yourself that new class extended from what you chose.

If you want your files put into private/public folders then in a named folder. Then click public, then choose the folder you want them in. Example


YourProject/Private/Volumes/WP_Checkpoint.cpp
YourProject/Public/Volumes/WP_Checkpoint.h

Then it will save your files like so in those folder named that.