Docs

Scripting basics

Native gameplay is Python in your project’s scripts/ folder. Scripts hot-reload while the game runs, so you edit and see the change without restarting.

This page is about Hexaliz’s native runtime. Browser games use their own JavaScript, and Godot or other engine projects keep their own languages.

Components, systems and events

  • Entities are the things in a scene, with stable IDs. Their data lives in components: built-ins such as Transform and Health, or your own @component classes.
  • Systems (@system) run every fixed tick (60 per second by default) and read input, query entities and change them.
  • Events (@on_event) handle things that happen, such as collisions, UI clicks and saves.
scripts/main.py
import engine.input as controls
from engine import Changed, Query, With, Without, component, on_event, system
from engine.components import Health, Transform

@component
class Fighter:                      # typed fields: int, float, bool, str, Vec3, ...
    speed: float = 2.0
    target: int = 0                 # an entity id (0 = none)

@system
def advance(world, input, dt):
    x, y = controls.axis2d(input, "move")
    for e, fighter, xf in Query(Fighter, Transform, Without("Dead")):
        xf.position.x += fighter.speed * x * dt   # views write straight into the engine
    for e, health in Query(Health, Changed(Health), With(Fighter)):
        if health.current <= 0:
            e.despawn()

@on_event("collision_start")
def hit(world, event):              # entity_a, entity_b, is_sensor, normal, impulse
    ...
  • Query(A, B) yields (entity, a, b) for each entity that has both; With, Without and Changed filter, and tag= or name= pick by tag or name.
  • On an entity handle: e.get(Fighter), e.add(Fighter()), e.remove(Fighter), e.despawn().
  • Writes are checked as they happen, and a callback that raises an error rolls back everything it did.
  • Scripts read actions such as move and jump from *.input.toml, never raw keys, so players can rebind them.
  • Use engine.clock and engine.rng instead of time.time() and random, so replays, saves and multiplayer stay exact.

Use the engine's building blocks

Before writing movement, chasing or combat by hand, check the built-in blocks: CharacterMotor for walking and jumping,NavAgent for pathfinding, spatial queries for “what is near”, and native abilities, auras, threat and enemy AI. They are faster than per-tick Python and work with saves, replays and networking.

Find the right call

Search the gameplay API by intent, and print an outline of an existing game’s code:

shell
hexaliz api cooldown
hexaliz map ~/games/dodge

Typed stubs (engine/*.pyi) ship beside the engine package for editor autocomplete. The full scripting guide ishexaliz skill build-game-scene scripting.md; unit-test systems without the engine with engine.testing.TestWorld.

Check your game

hexaliz check ~/games/dodge validates the live files and returns a picture of the running game with the problems it found. In the app, the Console shows script errors and the Performance popover shows what each system costs per tick. The game must keep 100 % speed: if a script makes the tick slower than real time, fix the script.

More: Make a 2D game has a complete small example.