Cuando intentas construir una pantalla de estado o un menú personalizado en Ren'Py, casi seguro pensarás: "Cambié la variable, pero la pantalla no se actualizó."
No es un bug. El screen language de Ren'Py está diseñado para ser declarativo. Si estás acostumbrado a la programación imperativa de Python, esto se siente contraintuitivo al principio.
Esta guía cubre los fundamentos del screen language en Ren'Py 8.5.2 y explica la mecánica detrás de "por qué no se actualiza."
Screen Language es declarativo
Python es imperativo. Escribes instrucciones paso a paso: "haz esto, luego haz aquello."
# Python (imperativo)
hp = 100
hp -= 30
print(hp) # 70
El screen language de Ren'Py es declarativo. Describes cómo debería verse la pantalla.
screen stats_hud():
frame:
text "HP: [player_hp]"
Este text "HP: [player_hp]" no es un comando que dice "muestra HP ahora." Es una declaración: "la pantalla debería mostrar el valor de HP." Ren'Py lee esta declaración en el momento apropiado y construye la pantalla.
Esta naturaleza "declarativa" es la clave para entender el comportamiento de actualización de pantallas.
Sintaxis básica de screens
Definiendo y mostrando una screen
# Definir una screen
screen greeting():
frame:
xalign 0.5
yalign 0.5
vbox:
text "Hello"
textbutton "Close" action Hide("greeting")
label start:
# Mostrar la screen
show screen greeting
"A window is visible on screen."
# Ocultar la screen
hide screen greeting
Define la estructura de UI con la declaración screen, luego muéstrala con show screen.
Displayables clave
Los bloques de construcción (displayables) que usas dentro de las screens.
| Displayable | Propósito | Ejemplo |
|---|---|---|
text | Mostrar texto | text "HP: 100" |
add | Mostrar una imagen | add "icon.png" |
textbutton | Botón de texto | textbutton "OK" action Return() |
imagebutton | Botón de imagen | imagebutton idle "btn.png" action Return() |
vbox | Contenedor vertical | Apila hijos verticalmente |
hbox | Contenedor horizontal | Apila hijos horizontalmente |
frame | Ventana enmarcada | Área de UI con fondo |
bar | Barra/deslizador | bar value player_hp range 100 |
Para la lista completa, consulta Screens and Screen Language.
Condiciones y bucles
Puedes usar if y for dentro del screen language.
screen inventory():
frame:
vbox:
text "Inventory"
for item in inventory_list:
textbutton "[item]" action NullAction()
if len(inventory_list) == 0:
text "No items"
Estos se parecen al if/for de Python, pero se comportan diferente. Los if/for de screen se re-evalúan cada vez que la screen se re-evalúa. No son flujo de control imperativo de una sola vez.
Por qué tu screen no se actualiza
Este es el concepto central. Mira este código:
default player_hp = 100
screen hp_display():
text "HP: [player_hp]"
label start:
show screen hp_display
"HP is [player_hp]."
$ player_hp -= 30
"HP dropped to [player_hp]."
Este código funciona bien. Cuando player_hp cambia, la screen se actualiza.
Entonces, ¿por qué la gente dice "mi screen no se actualiza"? Aquí es cuando realmente sucede.
El caso: Sin interacción
label start:
show screen hp_display
$ player_hp -= 30
# ← La screen NO se ha actualizado aquí
$ player_hp -= 20
# ← Todavía NO se ha actualizado
"HP is [player_hp]."
# ← La screen finalmente se actualiza en esta declaración say (interacción)
Las screens de Ren'Py se re-evalúan cuando ocurre una interacción. Una interacción es cualquier punto donde el motor espera input del jugador.
| Causa interacción | NO causa interacción |
|---|---|
Declaraciones say (say) | $ variable = value |
Opciones (menu) | show image |
pause | hide image |
call screen | show screen |
with transition | Declaraciones Python (líneas $) |
No importa cuántas variables cambies con líneas $, la screen no se redibujará hasta la siguiente interacción.
La solución: Agrega una interacción
Para actualizar la screen después de cambiar variables, dispara una interacción con una declaración say o pause.
label start:
show screen hp_display
$ player_hp -= 30
pause 0.5
# ← pause dispara una interacción, la screen se actualiza
$ player_hp -= 20
"HP dropped to [player_hp]."
# ← la declaración say también es una interacción, la screen se actualiza aquí también
Cuando cambias variables a través de botones dentro de una screen, los Actions (cubiertos abajo) automáticamente reinician la interacción, así que no necesitas disparar una manualmente.
Cuidado con la predicción de screens
Ren'Py predice las screens antes de mostrarlas. Esta optimización permite transiciones suaves, pero significa que el código Python dentro de las screens puede ejecutarse en momentos inesperados.
screen dangerous():
python:
# ¡Esto se ejecuta durante la predicción también!
store.gold -= 100
text "Gold: [gold]"
El bloque python: dentro de una screen se ejecuta durante la predicción, antes de que la screen se muestre realmente. Nunca escribas efectos secundarios (cambios de variables, operaciones de archivo) en bloques python: de screens. Usa Actions para cambios de variables en su lugar.
show screen vs call screen
Dos formas de mostrar una screen, con comportamiento muy diferente.
show screen: El label sigue ejecutándose
label start:
show screen hp_display
"HP display is visible during this dialogue."
"Still visible here."
hide screen hp_display
"HP display is gone."
show screen muestra la screen pero no detiene la ejecución del label. Úsalo para HUDs siempre visibles (barras de estado, minimapas, etc.).
call screen: Espera input del jugador
screen choice_menu():
vbox:
xalign 0.5
yalign 0.5
textbutton "Fight" action Return("fight")
textbutton "Flee" action Return("flee")
label start:
call screen choice_menu
# El resultado se almacena en _return
if _return == "fight":
"You chose to fight!"
else:
"You ran away!"
call screen muestra la screen y detiene la ejecución del label hasta que se llama a Return(). El valor de retorno va a _return. Úsalo para menús y diálogos temporales.
Controlando screens con Actions
Lo que pasas al action de un botón no es una llamada a función Python — es un objeto Action.
Un error común
init python:
def do_heal():
store.player_hp += 20
screen heal_button():
# Incorrecto — llama a do_heal() inmediatamente durante la evaluación de la screen
# textbutton "Heal" action do_heal()
# Correcto — lo envuelve en Function()
textbutton "Heal" action Function(do_heal)
Escribir do_heal() llama a la función inmediatamente durante la evaluación de la screen, pasando su valor de retorno (None) a action. Escribir Function(do_heal) hace que se ejecute cuando se hace clic en el botón.
Actions incorporados clave
| Action | Comportamiento |
|---|---|
SetVariable("name", value) | Cambiar una variable global |
SetScreenVariable("name", value) | Cambiar una variable local de screen |
ToggleVariable("name") | Alternar una variable booleana |
Function(callable) | Ejecutar cualquier función |
Show("screen_name") | Mostrar otra screen |
Hide("screen_name") | Ocultar una screen |
Return(value) | Devolver un valor a call screen |
NullAction() | No hacer nada (hace que un botón sea clickeable) |
Los Actions incorporados reinician automáticamente la interacción después de la ejecución. Cambia HP con SetVariable, y cualquier screen que muestre HP se actualiza automáticamente. Por eso raramente necesitas renpy.restart_interaction() directamente.
Para la lista completa, consulta Screen Actions.
Variables locales de screen
Las variables usadas solo dentro de una screen se declaran con default.
screen counter():
default count = 0
vbox:
text "Count: [count]"
textbutton "+1" action SetScreenVariable("count", count + 1)
textbutton "Reset" action SetScreenVariable("count", 0)
default se inicializa una vez cuando la screen se muestra por primera vez. Asignar variables en un bloque python: dentro de una screen las reinicia en cada re-evaluación.
Conclusión
Lo que cubrimos:
- Paradigma declarativo: Las screens describen lo que debería mostrarse, no instrucciones paso a paso
- Sintaxis básica: Define con
screen, construye con displayablestext/textbutton/vbox/frame - Interacciones: Las screens se re-evalúan en las interacciones. Las líneas
$solas no disparan actualizaciones de screen - show vs call:
show screenes no bloqueante (para HUDs),call screenes bloqueante (para menús) - Actions: Pasa objetos
SetVariable/Function/Returna los botones. Automáticamente disparan actualizaciones de screen
Para lo básico de Ren'Py, consulta la guía de inicio. Para visualización de imágenes, consulta la guía básica de imágenes.
Recursos oficiales:
- Screens and Screen Language — referencia de screen language
- Screen Actions — lista completa de Actions
- Screen Language Optimization — detalles de predicción y optimización
- r/RenPy — comunidad