Functions
A Function is an event-free operation. It has typed Parameters, typed Outputs, private Local Variables, and one ordered Action implementation. Other Logic invokes it through a Custom Action block.
Use a Function when multiple callers need the same operation, such as applying damage, awarding points, or calculating a price. Give the operation explicit inputs and a small, understandable result. The damage example below uses a live target and a Number amount to explain the call contract.
Separate the Trigger From the Operation
For a clickable target, Hit Target can be a Logic Component whose mouse-click Event decides when to respond. Apply Damage can be a Function whose implementation decides how health changes.
The same Function could later be called by contact Logic or a projectile hit. Those callers provide a victim and amount; they do not need to reproduce the health calculation. Changing the shared Function then changes the operation for all of those callers.
| Resource | Responsibility | Attached to an Object |
|---|---|---|
| Logic Component | Respond to Events and maintain its own private state | Yes |
| Function | Perform an explicitly called operation and provide Outputs | No |
Choose Function from the Add menu when creating the resource. Switching a tab inside the Logic Editor does not convert the resource type.
Design the Contract First
Before adding Actions, write down what the caller must supply and what it needs back. Apply Damage uses this contract:
| Declaration | Type | Meaning |
|---|---|---|
| victim Parameter | Structural Object | A live Object with the named health Data Structure slot and Health schema |
| amount Parameter | Number | Damage to subtract from that Object’s current health |
| remaining Output | Number | Its health after the change |
Its implementation changes victim.health.current to max(0, victim.health.current - amount). The remaining Output reads victim.health.current after that change. Health survives the Function call because it belongs to the live Object.
Choose a nominal Object contract when the operation belongs to one exact Object definition. Choose a structural contract when multiple Objects can provide the same required named component slots.
Keep the required data explicit. A Function cannot reach into another Logic scope’s private Local Variables. A component path is also part of the contract: victim.health.current requires the named health slot and its current field on the target Object.
Call and Use a Result
In the Function’s declaration panel, use Parameters > Add Parameter to add a Number, Object, Thing, or Function input. Expand Object inputs to choose their compatibility mode and required components. Use Outputs > Add Output to name a typed result and provide its expression.
In the calling Logic, insert the matching Custom Action and supply compatible arguments. For a click on a target, bind victim to SELF and amount to the caller’s damage Parameter. SELF means the live owner of that Logic attachment, so three placed targets can call the same Function with different instances.
Expand the Custom Action and set Action Name to hit. After that producing Action, typed completion offers hit.remaining. Use it as the value of Change Variable or as an operand in an If comparison.
An Action Name distinguishes repeated calls. For calls named firstHit and secondHit, select firstHit.remaining or secondHit.remaining as needed.
Use the call’s typed result where the editor makes it available. A result is associated with that producing Action and execution sequence; it is not an automatically declared Project Global. Put the call before its consumer in the same available flow. If a result must be displayed later, copy it into appropriately scoped state. For example, a declared Number Global named lastHealth can retain hit.remaining for a HUD; that sample does not replace the target’s authoritative health field.
Local Lifetime
A Function’s Local Variables begin at their defaults on each call. Use them for intermediate calculations. Store state that must survive calls in an explicit Object Data Structure field or Project Global.
For example, a Number local named computedDamage can hold a calculation during Apply Damage. It should not hold the target’s persistent health or a combo that must accumulate over many calls. Two hits are two invocations, and that local starts again on the second invocation.
Functions do not own Events and are not attached as event-driven Logic Components. The editor checks call contracts before compilation; recursive Function expansion is rejected.
Accept an Operation as an Input
Logic Components can also declare typed Function Parameters to choose a compatible callback at an attachment or Scene placement. This is useful when several buttons share activation Logic but should perform different operations. The Function Parameter declares the expected input and Output signature; the placement selects a matching Function.
The selected implementation is configured there, and Invoke Function Parameter calls it. Instance arguments are selected per invocation. An optional unassigned callback is a no-op only when no Outputs are consumed. If the caller needs an Output to continue, supply a compatible Function instead of treating absence as a returned value.
Start with a direct Function call when learning the workflow. Introduce Function Parameters once choosing the operation per attachment makes the project easier to maintain.
Check the Call Before Debugging the Formula
| Problem | Check |
|---|---|
| Function is missing from the expected choice | Confirm it is a Function resource and its signature fits the receiving field |
| An Object argument is rejected | Compare its exact Object type or named structural slots and schemas with the declared contract |
| The wrong instance changes | Inspect the live Object argument; choose SELF or another explicit compatible instance |
| A result cannot be selected | Check the Output declaration, Action Name, and whether the producing call precedes this field |
| State resets on each call | Move persistent state from a Function local to its intended Object field or Project Global |
| Compilation reports recursive expansion | Remove the direct or indirect Function call cycle |
Test two compatible targets with different current values. One call should change its victim and leave the other untouched. Then test zero damage and a hit larger than the remaining health. Check that zero damage leaves health unchanged and excess damage stops at zero.
Myth Engine Documentation
