pyxen.Entity

Un Entity es un identificador ligero — un contenedor de componentes.

Para una introducción al sistema de entidad-componente, consulta Entidades y componentes.


Componentes integrados

ComponenteAcceso
Transforme.x, e.y, e.rotation, e.scale
Spritee.sprite, e.color
Animatione.animation
Sounde.sound
Musice.music
GridBodye.body
GridMape.map
Nodee.parent, e.children
Layere.layer
Namee.name
Camerae.camera

Transform

e.x = 100
e.y = 50
e.rotation = 45
e.scale = (2, 2)

Leer scale devuelve un Vector2:

s = e.scale
print(s.x, s.y)

Sprite

e.sprite = sprite
e.color = (1.0, 0.5, 0.5, 1.0)

Leer color devuelve un Color:

c = e.color
print(c.r, c.g, c.b, c.a)

Animación de sprites

Cuando un sprite se crea con el parámetro animation, el motor reproduce la animación automáticamente. Puedes leer el estado de la animación mediante e.animation:

player.sprite = Sprite("hero", animation="walk")

Propiedades

PropiedadTipoDescripción
namestrNombre del clip de animación actual
frameintÍndice del fotograma actual dentro del clip
playingboolTrue si la animación se está reproduciendo
finishedboolTrue si una animación de una sola vez ha terminado
anim = player.animation
if anim:
    print(anim.name)      # "walk"
    print(anim.frame)     # 2
    print(anim.playing)   # True
    print(anim.finished)  # False

Si no hay ninguna animación activa, e.animation devuelve None:

player.sprite = Sprite("hero", tile=(0, 0, 16, 16))
print(player.animation)  # None

Cancelar

Asigna None a e.animation para detener la reproducción:

player.animation = None

Asignar un nuevo sprite cancela automáticamente cualquier animación existente.

Animaciones de una sola vez

Usa loop=False para animaciones que se reproducen una vez:

player.sprite = Sprite("hero", animation="attack", loop=False)

def update():
    if player.animation and player.animation.finished:
        player.sprite = Sprite("hero", animation="idle")

Tweens

Los tweens animan las propiedades de una entidad a lo largo del tiempo. El motor se encarga de la interpolación automáticamente — sin código por frame.

entity.tween()

# Forma con nombre de propiedad
entity.tween("x", to=200, duration=1.0)
entity.tween("alpha", to=0, duration=0.5, ease="out_quad")

# Forma abreviada — animar varias propiedades a la vez
entity.tween(x=200, y=100, duration=1.0, ease="out_quad")
ParámetroTipoPor defectoDescripción
propertystrNombre de la propiedad (posicional o forma abreviada)
tofloatValor objetivo
byfloatOffset relativo (alternativa a to)
startfloatactualValor inicial (por defecto el valor actual)
durationfloat1.0Duración en segundos
easestr"linear"Nombre de la función de easing

Usa to para un objetivo absoluto, o by para un offset relativo:

entity.tween("x", to=200, duration=1.0)    # mover a x=200
entity.tween("x", by=50, duration=0.5)     # mover 50 píxeles a la derecha

Usa start para sobreescribir el valor inicial:

entity.tween("x", to=200, start=0, duration=1.0)  # siempre empezar desde 0

Propiedades animables

ComponentePropiedades
Transformx, y, rotation, sx, sy
Spriter, g, b, alpha
Camerazoom

Funciones de easing

NombreCurva
linearVelocidad constante (por defecto)
in_quadInicio lento, acelerando
out_quadInicio rápido, desacelerando
in_out_quadInicio y final lentos
in_cubicInicio más lento que quad
out_cubicInicio más rápido que quad
in_out_cubicInicio y final suaves
in_expoInicio muy lento, aceleración explosiva
in_out_expoParte media explosiva
out_expoInicio muy rápido, parada suave
in_backRetrocede antes de avanzar
out_backSobrepasa el objetivo y se estabiliza
in_out_backRetroceso y sobrepaso
in_elasticTensión elástica
out_elasticSobrepaso y rebote elástico
in_out_elasticElástico en ambos extremos

entity.tweens.cancel()

Cancela tweens de una entidad. Pasa un nombre de propiedad para cancelar un solo tween, o llama sin argumentos para cancelar todos. El valor se congela en su posición actual.

entity.tweens.cancel("x")   # cancelar una propiedad
entity.tweens.cancel()       # cancelar todos

Resolución de conflictos

Iniciar un nuevo tween en la misma entidad y propiedad reemplaza el anterior. Los tweens en propiedades diferentes se ejecutan de forma independiente.

entity.tween("x", to=100, duration=1.0)
entity.tween("x", to=200, duration=0.5)  # reemplaza el primer tween
entity.tween("y", to=50, duration=1.0)   # se ejecuta junto al tween de x

Los tweens en entidades destruidas se limpian automáticamente.

Iniciar un animate() en una propiedad cancela cualquier tween() activo en esa propiedad, y viceversa.


Animaciones

Animaciones continuas que se ejecutan indefinidamente — oscilación de onda sinusoidal (pulsación, respiración, balanceo) y rotación a velocidad constante.

entity.animate() — Oscilar

Oscila una propiedad alrededor de un valor central con una onda sinusoidal.

