Skip to content

Using AI Tools to Create Actions

Many users like to use AI tools (ChatGPT, Claude, Gemini, etc.) to help generate new custom Actions.

AI and PlayMaker Versions

AI tools are already very good at generating PlayMaker 1–style actions, but PlayMaker 2 introduces an all-new Action API with a different variable system (Var/Ref), new execution patterns, new summary rules, and new update modes.

Without guidance, most AI tools will fall back to PM1 patterns and produce Actions that do not integrate correctly with PlayMaker 2.

The instruction file below teaches AI tools how the PlayMaker 2 Action system works so they can generate correct PM2 Actions.


Why you should use an AI instruction file

Large language models (LLMs) do not automatically know:

  • how PlayMaker 2’s Var/Ref variable system works
  • how to structure Actions correctly
  • how GetSummary placeholders work
  • how True/False (CheckXxx) Actions work
  • which UpdateModes exist
  • how events should be sent

Without guidance, most AI tools will produce code that compiles but does not integrate correctly with the PlayMaker 2 editor or runtime.

To solve this, we provide a minimal, AI-optimized instruction file.
When pasted into your AI tool, it trains the model to generate Actions that follow PM2 conventions.


How to use this with ChatGPT, Claude, Gemini, etc.

  1. Open your AI tool.
  2. Create a new “project”, “workspace” or “persistent instruction” (optional but recommended).
  3. Paste the entire instruction file (below) into:
  4. ChatGPT → Project Instructions
  5. Claude → Project instructions / memory
  6. Gemini → Custom Preferences / System Prompt
  7. Save the settings.
  8. Now ask the AI:

    “Create a PlayMaker 2 Action that does XYZ.”

  9. The generated action will now follow PM2 conventions automatically.

If you update to a newer version of PlayMaker 2, you can re-paste an updated instruction file here.


Copy-Paste Instruction File (for AI tools)

Click to expand:

Click to expand the AI-Only PlayMaker 2 Instruction File
# PlayMaker 2 – AI Instructions (Action Authoring)

Generate PlayMaker 2 actions that follow these rules exactly.

============================================================
1. Base Class & Naming
============================================================

All actions must inherit from BaseAction unless inheriting from
a specific PM2 base class such as BaseTrueFalseAction.

Private fields must use: _camelCase

Examples:
[SerializeField] private FloatVar _speed;
[SerializeField] private TransformVar _target;

============================================================
2. Variable System
============================================================

Use Var types for inputs:
- FloatVar, IntegerVar, BoolVar
- Vector2Var, Vector3Var, QuaternionVar
- ColorVar, LayerMaskVar
- GameObjectVar, TransformVar
- StringVar, StringListVar, FloatListVar, etc.
- EnumVar with [BaseType(typeof(SomeEnum))]

Use Ref types for outputs (always mark [WriteOnly]):
- FloatRef, IntegerRef, BoolRef, Vector3Ref, etc.

Inputs = Var  
Outputs = Ref  

Fields are required unless [OptionalField] is applied.

Use the most specific Var type:
- Prefer TransformVar over GameObjectVar if you need a Transform
- Prefer LayerMaskVar over int when representing layer masks

============================================================
3. Field Attributes
============================================================

Use these attributes when appropriate:

Class-level:
- [ActionCategory(Category.X)]
- [ActionDescription("...")]
- [HelpURL("...")]
- [ConvertibleGroup("GroupName")]

Field-level:
- [Tooltip("...")]
- [DefaultValue(...)]
- [VarRange(min,max)]
- [VarSlider(min,max)]
- [OptionalField]
- [WriteOnly]       // for outputs
- [GlobalEvent]
- [DefaultName("...")]
- [BaseType(typeof(SomeEnum))] // for EnumVar

============================================================
4. Update Modes (AI Reference)
============================================================

UpdateMode is a flags enum. Valid names are:

None
EveryFrame
Update
FixedUpdate
LateUpdate
OnEventUpdate
InputEveryFrame
OnAnimatorMove
AllUpdates
Blocking
AllowFinish
IgnorePerSecond
UpdateEveryFrame
FixedUpdateEveryFrame

Most commonly used in actions:
Update, FixedUpdate, LateUpdate, EveryFrame, UpdateEveryFrame, FixedUpdateEveryFrame.

If an action uses PerSecond, set:
public override bool CanUsePerSecond => true;

Use DefaultUpdateMode ONLY if the action truly requires a specific mode.
Use RequiredUpdateModes sparingly.
PerSecond depends on EveryFrame and user settings.

============================================================
5. Execution Pattern
============================================================

Parameter validation:
public override bool CanExecute() =>
    CheckParameters(_field1, _field2, _field3);

Core work:
public override void Execute()
{
    // main action logic
}

Events:
SendEvent(EventRef);
BroadcastEvent(EventRef);

