Overview
GS_Core includes a rich set of utility libraries for common game development patterns. These are header-only (or lightweight) utilities that any component or system can use without additional setup.
This is the multi-page printable view of this section. Click here to print.
GS_Core includes a rich set of utility libraries for common game development patterns. These are header-only (or lightweight) utilities that any component or system can use without additional setup.
PhysicsTriggeringVolume is a base class that provides everything needed to process physics trigger overlaps and collision contacts. Inherit from it to create interactive volumes — damage zones, pickup areas, dialogue triggers, environmental hazards — without writing boilerplate physics code.
It handles entity tracking (so you only get one enter/exit per entity), supports both trigger overlaps and collision contacts, and provides optional hold/persist callbacks for continuous processing.
TypeId: {A0C4C982-1B31-4FD3-9386-AD1A57ABEF8E}
PhysicsTriggeringVolume (which itself inherits from AZ::Component).The base class maintains an internal m_entities list that tracks which entities are currently inside the volume. This ensures:
TriggerEnter / CollisionEnter fires only once per entity (not on every physics tick).TriggerExit / CollisionExit fires only when an entity that was previously inside leaves.Override these to react to PhysX trigger volume events.
| Method | Description |
|---|---|
TriggerEnter() | Called when a new entity enters the trigger volume. |
TriggerExit() | Called when an entity leaves the trigger volume. |
TriggerHold() | Called on each physics tick while an entity remains inside. Requires EnableTriggerHoldUpdate to be enabled. |
Override these to react to PhysX rigid body collision events.
| Method | Description |
|---|---|
CollisionEnter() | Called when a new entity begins colliding with this volume. |
CollisionExit() | Called when an entity stops colliding with this volume. |
CollisionHold() | Called on each physics tick while collision persists. Requires EnableTriggerHoldUpdate to be enabled via OnCollisionPersist. |
| Property | Description |
|---|---|
EnableTriggerHoldUpdate | Enables the TriggerHold() / CollisionHold() callbacks on each physics tick. Disabled by default for performance. |
public virtual to avoid double-inheritance issues with AZ::Component. Do not add a second AZ::Component inheritance in your class.#pragma once
#include <GS_Core/Utilities/PhysicsTriggeringVolume.h>
namespace MyProject
{
class DamageZoneComponent
: public virtual GS_Core::PhysicsTriggeringVolume
{
public:
AZ_COMPONENT_DECL(DamageZoneComponent);
static void Reflect(AZ::ReflectContext* context);
protected:
// IMPORTANT: Call parent Activate/Deactivate
void Activate() override;
void Deactivate() override;
// Trigger overrides
void TriggerEnter() override;
void TriggerExit() override;
void TriggerHold() override;
private:
float m_damagePerSecond = 10.0f;
};
}
#include "DamageZoneComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace MyProject
{
AZ_COMPONENT_IMPL(DamageZoneComponent, "DamageZoneComponent", "{YOUR-UUID-HERE}");
void DamageZoneComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<DamageZoneComponent, GS_Core::PhysicsTriggeringVolume>()
->Version(0)
->Field("DamagePerSecond", &DamageZoneComponent::m_damagePerSecond);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<DamageZoneComponent>(
"Damage Zone", "Deals damage to entities inside the trigger volume")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "MyProject")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->DataElement(AZ::Edit::UIHandlers::Default,
&DamageZoneComponent::m_damagePerSecond,
"Damage Per Second", "How much damage to deal per second while inside");
}
}
}
void DamageZoneComponent::Activate()
{
// IMPORTANT: Call parent to connect to physics buses
PhysicsTriggeringVolume::Activate();
// Enable hold updates for continuous damage
// EnableTriggerHoldUpdate = true;
}
void DamageZoneComponent::Deactivate()
{
// IMPORTANT: Call parent to disconnect from physics buses
PhysicsTriggeringVolume::Deactivate();
}
void DamageZoneComponent::TriggerEnter()
{
// An entity entered the damage zone
AZ_TracePrintf("DamageZone", "Entity entered damage zone");
}
void DamageZoneComponent::TriggerExit()
{
// An entity left the damage zone
AZ_TracePrintf("DamageZone", "Entity exited damage zone");
}
void DamageZoneComponent::TriggerHold()
{
// Called each physics tick while entity is inside
// Apply damage: m_damagePerSecond * deltaTime
}
}
m_descriptors.insert(m_descriptors.end(), {
MyProject::DamageZoneComponent::CreateDescriptor(),
});
DamageZoneComponent).Helper functions for finding entities by name.
| Function | Description |
|---|---|
EntityUtility::GetEntityByName(name) | Returns the entity pointer for the named entity. |
EntityUtility::GetEntityIdByName(name) | Returns the EntityId for the named entity. |
PhysicsTriggeringVolume is a base class that provides everything needed to process physics trigger overlaps and collision contacts. Inherit from it to create interactive volumes — damage zones, pickup areas, dialogue triggers, environmental hazards — without writing boilerplate physics code.
It handles entity tracking (so you only get one enter/exit per entity), supports both trigger overlaps and collision contacts, and provides optional hold/persist callbacks for continuous processing.
TypeId: {A0C4C982-1B31-4FD3-9386-AD1A57ABEF8E}
PhysicsTriggeringVolume (which itself inherits from AZ::Component).The base class maintains an internal m_entities list that tracks which entities are currently inside the volume. This ensures:
TriggerEnter / CollisionEnter fires only once per entity (not on every physics tick).TriggerExit / CollisionExit fires only when an entity that was previously inside leaves.Override these to react to PhysX trigger volume events.
| Method | Description |
|---|---|
TriggerEnter() | Called when a new entity enters the trigger volume. |
TriggerExit() | Called when an entity leaves the trigger volume. |
TriggerHold() | Called on each physics tick while an entity remains inside. Requires EnableTriggerHoldUpdate to be enabled. |
Override these to react to PhysX rigid body collision events.
| Method | Description |
|---|---|
CollisionEnter() | Called when a new entity begins colliding with this volume. |
CollisionExit() | Called when an entity stops colliding with this volume. |
CollisionHold() | Called on each physics tick while collision persists. Requires EnableTriggerHoldUpdate to be enabled via OnCollisionPersist. |
| Property | Description |
|---|---|
EnableTriggerHoldUpdate | Enables the TriggerHold() / CollisionHold() callbacks on each physics tick. Disabled by default for performance. |
public virtual to avoid double-inheritance issues with AZ::Component. Do not add a second AZ::Component inheritance in your class.#pragma once
#include <GS_Core/Utilities/PhysicsTriggeringVolume.h>
namespace MyProject
{
class DamageZoneComponent
: public virtual GS_Core::PhysicsTriggeringVolume
{
public:
AZ_COMPONENT_DECL(DamageZoneComponent);
static void Reflect(AZ::ReflectContext* context);
protected:
// IMPORTANT: Call parent Activate/Deactivate
void Activate() override;
void Deactivate() override;
// Trigger overrides
void TriggerEnter() override;
void TriggerExit() override;
void TriggerHold() override;
private:
float m_damagePerSecond = 10.0f;
};
}
#include "DamageZoneComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace MyProject
{
AZ_COMPONENT_IMPL(DamageZoneComponent, "DamageZoneComponent", "{YOUR-UUID-HERE}");
void DamageZoneComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<DamageZoneComponent, GS_Core::PhysicsTriggeringVolume>()
->Version(0)
->Field("DamagePerSecond", &DamageZoneComponent::m_damagePerSecond);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<DamageZoneComponent>(
"Damage Zone", "Deals damage to entities inside the trigger volume")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "MyProject")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->DataElement(AZ::Edit::UIHandlers::Default,
&DamageZoneComponent::m_damagePerSecond,
"Damage Per Second", "How much damage to deal per second while inside");
}
}
}
void DamageZoneComponent::Activate()
{
// IMPORTANT: Call parent to connect to physics buses
PhysicsTriggeringVolume::Activate();
// Enable hold updates for continuous damage
// EnableTriggerHoldUpdate = true;
}
void DamageZoneComponent::Deactivate()
{
// IMPORTANT: Call parent to disconnect from physics buses
PhysicsTriggeringVolume::Deactivate();
}
void DamageZoneComponent::TriggerEnter()
{
// An entity entered the damage zone
AZ_TracePrintf("DamageZone", "Entity entered damage zone");
}
void DamageZoneComponent::TriggerExit()
{
// An entity left the damage zone
AZ_TracePrintf("DamageZone", "Entity exited damage zone");
}
void DamageZoneComponent::TriggerHold()
{
// Called each physics tick while entity is inside
// Apply damage: m_damagePerSecond * deltaTime
}
}
m_descriptors.insert(m_descriptors.end(), {
MyProject::DamageZoneComponent::CreateDescriptor(),
});
DamageZoneComponent).Multi-stop gradient utilities for sampling color, float, or vector values along a 0.0–1.0 range.
| Gradient | Description |
|---|---|
ColorGradient | Multi-stop color gradient with ColorGradientMarker entries (color + position). Sample at any point for interpolated color. |
FloatGradient | Float value gradient for numeric curves. |
Vector2Gradient | 2D vector gradient. |
Helper functions for working with O3DE spline components.
| Function | Description |
|---|---|
SplineUtility::FindClosestWorldPoint(spline, worldPos) | Finds the closest point on the spline in world space. |
SplineUtility::FindClosestLocalPoint(spline, localPos) | Finds the closest point on the spline in local space. |
SplineUtility::FindClosestFraction(spline, worldPos) | Returns the 0.0–1.0 fraction along the spline closest to the given world position. |
A library of 40+ easing curve functions for animation, transitions, and interpolation. Each curve type comes in three variants: Ease In, Ease Out, and Ease In-Out.
All functions take and return clamped values between 0.0 and 1.0 (available as both float and double).
| Curve | Character |
|---|---|
Linear | Constant speed — no easing |
Quadratic | Gentle acceleration/deceleration |
Cubic | Moderate acceleration/deceleration |
Quartic | Strong acceleration/deceleration |
Quintic | Very strong acceleration/deceleration |
Sinusoidal | Smooth, natural-feeling motion |
Exponential | Sharp acceleration, gradual deceleration (or vice versa) |
Circular | Based on circular arc — distinct feel |
Elastic | Overshoots and springs back |
Back | Pulls back before moving forward |
Bounce | Bounces at the end |
The CurveType enum ({A9718DE5-BFD6-4206-A8B8-0DEB7B7162F2}) can be reflected to the inspector, allowing designers to select easing curves from a dropdown in the Entity Inspector.
A collection of critically damped spring functions for smooth, controlled blending between current and target values. Springs are ideal for camera follow, UI animations, procedural motion, and any system that needs to track a moving target without oscillation.
Supports float, AZ::Vector2, AZ::Vector3, and AZ::Quaternion data types.
| Spring | Description |
|---|---|
SimpleSpring | Basic critically damped spring. Good for most smoothing needs. |
AccelerationSpring | Spring with acceleration control. Good for smooth starts. |
DoubleSpring | Two-pass spring for extra-smooth results. Good for camera follow. |
TimedSpring | Spring that reaches the target in a specified time. Good for UI transitions. |
VelocitySpring | Spring with explicit velocity tracking. Good for physics-driven motion. |
QuaternionSpring | Rotation-specific spring. Good for camera and character rotation smoothing. |
Helper functions for angle-based section mapping and orientation conversion.
| Function | Description |
|---|---|
SectionByAngle::PickByAngle(angle, config) | Maps an angle to a section index using a predefined config. Useful for 4-directional or 8-directional animation selection. |
SectionByAngle::YawFromDir(direction) | Converts a direction vector to a yaw angle. |
SectionByAngle::QuatFromYaw(yaw) | Converts a yaw angle to a quaternion rotation. |
Includes 22 predefined SectionConfig presets for common angle-to-section mapping patterns (4-way, 8-way, etc.).
PhysicsTriggeringVolume is a base class that provides everything needed to process physics trigger overlaps and collision contacts. Inherit from it to create interactive volumes — damage zones, pickup areas, dialogue triggers, environmental hazards — without writing boilerplate physics code.
It handles entity tracking (so you only get one enter/exit per entity), supports both trigger overlaps and collision contacts, and provides optional hold/persist callbacks for continuous processing.
TypeId: {A0C4C982-1B31-4FD3-9386-AD1A57ABEF8E}
PhysicsTriggeringVolume (which itself inherits from AZ::Component).The base class maintains an internal m_entities list that tracks which entities are currently inside the volume. This ensures:
TriggerEnter / CollisionEnter fires only once per entity (not on every physics tick).TriggerExit / CollisionExit fires only when an entity that was previously inside leaves.Override these to react to PhysX trigger volume events.
| Method | Description |
|---|---|
TriggerEnter() | Called when a new entity enters the trigger volume. |
TriggerExit() | Called when an entity leaves the trigger volume. |
TriggerHold() | Called on each physics tick while an entity remains inside. Requires EnableTriggerHoldUpdate to be enabled. |
Override these to react to PhysX rigid body collision events.
| Method | Description |
|---|---|
CollisionEnter() | Called when a new entity begins colliding with this volume. |
CollisionExit() | Called when an entity stops colliding with this volume. |
CollisionHold() | Called on each physics tick while collision persists. Requires EnableTriggerHoldUpdate to be enabled via OnCollisionPersist. |
| Property | Description |
|---|---|
EnableTriggerHoldUpdate | Enables the TriggerHold() / CollisionHold() callbacks on each physics tick. Disabled by default for performance. |
public virtual to avoid double-inheritance issues with AZ::Component. Do not add a second AZ::Component inheritance in your class.#pragma once
#include <GS_Core/Utilities/PhysicsTriggeringVolume.h>
namespace MyProject
{
class DamageZoneComponent
: public virtual GS_Core::PhysicsTriggeringVolume
{
public:
AZ_COMPONENT_DECL(DamageZoneComponent);
static void Reflect(AZ::ReflectContext* context);
protected:
// IMPORTANT: Call parent Activate/Deactivate
void Activate() override;
void Deactivate() override;
// Trigger overrides
void TriggerEnter() override;
void TriggerExit() override;
void TriggerHold() override;
private:
float m_damagePerSecond = 10.0f;
};
}
#include "DamageZoneComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace MyProject
{
AZ_COMPONENT_IMPL(DamageZoneComponent, "DamageZoneComponent", "{YOUR-UUID-HERE}");
void DamageZoneComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<DamageZoneComponent, GS_Core::PhysicsTriggeringVolume>()
->Version(0)
->Field("DamagePerSecond", &DamageZoneComponent::m_damagePerSecond);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<DamageZoneComponent>(
"Damage Zone", "Deals damage to entities inside the trigger volume")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "MyProject")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->DataElement(AZ::Edit::UIHandlers::Default,
&DamageZoneComponent::m_damagePerSecond,
"Damage Per Second", "How much damage to deal per second while inside");
}
}
}
void DamageZoneComponent::Activate()
{
// IMPORTANT: Call parent to connect to physics buses
PhysicsTriggeringVolume::Activate();
// Enable hold updates for continuous damage
// EnableTriggerHoldUpdate = true;
}
void DamageZoneComponent::Deactivate()
{
// IMPORTANT: Call parent to disconnect from physics buses
PhysicsTriggeringVolume::Deactivate();
}
void DamageZoneComponent::TriggerEnter()
{
// An entity entered the damage zone
AZ_TracePrintf("DamageZone", "Entity entered damage zone");
}
void DamageZoneComponent::TriggerExit()
{
// An entity left the damage zone
AZ_TracePrintf("DamageZone", "Entity exited damage zone");
}
void DamageZoneComponent::TriggerHold()
{
// Called each physics tick while entity is inside
// Apply damage: m_damagePerSecond * deltaTime
}
}
m_descriptors.insert(m_descriptors.end(), {
MyProject::DamageZoneComponent::CreateDescriptor(),
});
DamageZoneComponent).The Random utilities provide weighted random selection for gameplay and procedural systems. The primary utility is GetRandomWeighted, a template function that selects an item from a collection based on assigned weights — higher weights mean higher probability of selection.
| Function | Description |
|---|---|
GetRandomWeighted<T>(collection) | Selects a random item from a weighted collection. Each item must provide a weight value. Items with higher weights are proportionally more likely to be selected. |
#include <GS_Core/Utilities/RandomUtils.h>
// Define weighted items (e.g., loot drops)
struct LootEntry
{
AZStd::string itemName;
float weight; // Higher = more common
};
AZStd::vector<LootEntry> lootTable = {
{ "Common Sword", 50.0f },
{ "Rare Shield", 30.0f },
{ "Epic Helmet", 15.0f },
{ "Legendary Ring", 5.0f },
};
// Select a random item weighted by drop rate
auto selected = GS_Core::RandomUtils::GetRandomWeighted(lootTable);
// "Common Sword" is 10x more likely than "Legendary Ring"
The Actions system provides a simple, universal pattern for triggering discrete behaviors. Instead of recoding common functionality (toggle cursor, play sound, print log) into every component that needs it, you attach Action components to an entity and fire them by channel name.
Actions support chaining — when one action completes, it can fire another action on a different channel, enabling lightweight sequences without custom code.
Entity with Actions
│
├── ToggleMouseCursor_GSAction (channel: "enter_menu")
├── PlaySound_GSAction (channel: "enter_menu")
└── PrintLog_GSAction (channel: "debug")
Any system calls:
ActionIncomingEventBus::Event(entityId, DoAction, "enter_menu")
→ Both ToggleMouseCursor and PlaySound fire (matching channel)
→ PrintLog does NOT fire (different channel)
| Component | Purpose | Documentation |
|---|---|---|
| GS_ActionComponent | Base class for all actions. Handles channel matching, completion broadcasting, and action chaining. | Action |
| ToggleMouseCursor_GSActionComponent | Toggles the mouse cursor on or off. | Core Actions |
| PrintLog_GSActionComponent | Prints a message to the console log. | Core Actions |
DoAction(channelName) on the entity’s ActionIncomingEventBus to trigger matching actions.GS_ActionComponent is the base class for all triggerable actions. Actions are single-purpose behaviors that fire when their channel matches an incoming DoAction call. They support completion broadcasting and optional chaining to sequence multiple actions together.
Every GS_Play action (Toggle Mouse Cursor, Print Log, and actions from other gems) extends this class. When you need a custom action, you extend it too.
DoAction(targetChannel) on an entity’s ActionIncomingEventBus.targetChannel.ProcessAction() to execute their behavior.CompleteAction() handles completion:OnActionComplete on the ActionOutgoingEventBus.DoAction with that channel name, triggering the next action in the chain.By setting the On Complete Channel Chain to a different channel name, an action can trigger the next step in a sequence when it completes. This enables lightweight behavior chains without custom sequencing code.
Action A (channel: "step1", onCompleteChain: "step2")
→ fires → Action B (channel: "step2", onCompleteChain: "step3")
→ fires → Action C (channel: "step3")
Important: Every custom action must call
CompleteAction()when its work is done. If you forget, the action will never complete and chains will break.
| Property | Type | Default | Description |
|---|---|---|---|
| Channel | AZStd::string | "" | The channel this action responds to. Only DoAction calls with a matching channel will trigger this action. |
| Broadcast On Complete | bool | false | When enabled, broadcasts OnActionComplete on the ActionOutgoingEventBus when this action finishes. |
| On Complete Channel Chain | AZStd::string | "" | When non-empty, fires a new DoAction with this channel name after completing. Enables action chaining. |
ActionIncomingEventBusEntity-addressed bus — call via Event(entityId, ...).
| Method | Parameters | Returns | Description |
|---|---|---|---|
DoAction | AZStd::string targetChannel | void | Triggers all actions on the target entity whose channel matches targetChannel. |
ActionOutgoingEventBusEntity-addressed bus — connect via BusConnect(entityId).
| Event | Parameters | Description |
|---|---|---|
OnActionComplete | — | Broadcast when an action with Broadcast On Complete enabled finishes its work. |
Override these when creating custom actions.
| Method | Description |
|---|---|
DoAction(targetChannel) | Evaluates whether this action should fire. Default compares channel to targetChannel. Override for custom evaluation logic. |
ProcessAction() | Your primary override. Executes the action’s behavior. Called when channel evaluation passes. |
CompleteAction() | Handles completion. Default checks broadcastOnComplete, fires OnActionComplete, then checks onCompleteChannelChain for chaining. Override to add custom completion logic, but always call base or handle chaining manually. |
#include <GS_Core/GS_CoreBus.h>
// Fire all actions on this entity that match the "open_door" channel
GS_Core::ActionIncomingEventBus::Event(
targetEntityId,
&GS_Core::ActionIncomingEventBus::Events::DoAction,
AZStd::string("open_door")
);
#include <GS_Core/GS_CoreBus.h>
class MyActionListener
: public AZ::Component
, protected GS_Core::ActionOutgoingEventBus::Handler
{
protected:
void Activate() override
{
// Listen for action completions on a specific entity
GS_Core::ActionOutgoingEventBus::Handler::BusConnect(m_targetEntityId);
}
void Deactivate() override
{
GS_Core::ActionOutgoingEventBus::Handler::BusDisconnect();
}
void OnActionComplete() override
{
// An action on the target entity has completed
// React accordingly (advance dialogue, open next door, etc.)
}
private:
AZ::EntityId m_targetEntityId;
};
Create a custom action whenever you need a reusable, triggerable behavior that can be attached to any entity.
#pragma once
#include <Source/ActionSystem/GS_ActionComponent.h>
namespace MyProject
{
class PlayEffect_GSActionComponent
: public GS_Core::GS_ActionComponent
{
public:
AZ_COMPONENT_DECL(PlayEffect_GSActionComponent);
static void Reflect(AZ::ReflectContext* context);
protected:
// Action overrides
void ProcessAction() override;
void CompleteAction() override;
private:
AZStd::string m_effectName;
float m_duration = 1.0f;
};
}
#include "PlayEffect_GSActionComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace MyProject
{
AZ_COMPONENT_IMPL(PlayEffect_GSActionComponent, "PlayEffect_GSActionComponent", "{YOUR-UUID-HERE}",
GS_Core::GS_ActionComponent);
void PlayEffect_GSActionComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<PlayEffect_GSActionComponent, GS_Core::GS_ActionComponent>()
->Version(0)
->Field("EffectName", &PlayEffect_GSActionComponent::m_effectName)
->Field("Duration", &PlayEffect_GSActionComponent::m_duration);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
// Pattern: Incoming Channel → Feature Properties → Outgoing Channel
editContext->Class<PlayEffect_GSActionComponent>(
"Play Effect Action", "Triggers a named particle effect")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "MyProject/Actions")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->DataElement(AZ::Edit::UIHandlers::Default,
&PlayEffect_GSActionComponent::m_effectName, "Effect Name",
"Name of the particle effect to trigger")
->DataElement(AZ::Edit::UIHandlers::Default,
&PlayEffect_GSActionComponent::m_duration, "Duration",
"How long the effect plays (seconds)");
}
}
}
void PlayEffect_GSActionComponent::ProcessAction()
{
// Your action logic — trigger the particle effect
AZ_TracePrintf("Action", "Playing effect: %s for %.1f seconds",
m_effectName.c_str(), m_duration);
// ... spawn particle effect, start timer, etc. ...
// IMPORTANT: Call CompleteAction when done
// If the action is instant, call it here.
// If it takes time (animation, timer), call it when the effect finishes.
CompleteAction();
}
void PlayEffect_GSActionComponent::CompleteAction()
{
// Custom completion logic (if any)
// ...
// IMPORTANT: Call base to handle broadcast and chaining
GS_ActionComponent::CompleteAction();
}
}
m_descriptors.insert(m_descriptors.end(), {
MyProject::PlayEffect_GSActionComponent::CreateDescriptor(),
});
When reflecting custom action properties in the Edit Context, follow this organization pattern so all actions have a consistent inspector layout:
channel property (inherited, reflected by base class)broadcastOnComplete and onCompleteChannelChain properties (inherited, reflected by base class)GS_Core includes pre-built Action components for common behaviors. Attach them to any entity, set a channel, and fire them from any system without writing code.
All built-in actions inherit from GS_ActionComponent and follow the same channel-matching, completion, and chaining patterns.
Toggles the operating system mouse cursor on or off.
Use this action when transitioning between gameplay (cursor hidden) and menus (cursor visible). Common triggers include opening an inventory, entering a pause menu, or starting a dialogue sequence.
| Property | Type | Default | Description |
|---|---|---|---|
| Channel | AZStd::string | "" | Inherited. The channel this action responds to. |
| Broadcast On Complete | bool | false | Inherited. Broadcasts OnActionComplete when the toggle finishes. |
| On Complete Channel Chain | AZStd::string | "" | Inherited. Fires a follow-up DoAction on completion for chaining. |
#include <GS_Core/GS_CoreBus.h>
// Toggle the cursor when opening the pause menu
GS_Core::ActionIncomingEventBus::Event(
uiEntityId,
&GS_Core::ActionIncomingEventBus::Events::DoAction,
AZStd::string("toggle_cursor")
);
Prints a configurable message to the console log. Useful for debugging action chains, verifying event flow, or logging gameplay milestones.
Use this action during development to verify that action channels fire correctly, test chaining sequences, or log gameplay events without writing custom components.
| Property | Type | Default | Description |
|---|---|---|---|
| Channel | AZStd::string | "" | Inherited. The channel this action responds to. |
| Message | AZStd::string | "" | The message to print to the console log. |
| Broadcast On Complete | bool | false | Inherited. Broadcasts OnActionComplete when the print finishes. |
| On Complete Channel Chain | AZStd::string | "" | Inherited. Fires a follow-up DoAction on completion for chaining. |
#include <GS_Core/GS_CoreBus.h>
// Trigger a debug log message
GS_Core::ActionIncomingEventBus::Event(
debugEntityId,
&GS_Core::ActionIncomingEventBus::Events::DoAction,
AZStd::string("debug")
);
// Console output: whatever message was configured on the PrintLog action
Need custom behavior? See the Extending the Action Class guide for a complete walkthrough with header, implementation, Reflect pattern, and module registration.