Executable Item
v1.0
Overview
ExecutableItem
is the base class for all items that can be executed by an ActionExecutor
. There are two concrete implementations:
ActionItem - Wraps a single
Action
asset and executes itGroupItem - Contains multiple
ExecutableItem
s that execute in parallel with configurable exit conditions
Both types support conditionals, chance-based execution, looping, and runtime lookup via unique identifiers (UIDs).
ActionItem vs GroupItem
An ActionItem
represents a single action from your Action assets.
A GroupItem
represents a collection of items. Groups can contain both ActionItem
s and nested GroupItem
s. Group Items have exit conditions, which determine when the Executor will start the next ExecutableItem
.
Barrier
Wait for all items to complete
Synchronized animations, coordinated effects
Race
Complete when first item finishes
Competitive animations, interrupt-driven sequences
Timed
Complete after a fixed duration
Time-limited effects, fire-and-forget groups
Looking Up ExecutableItems
by Unique ID (UID)
ExecutableItems
by Unique ID (UID)Every ExecutableItem
has a unique identifier that's automatically generated and persisted. This can be modified to a custom string in the Inspector, when viewing any Action Executor.

You can look up items in any ActionExecutor
programmatically using their UID.
using MagicPigGames.JuicyActions;
public class AbilityController : MonoBehaviour
{
[SerializeField] private ActionExecutor executor;
[SerializeField] private string criticalHitActionUID;
public void TriggerCriticalHit()
{
// Look up the specific action by its UID
var criticalHitItem = executor.GetExecutableItem(criticalHitActionUID);
if (criticalHitItem != null && criticalHitItem is ActionItem actionItem)
{
// Modify the action before it executes
actionItem.chances = 1f; // Guarantee execution
actionItem.enabled = true;
}
executor.Execute(this);
}
}
Working with ExecutableItems
Accessing Items from ActionExecutor
using MagicPigGames.JuicyActions;
public class DynamicActionController : MonoBehaviour
{
[SerializeField] private ActionExecutor executor;
void Start()
{
// Get all items
var allItems = executor.Items;
// Iterate through items
foreach (var item in allItems)
{
Debug.Log($"Item UID: {item.UID}");
Debug.Log($"Item Type: {(item.IsAction ? "Action" : "Group")}");
Debug.Log($"Enabled: {item.enabled}");
Debug.Log($"Chances: {item.chances}");
}
}
}
Modifying Items at Runtime
using MagicPigGames.JuicyActions;
public class DifficultyManager : MonoBehaviour
{
[SerializeField] private ActionExecutor bossAbilities;
public void SetDifficulty(float difficultyMultiplier)
{
foreach (var item in bossAbilities.Items)
{
if (item is ActionItem actionItem)
{
// Increase action frequency based on difficulty
actionItem.chances = Mathf.Clamp01(0.5f * difficultyMultiplier);
// Access the action's duration through overrides
if (actionItem.overrides != null)
{
// Make actions faster on higher difficulties
actionItem.overrides.timeBeforeNextAction /= difficultyMultiplier;
}
}
else if (item is GroupItem groupItem)
{
// Make group-based attacks more frequent
groupItem.chances = Mathf.Clamp01(0.3f * difficultyMultiplier);
}
}
}
}
Filtering Items
using System.Linq;
using MagicPigGames.JuicyActions;
public class ActionFilter : MonoBehaviour
{
[SerializeField] private ActionExecutor executor;
// Get all ActionItems
public List<ActionItem> GetAllActions()
{
return executor.Items
.Where(item => item.IsAction)
.Cast<ActionItem>()
.ToList();
}
// Get all GroupItems
public List<GroupItem> GetAllGroups()
{
return executor.Items
.Where(item => item.IsGroup)
.Cast<GroupItem>()
.ToList();
}
// Get all enabled items
public List<ExecutableItem> GetEnabledItems()
{
return executor.Items
.Where(item => item.enabled)
.ToList();
}
// Get items with chance > 0.5
public List<ExecutableItem> GetHighProbabilityItems()
{
return executor.Items
.Where(item => item.chances > 0.5f)
.ToList();
}
}
Common Properties
All ExecutableItem
s share these properties:
Basic Settings
// Enable/disable the item
item.enabled = true;
// Control execution probability (0.0 = never, 1.0 = always)
item.chances = 0.75f;
Conditional Execution
// Enable conditional checks
item.useConditional = true;
// Set how multiple conditions are combined
item.conditionalJoin = ConditionalJoin.And; // All must be true
// OR
item.conditionalJoin = ConditionalJoin.Or; // At least one must be true
// Add conditions (see Conditional documentation)
item.conditionals.Add(new Conditional());
Looping
// Enable looping
item.enableLoop = true;
// Set to infinite loop
item.infiniteLoop = true;
// OR set a specific loop count
item.infiniteLoop = false;
item.LoopCount = 3; // Execute 3 times
Runtime Loop State
// Check current loop iteration
int currentIteration = item.CurrentLoopIteration;
// Check if should continue looping
bool shouldLoop = item.ShouldContinueLooping();
// Reset loop state (called automatically by executor)
item.ResetLoopState();
// Increment loop counter (called automatically by executor)
item.IncrementLoopIteration();
Working with ActionItem Overrides
ActionItems support per-instance overrides without modifying the original Action asset.
Duration Overrides
var actionItem = executor.Items[0] as ActionItem;
if (actionItem != null && actionItem.overrides != null)
{
// Override the time before next action
actionItem.overrides.timeBeforeNextAction = 2.5f;
}
Field Overrides
For fields marked with [CanOverride]
or [MustOverride]
in your Action:
// Using ActionExecutor helper methods
executor.SetFieldOverride<MyCustomAction>("damageAmount", 50, turnOverrideOn: true);
// Check if override is enabled
bool isEnabled = executor.IsFieldOverrideEnabled<MyCustomAction>("damageAmount");
// Get override value
if (executor.TryGetFieldOverride<MyCustomAction, int>("damageAmount", out int damage))
{
Debug.Log($"Damage override: {damage}");
}
// Clear all overrides for an action type
executor.ClearFieldOverrides<MyCustomAction>();
Working with GroupItems
Accessing Group Contents
var groupItem = executor.Items[0] as GroupItem;
if (groupItem != null)
{
Debug.Log($"Group: {groupItem.name}");
Debug.Log($"Exit Condition: {groupItem.exitCondition}");
Debug.Log($"Item Count: {groupItem.items.Count}");
// Iterate through group items
foreach (var item in groupItem.items)
{
if (item.IsAction)
{
var action = item as ActionItem;
Debug.Log($" - Action: {action.actionAsset.name}");
}
else if (item.IsGroup)
{
var nestedGroup = item as GroupItem;
Debug.Log($" - Group: {nestedGroup.name}");
}
}
}
Modifying Group Behavior
var groupItem = executor.Items[0] as GroupItem;
if (groupItem != null)
{
// Change exit condition
groupItem.exitCondition = GroupExitCondition.Race;
// Set time limit for timed groups
groupItem.timeLimit = 5f;
// End actions when group exits
groupItem.endActionsOnExit = true;
// Add new items to the group at runtime
var newAction = new ActionItem
{
enabled = true,
actionAsset = myActionAsset,
overrides = new ActionOverrides()
};
groupItem.items.Add(newAction);
}
Advanced: Dynamic Item Management
Adding Items at Runtime
using MagicPigGames.JuicyActions;
public class DynamicActionBuilder : MonoBehaviour
{
[SerializeField] private ActionExecutor executor;
[SerializeField] private Action explosionAction;
[SerializeField] private Action soundAction;
public void AddExplosionCombo()
{
// Create a new group
var comboGroup = new GroupItem
{
enabled = true,
name = "Explosion Combo",
exitCondition = GroupExitCondition.Barrier,
items = new List<ExecutableItem>()
};
// Add explosion action
comboGroup.items.Add(new ActionItem
{
enabled = true,
actionAsset = explosionAction,
overrides = new ActionOverrides()
});
// Add sound action
comboGroup.items.Add(new ActionItem
{
enabled = true,
actionAsset = soundAction,
overrides = new ActionOverrides()
});
// Add the group to executor
executor.Items.Add(comboGroup);
}
}
Removing Items
// Remove by reference
executor.RemoveItem(item);
// Remove by UID
var itemToRemove = executor.GetExecutableItem(uid);
if (itemToRemove != null)
{
executor.RemoveItem(itemToRemove);
}
// Remove all items
executor.ClearActions();
Validation
ExecutableItems provide validation to help catch configuration errors:
var item = executor.Items[0];
// Validate the item
var issues = item.Validate();
if (issues.Count > 0)
{
Debug.LogWarning("Item validation issues:");
foreach (var issue in issues)
{
Debug.LogWarning($" - {issue}");
}
}
Common Validation Issues:
Missing action asset reference
Chances outside valid range (0-1)
Invalid loop count
Empty groups
Invalid conditional configuration
Best Practices
Use UIDs for Persistent References
// Store UIDs in serialized fields for persistent references
[SerializeField] private string ultimateAbilityUID;
void TriggerUltimate()
{
var item = executor.GetExecutableItem(ultimateAbilityUID);
if (item != null)
{
item.enabled = true;
executor.Execute(this);
}
}
Cache Item References
// Cache frequently accessed items
private ActionItem cachedPowerup;
void Start()
{
var item = executor.GetExecutableItem(powerupUID);
cachedPowerup = item as ActionItem;
}
void ActivatePowerup()
{
if (cachedPowerup != null)
{
cachedPowerup.chances = 1f;
}
}
Validate Before Execution
void ExecuteWithValidation()
{
foreach (var item in executor.Items)
{
var issues = item.Validate();
if (issues.Count > 0)
{
Debug.LogError($"Item {item.UID} has validation errors!");
return;
}
}
executor.Execute(this);
}
Use Groups for Coordinated Effects
// Instead of separate sequential actions
// Use a Barrier group to synchronize multiple effects
var effectGroup = new GroupItem
{
name = "Impact Effects",
exitCondition = GroupExitCondition.Barrier,
items = new List<ExecutableItem>
{
new ActionItem { actionAsset = particleAction },
new ActionItem { actionAsset = soundAction },
new ActionItem { actionAsset = cameraShakeAction }
}
};
Use Conditionals for State-Based Execution
// Configure items with conditionals rather than runtime enable/disable
var item = new ActionItem
{
enabled = true,
useConditional = true,
conditionalJoin = ConditionalJoin.And,
conditionals = new List<Conditional>
{
// Only execute when player health is low
new Conditional { /* configure health check */ }
}
};
See Also
Last updated
Was this helpful?