Pyxen Script

Pyxen games are written in Pyxen Script, a Python dialect made for games. It has Python’s syntax and feel: indentation, def, lists, dictionaries, f-strings, comprehensions. What changes is underneath. Your code is checked as a whole and compiled before the game starts, and it runs on a runtime built for one job: running a game, the same way, on every device.

If you already know Python, most of what you write works as you expect. This page explains why Pyxen Script exists, what it shares with Python, and what it leaves out on purpose.

Why a dialect

A game asks different things of a language than a script does.

Earlier versions of Pyxen ran a MicroPython interpreter; Pyxen Script replaces it.

What is the same as Python

Pyxen Script is tested against hundreds of one-line Python idioms, each compared with the output of standard Python. Everything below behaves as it does in Python:

What is different

No classes

Pyxen Script has no class. This is by design.

In a Pyxen game, state lives on entities and their components, which the engine owns, stores compactly, and shows you in the frame inspector. A class would be a second place to keep the same state, invisible to the engine and to the inspector. So where Python code would define a class, Pyxen code spawns an entity, attaches a component, and writes functions that act on it.

A typical Python class:

class Enemy:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.hp = 3

    def hit(self):
        self.hp -= 1

The same thing in Pyxen Script:

def spawn_enemy(x, y):
    e = world.spawn(name="enemy", x=x, y=y, sprite=Sprite("slime"))
    e.enemy = {"hp": 3, "speed": 1.5}
    return e

def hit(e):
    e.enemy.hp -= 1
    if e.enemy.hp <= 0:
        world.destroy(e)

def update():
    for e in world.all("enemy"):
        e.x -= e.enemy.speed

The entity already has a position, a sprite and a place in the scene. The enemy component holds what is specific to enemies, and world.all("enemy") finds every one of them, so there is no list of instances to keep in sync. For plain data that is not a game object, such as a high-score table or a level description, use dictionaries and lists. See Entities & Components for the full model.

No exceptions

Pyxen Script has no try, except, finally or raise. This is by design too.

An error in Pyxen Script stops the game and is reported at its line, with the calls that led to it. Nothing can catch it on the way, so an error is never swallowed by an except: pass and turned into a game that misbehaves quietly three levels later.

Most try blocks in game code ask a question that has a direct answer. Ask the question instead:

# does this entity have a component?
hp = e.health.value if e.has("health") else 0

# is this key in the dictionary?
best = scores.get(name, 0)

# is this text a number?
if text.isdigit():
    level = int(text)

# is this index inside the list?
if i < len(items):
    item = items[i]

assert is available, and stops the game at its line when its condition is false.

Also not in Pyxen Script

Each of these is reported by name, at its line, before the game starts.

Modules and imports

A project is compiled as one program. Every script in it is already visible to the others by its file name: a function spawn() in monsters.py is called as monsters.spawn() from any other script, with no import. The engine API (world, input, Sprite, …) is always available too.

Imports you already have, such as from pyxen import * or import monsters, still work. Pyxen Script treats them as unnecessary, and you can remove them.