We create a new Actor class and add a box component to give the actor something that will collide with the character. Alternatively, you could subclass AVolume if you wanted to use the Binary Space Partitioning (BSP) functionality to define the volume's shape (found under Geometry in the Place section of the Modes tab).
NotifyActorBeginOverlap and NotifyActorEndOverlap are overridden so that we can perform an operation when an object enters or leaves the AntiGravityVolume area.
Inside theĀ NotifyActorBeginOverlap implementation, we attempt to cast the object that overlapped us into an IGravityObject pointer. This tests whether the object in question implements the interface. If the pointer is valid, then the object does implement the interface, so it is safe to use the interface pointer to call Interface methods on the object.
Given that we are inside NotifyActorBeginOverlap, we want to disable gravity on the object, so we call DisableGravity(). Inside NotifyActorEndOverlap, we perform the same check, but we re-enable gravity on the object. Within the default implementation of DisableGravity, we cast our own pointer (the this pointer) to AActor. This allows us to confirm that the interface has been implemented only on the Actor subclasses, and to call methods defined in AActor.
If the pointer is valid, we know we are an Actor, so we can use GetComponents<class ComponentType>() to get a TArray of all components of a specific type from ourselves. GetComponents is a template function. It expects some template parameters, as follows:
template<class T, class AllocatorType>
voidGetComponents(TArray<T*, AllocatorType>&OutComponents)
const
Since the 2014 version of the standard, C++ supports compile-time deduction of template parameters. This means that we don't need to actually specify the template parameters when we call the function if the compiler can work them out from the normal function parameters that we provide.
The default implementation of TArray is template<typename T, typename Allocator = FDefaultAllocator> class TArray;. This means that we don't need to specify an allocator by default, so we just use TArray<UPrimitiveComponent*> when we declare the array.
When TArray is passed into the GetComponents function, the compiler knows it is actually TArray<UPrimitiveComponent*, FDefaultAllocator>, and it is able to fill in the template parameters T and AllocatorType with UPrimitiveComponent and FDefaultAllocator, so neither of those are required as template parameters for the function's invocation.
GetComponents iterates through the components that Actor has, and any components that inherit from typename T have pointers to them stored inside the PrimitiveComponents array.
Using a range-based for loop, another new feature of C++, we can iterate over the components that the function placed into our TArray without needing to use the traditional for loop structure.
Each of the components has SetEnableGravity(false) called on them, which disables gravity.
Likewise, the EnableGravity function iterates over all the primitive components contained in the actor, and enables gravity with SetEnableGravity(true).