Inheritance
CompilesOften the game already has a script that does nearly what you want. Inheritanceinheritance: Building one script on another with super: yours gets the parent's fields and functions and changes only what it needs to. lets you start from it: your script gets all of its fields, functions and events, and you change only the parts you need.
super: naming the parent
Section titled “super: naming the parent”The first line of an inheriting script names the parent by its path in the game’s data:
super "/data/catch/scripts/utility/entity_mover/entity_mover_rotate.vscript"
let bob_height: float = 40.0That’s already a complete, working script: it spins exactly like the shipped rotator, and it has one extra setting. Everything the parent declared (its fields, its functions, its events) is part of yours.
override: replacing a function
Section titled “override: replacing a function”A parent marks the functions a child may replace with virtual. Replace one by declaring a function with the same
name and parameters, marked override:
super "/data/catch/scripts/utility/entity_mover/entity_mover_rotate.vscript"
override fn update_rotation() { // The parent's rotation no longer happens: this body replaces it.}super::: calling the parent’s version
Section titled “super::: calling the parent’s version”Usually you don’t want to replace the parent’s behaviour so much as add to it. super::name(…) runs the
parent’s version from inside yours:
// spinning_bobber.vscript: the shipped rotator, plus a gentle bob up and// down.//// Everything about spinning comes from the parent: its fields (`period`,// `axis`) still show up in the editor, and its code still runs. This script// adds two fields and changes one function.super "/data/catch/scripts/utility/entity_mover/entity_mover_rotate.vscript"
// How far it rises and falls from where it was placed, in world units.let bob_height: float = 40.0;
// Seconds for one full rise and fall.let bob_seconds: float = 2.0;
// Where it started, so the bob is around its placed position.let mut start_position: vec3 = vec3(0, 0, 0);
// The parent's `created` finds the transform and starts the spin; keep// that, then remember where we are.event export fn created() { super::created(); start_position = transform.position;}
// The parent calls this every tick to turn the entity. Turn it as before,// then move it up or down.override fn update_rotation() { super::update_rotation(); let seconds: float = $time.ms_to_seconds($time.get_gameplay_time_ms()); let wave: float = $math.sin(seconds / bob_seconds * 6.2831855); transform.position = start_position + $math.vec3(0.0, 0.0, wave * bob_height);}update_rotation runs the parent’s spin, then moves the entity up or down. created does everything the parent’s
created did, then remembers where it started. The field transform is the parent’s; the child reads it as if
it were its own.
Events work the same way: declare an event with the parent’s event’s name, and call super:: to keep the parent’s
behaviour.
Finding something to inherit
Section titled “Finding something to inherit”The shipped scripts most often used as parents are families built for exactly this: movers (entity_mover_base
and its _rotate, _physics children), contract conditions, camera controllers, menus and widgets. A parent with
several virtual functions is one designed to be extended.
For programmers
Single inheritance; the parent’s code is inlined into the child when compiled, with the child’s fields laid out
after the parent’s. virtual / override give dynamic dispatch within the hierarchy, and super::f() is a
static call to the parent’s copy. Inherited fields are addressed by bare name. A parent you name must exist in
the game data, or every inherited name is unknown (V0203).