entity.animate("sx", "sy", by=0.15, speed=6.0)     # coin pulse
entity.animate("alpha", by=0.3, center=0.7, speed=4.0)  # flicker 0.4–1.0

El valor sigue: center + sin(elapsed * speed) * by

entity.animate() — Girar

Acumula un valor a una velocidad constante. Omite by= para usar el modo de giro.

entity.animate("rotation", speed=180)   # 180°/sec clockwise

Parámetros

ParámetroTipoDefectoDescripción
*propsstrUno o más nombres de propiedad (posicionales)
byfloatAmplitud (modo oscilación). Omitir para giro.
centerfloatactualValor central para la oscilación
speedfloat1.0Frecuencia angular (oscilación) o unidades/seg (giro)

Las mismas 10 propiedades que los tweens: x, y, rotation, sx, sy, r, g, b, alpha, zoom.

entity.animations.cancel()

Cancela animaciones de una entidad. Pasa un nombre de propiedad para cancelar una sola animación, o llama sin argumentos para cancelar todas.

entity.animations.cancel("rotation")   # cancelar una propiedad
entity.animations.cancel()             # cancelar todas

Parent / Children

child.parent = parent

Acceder a los hijos:

for c in parent.children:
    print(c.name)

Obtener el número de hijos:

parent.children.count

Componentes personalizados

Los componentes se crean asignando:

  • Un diccionario — componente estructurado
  • Un booleano — componente marcador
e.cell = {
    'row': 0,
    'col': 0
}

La primera asignación crea el esquema. Los tipos de campo se infieren y el esquema queda fijo — no se pueden añadir nuevos campos después.


Uso de componentes en sistemas

for cell in world.all("cell"):
    ...

Ver: pyxen.world.all()


Componentes marcadores

e.alive = True

Los marcadores no almacenan datos — solo indican presencia. Se consultan como componentes normales:

for e in world.all("alive"):
    ...

Acceso a campos de componentes

e.cell.row
e.cell.col
e.cell.row = 5

Tipos de campo soportados

Tipo PythonAlmacenado como
intEntero de 32 bits
floatFlotante de 32 bits
boolBooleano
strCadena fija (máx 31 chars)
EntityReferencia a entidad

Los tipos inválidos producen:

TypeError: invalid value type in dict

Reglas de esquema

  • Tamaño máximo de componente: 256 bytes
  • Cadenas máximo: 31 caracteres
  • Las claves del diccionario deben ser cadenas
  • No se pueden añadir nuevos campos después de la creación del esquema
e.cell = {'row': 0}
e.cell = {'row': 0, 'new_field': 5}
ValueError: cannot create new fields after schema is complete

Es válido omitir campos en asignaciones posteriores — toman valores por defecto 0, 0.0, False, "", etc.


Comprobar si tiene un componente

e.has("cell")

Devuelve True si la entidad tiene el componente, False en caso contrario.

Funciona tanto con nombres de componentes personalizados como integrados:

e.has("sprite")   # True si la entidad tiene un sprite
e.has("body")     # True si la entidad tiene un grid body

Consultar descendientes

entity.all(*components, without=(), include_self=False)

Devuelve un iterador sobre todos los descendientes de la entidad (en profundidad a través de la jerarquía del grafo de escena) que coincidan con el filtro de componentes dado.

Funciona exactamente como world.all(), pero limitado a un subárbol en lugar de todo el mundo.

# Todos los descendientes con el componente "enemy"
for e in parent.all("enemy"):
    ...

# Con exclusión
for e in parent.all("enemy", without=("boss",)):
    ...

# Incluir la propia entidad padre
for e in parent.all("tag", include_self=True):
    ...
ParámetroTipoPor defectoDescripción
*componentsstrNombres de componentes requeridos
withouttuple()Nombres de componentes a excluir
include_selfboolFalseSi incluir la propia entidad

Se soportan tanto nombres de componentes integrados como personalizados.


Eliminar componentes

Elimina un componente de una entidad usando del o asignando None:

# Ambos son equivalentes:
del entity.health
entity.health = None

Después de eliminarlo, entity.has("health") retorna False y la entidad ya no coincide con consultas para ese componente.

e = world.spawn()
e.health = {'hp': 100}

del e.health

e.has("health")         # False
# world.all("health") no incluirá e

Puedes volver a añadir un componente después de eliminarlo:

del e.health
e.health = {'hp': 50}   # funciona correctamente

Componentes integrados

Todos los componentes integrados se pueden eliminar:

del e.sprite    # limpia datos del sprite
del e.body      # limpia cuerpo de físicas
del e.camera    # elimina cámara
del e.text      # elimina texto
del e.sound     # elimina sonido
del e.music     # elimina música
del e.map       # elimina mapa de cuadrícula

Sprite y body se inicializan a cero (la entidad aún tiene el almacenamiento, pero los datos están vacíos). Camera, text, sound, music y map se borran completamente.

Marcadores

e.enemy = True
del e.enemy      # o: e.enemy = None
e.has("enemy")   # False

Ciclo de vida de Entity

  • Se crea con world.spawn()
  • Se modifica mediante asignación de componentes
  • Se eliminan componentes con del o = None
  • Se destruye con world.destroy()

Ver: pyxen.world.spawn() | pyxen.world.destroy()