Skip to main content

Companion Types

A companion is any type that is declared in C# that is bound to your template, typography, function or decorator declaration. The purpose of a companion is to provide a generic way to integrate C# code with a template.

A type is valid as a companion as long as it is public and defines a parameterless constructor or is a struct.

// C# type somewhere in your project

public struct SomeCompanion {

public int hitPoints;

public string currentLevelName;

public void ReloadWeapon() {
// assume this does work in your game
}

}

// ... some template file ...

// : typeName syntax declares a companion type binding for this template
// there can only be 1 companion per template. When declaring a companion type,
// a new built-in variable becomes available in the template: $companion.
// this refers to the companion instance for this template. From this reference
// you can use any public field, method, property, or event that the type exposes.
template ThingWithCompanion : SomeCompanion {

render {

Text($"Current Level is {$companion.currentLevelName}")

HealthBar($companion.hitPoints);

// you can call methods exposed on the companion instance
Button("Reload", mouse:click => $companion.ReloadWeapon());

}

}

Mapping values from companions

You can map values from a companion in the same way you could map them from state.

// c# file 
public class Inventory {

public int selectedItemIndex;

public string[] GetItemNames() { ... }

public string GetEquippedItemName(int itemIndex) { ... }

}

// template file
template InventoryUI : Inventory {

// we alias the selectedItemIndex parameter from the selectedItemIndex field on the companion
required int selectedItemIndex from $companion.selectedItemIndex;

// when mapping from a companion, if the companion's field name matches the template's declared name
// then you can omit the field name. This line is the same as the one above but shorter.
required int selectedItemIndex from $companion;

method string[] GetItemNames() from $companion; // when mapping a method, the signatures must match exactly.

// you can pick a different name for the template value if you specify the source explicitly;
method string GetItemName(int itemIndex) from $companion.GetEquippedItemName;
}

Mapping event and life cycle handlers from companions

An event or life cycle can also be mapped from the companion. As long as the signatures match between the event you are mapping and the method on the companion instance, the mapping is valid.

There is also a shorthand for mapping both input event names and life cycle handlers. For lifecycle events the return type is ignored and can be anything as long as your mapping method defines no parameters.

The name mapping table for lifecycle events is below:

Event NameMethod Mapping Name
before:createOnBeforeCreate
after:createOnAfterCreate
before:enableOnBeforeEnable
after:enableOnAfterEnable
before:updateOnBeforeUpdate
after:updateOnAfterUpdate
before:inputOnBeforeInput
after:inputOnAfterInput
before:finishOnBeforeFinish
after:finishOnAfterFinish
before:disableOnBeforeDisable
after:disableOnAfterDisable
before:destroyOnBeforeDestroy
after:destroyOnAfterDestroy

There is a similar mapping table for input event names, however with the added caveat that signature of your method must also match

Event NameMethod Mapping Name
mouse:enterOnMouseEnter(MouseInputEvent)
mouse:exitOnMouseExit(MouseInputEvent)
mouse:upOnMouseUp(MouseInputEvent)
mouse:downOnMouseDown(MouseInputEvent)
mouse:heldDownOnMouseHeldDown(MouseInputEvent)
mouse:moveOnMouseMove(MouseInputEvent)
mouse:hoverOnMouseHover(MouseInputEvent)
mouse:contextOnMouseContext(MouseInputEvent)
mouse:scrollOnMouseScroll(MouseInputEvent)
mouse:clickOnMouseClick(MouseInputEvent)
mouse:updateOnMouseUpdate(MouseInputEvent)
Event NameMapping Method Name
key:downOnKeyDown(KeyboardInputEvent)
key:heldDownOnKeyHeldDown(KeyboardInputEvent)
key:upOnKeyUp(KeyboardInputEvent)
Event NameMapping Method Name
focus:gainOnFocusGained(FocusChangeEvent)
focus:lostOnFocusLost(FocusChangeEvent)

Drag create is a special snowflake because it accepts a MouseInputEvent and expects to return an instance of DragEvent. All other drag handlers conform to the same signature requirements.

Event NameMapping Method NameDescription
drag:createDragEvent OnDragCreate(MouseInputEvent))Fires when a drag could begin. Returning null will not start a drag. Returning any other subclass of DragEvent will being a drag.
drag:move<T>OnDragMove(DragEvent)Fires when a drag of type T moves across this element
drag:hover<T>OnDragHover(DragEvent)Fires when a drag of type T hovers over this element
drag:update<T>OnDragUpdate(DragEvent)Fires when a drag of type T moves or hovers over this element
drag:enter<T>OnDragEnter(DragEvent)Fires when a drag of type T enters this element
drag:exit<T>OnDragExit(DragEvent)Fires when a drag of type T exits this element
drag:drop<T>OnDragDrop(DragEvent)Fires when a drop event of type T occurs on this element
drag:cancel<T>OnDragCancel(DragEvent)Fires when a drag event of type T is canceled on this element