Pyxen Script

Los juegos de Pyxen se escriben en Pyxen Script, un dialecto de Python hecho para juegos. Tiene la sintaxis y el estilo de Python: la indentación, def, las listas, los diccionarios, las f-strings, las comprensiones. Lo que cambia está por debajo. Tu código se comprueba en su conjunto y se compila antes de que empiece el juego, y se ejecuta en un runtime construido para una sola tarea: ejecutar un juego, de la misma manera, en cada dispositivo.

Si ya conoces Python, casi todo lo que escribas funcionará como esperas. Esta página explica por qué existe Pyxen Script, qué comparte con Python y qué deja fuera a propósito.

Por qué un dialecto

Un juego no le pide a un lenguaje lo mismo que un script.

Las versiones anteriores de Pyxen usaban un intérprete de MicroPython; Pyxen Script lo sustituye.

Qué es igual que en Python

Pyxen Script se prueba con cientos de modismos de Python de una línea, cada uno comparado con la salida de Python estándar. Todo lo siguiente se comporta como en Python:

Qué es diferente

Sin clases

Pyxen Script no tiene class. Es una decisión de diseño.

En un juego de Pyxen, el estado vive en las entidades y sus componentes, que pertenecen al motor, que los guarda de forma compacta y te los muestra en el inspector de fotogramas. Una clase sería un segundo lugar para guardar el mismo estado, invisible para el motor y para el inspector. Así que donde el código Python definiría una clase, el código de Pyxen crea una entidad, le añade un componente y escribe funciones que actúan sobre ella.

Una clase típica de Python:

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

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

Lo mismo en 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

La entidad ya tiene una posición, un sprite y un lugar en la escena. El componente enemy guarda lo que es propio de los enemigos, y world.all("enemy") los encuentra a todos, así que no hay una lista de instancias que mantener sincronizada. Para datos sencillos que no son objetos de juego, como una tabla de récords o la descripción de un nivel, usa diccionarios y listas. Consulta Entidades y componentes para el modelo completo.

Sin excepciones

Pyxen Script no tiene try, except, finally ni raise. También es una decisión de diseño.

Un error en Pyxen Script detiene el juego y se señala en su línea, junto con las llamadas que llevaron hasta él. Nada puede capturarlo por el camino, así que un error nunca se lo traga un except: pass para convertirse en un juego que falla en silencio tres niveles después.

La mayoría de los bloques try del código de juegos hacen una pregunta que tiene respuesta directa. Haz la pregunta:

# ¿tiene esta entidad un componente?
hp = e.health.value if e.has("health") else 0

# ¿está esta clave en el diccionario?
best = scores.get(name, 0)

# ¿es este texto un número?
if text.isdigit():
    level = int(text)

# ¿está este índice dentro de la lista?
if i < len(items):
    item = items[i]

assert está disponible y detiene el juego en su línea cuando su condición es falsa.

Tampoco está en Pyxen Script

Cada uno de estos puntos se señala por su nombre, en su línea, antes de que el juego arranque.

Módulos e imports

Un proyecto se compila como un único programa. Cada script ya es visible para los demás por su nombre de archivo: una función spawn() en monsters.py se llama monsters.spawn() desde cualquier otro script, sin import. La API del motor (world, input, Sprite…) también está siempre disponible.

Los imports que ya tienes, como from pyxen import * o import monsters, siguen funcionando. Pyxen Script los considera innecesarios y puedes quitarlos.