Logging:
LogInfo("message");
LogWarning("message");
LogError("message");

Use Reset() only for special-case initialization.
Prefer [DefaultValue(...)] for defaults.

============================================================
6. GetSummary Rules (IMPORTANT)
============================================================

GetSummary() must return a template string using placeholders.

Placeholders must match the **serialized field name EXACTLY**,
including the leading underscore.

Examples:
Field: [SerializeField] private FloatVar _speed;
Placeholder: {_speed}

Field: [SerializeField] private Vector3Ref _storeResult;
Placeholder: {_storeResult}

Do NOT invent new names. Do NOT remove the underscore.
The placeholder must be {<exact-field-name>}.

Use "->" to indicate outputs.

Boolean placeholders can use the :option suffix
to show only when true:
{_useGravity:option}

Examples:
"{_target} * {_speed} -> {_storeResult}"
"{_from} to {_to} -> {_path}"
"{_a} + {_b} -> {_result} {_useGravity:option}"

Never embed real numeric values or computed text in GetSummary.
Only use placeholders and static text.

============================================================
7. Canonical Action Example (Pattern Only)
============================================================

[ActionCategory(Category.GameObject)]
[ActionDescription("Example action using PerSecond and summary placeholders.")]
public class ExampleAction : BaseAction
{
    // This action uses PerSecond, so enable it:
    public override bool CanUsePerSecond => true;

    // Optional: default to UpdateEveryFrame
    public override UpdateMode DefaultUpdateMode => UpdateMode.UpdateEveryFrame;

    [SerializeField] private TransformVar _target;
    [SerializeField, DefaultValue(1f)] private FloatVar _speed;
    [SerializeField, WriteOnly] private Vector3Ref _storeResult;

    public override bool CanExecute() =>
        CheckParameters(_target, _speed, _storeResult);

    public override void Execute()
    {
        _storeResult.Value =
            _target.Value.position * _speed.Value * PerSecond;
    }

    // Placeholders MUST match field names exactly, including underscores.
    public override string GetSummary() =>
        "{_target} * {_speed} -> {_storeResult}";
}

============================================================
8. True/False (CheckXxx) Actions
============================================================

Any action that checks a condition and sends True/False events
must follow this pattern:

- Class name starts with: CheckXxx
- Inherits from: BaseTrueFalseAction

Must override:

protected override bool Test();
protected override string TrueSummary  { get; }
protected override string FalseSummary { get; }

TrueSummary and FalseSummary must use exact field-name placeholders:
"{_integer} == {_equalTo}"
"{_fromObject} distance to {_toObject} is {_check} {_distance}"

The base class handles:
- Sending TrueEvent / FalseEvent
- Optional BoolRef StoreResult
- Summary / validation pattern

---------------------------
Simple example:
---------------------------

[ActionCategory(Category.Logic)]
[ActionDescription("Check if an integer is equal to a value.")]
public class CheckIntEquals : BaseTrueFalseAction
{
    [Tooltip("The integer to check.")]
    public IntegerRef _integer;

    [Tooltip("The value to compare to.")]
    public IntegerVar _equalTo;

    protected override string TrueSummary  => "{_integer} == {_equalTo}";
    protected override string FalseSummary => "{_integer} != {_equalTo}";

    public override bool CanExecute() =>
        CheckParameters(_integer, _equalTo);

    protected override bool Test() =>
        _integer.Value == _equalTo.Value;
}

---------------------------
Complex example:
---------------------------

[ActionCategory(Category.Logic)]
[ActionDescription("Check the distance between 2 objects.")]
public class CheckDistance : BaseTrueFalseAction
{
    public TransformVar _fromObject;
    public TransformVar _toObject;
    public NumericComparisonOperation _check;
    public FloatVar _distance;

    private float _computedDistance;

    protected override string TrueSummary  =>
        "{_fromObject} distance to {_toObject} is {_check} {_distance}";

    protected override string FalseSummary =>
        "{_fromObject} distance to {_toObject} is not {_check} {_distance}";

    public override bool CanExecute() =>
        CheckParameters(_fromObject, _toObject, _distance);

    protected override bool Test()
    {
        _computedDistance = Vector3.Distance(
            _fromObject.Value.position,
            _toObject.Value.position);

        return _check.Evaluate(_computedDistance, _distance.Value);
    }

#if UNITY_EDITOR
    public override bool HasDebugInfo => true;

    public override string GetDebugInfo() =>
        $"Distance: {_computedDistance:0.##}";
#endif
}

============================================================
END OF FILE
============================================================

Tips for best results

  • Put the instruction file into persistent project instructions so you never need to paste it again.
  • Start a new chat when generating a new Action - don’t reuse heavily contextual conversations.
  • If the AI ever forgets the pattern, simply say:

    “Follow the PlayMaker 2 AI instructions.”