Lo que hace que una novela visual merezca ser rejugada son las opciones. La historia cambia según lo que el jugador elige, y eso es lo que le hace volver.
Esta guía cubre cómo implementar opciones y ramificaciones en Ren'Py 8.5.2, desde la declaración básica menu hasta múltiples finales.
La declaración menu
La declaración menu presenta opciones al jugador y ramifica según su selección.
label start:
"The road splits in two."
menu:
"Which way?"
"Take the left path":
"You chose the left path. A forest stretches ahead."
"Take the right path":
"You chose the right path. A river comes into view."
"The journey continues."
La cadena directamente debajo de menu: ("Which way?") es el subtítulo. Las cadenas debajo se convierten en las opciones. Cada bloque de opción contiene el código que se ejecuta cuando se selecciona esa opción.
Después de que termina el bloque de opción, la ejecución continúa en la línea después del menu ("The journey continues."). Independientemente de qué opción se eligió, el flujo se une aquí.
Haciendo que un personaje pregunte
En lugar de un subtítulo, puedes hacer que un personaje diga la pregunta.
define e = Character("Eileen")
label start:
menu:
e "Which do you prefer?"
"Tea":
e "Tea it is."
"Coffee":
e "Coffee it is."
Escribir e "Which do you prefer?" lo muestra como diálogo de Eileen y luego muestra las opciones.
jump vs call
Cuando los bloques de opciones se hacen largos, mueve la lógica a labels separados con jump o call. Estos dos se parecen pero difieren en un aspecto crítico: si la ejecución regresa o no.
jump — Solo ida
label start:
menu:
"Which way?"
"The forest":
jump forest_route
"The town":
jump town_route
label forest_route:
"You ventured deep into the forest."
jump chapter_2
label town_route:
"You arrived at a bustling town."
jump chapter_2
label chapter_2:
"Chapter 2 begins."
jump mueve la ejecución al label especificado y nunca regresa. Úsalo para transiciones de ruta y finales.
call — Ir y volver
label start:
"Time to prepare for the adventure."
call shop
"Shopping done. Time to set off."
label shop:
"What will you buy?"
menu:
"Buy a sword":
$ has_sword = True
"Buy a shield":
$ has_shield = True
return
call mueve la ejecución al label especificado, y return la devuelve al llamador. Úsalo para escenas compartidas (tiendas, minijuegos, flashbacks) que quieras invocar desde múltiples lugares.
Comparación
jump | call | |
|---|---|---|
| Regresa | No | Sí, vía return |
| Úsalo para | Ramificaciones de ruta, finales | Escenas compartidas, subrutinas |
| Pila de llamadas | No agrega | Agrega (consumido por return) |
Gestionando ramificaciones con flags
Guarda los resultados de las opciones en variables (flags) para referenciarlos en escenas posteriores.
Declarando flags
# Declarar con default (se guarda en archivos de guardado)
default met_fairy = False
default affection = 0
label start:
menu:
"Talk to the fairy?"
"Talk to her":
$ met_fairy = True
$ affection += 10
"You became friends with the fairy."
"Ignore her":
"You walked past."
Siempre declara flags con default. Las variables declaradas con default se guardan en los archivos de guardado y se restauran correctamente al cargar.
Ramificando según flags
label chapter_2:
if met_fairy:
"The fairy from before appeared."
$ affection += 5
else:
"An unfamiliar fairy appeared."
if affection >= 10:
"The fairy smiled at you."
else:
"The fairy is cautious."
Usa if/elif/else para cambiar texto y eventos según los valores de las variables.
Opciones condicionales
Agrega una condición if a una opción para mostrarla solo cuando se cumple la condición.
default has_key = False
label locked_door:
"A locked door stands before you."
menu:
"Use the key" if has_key:
"The door opened."
jump secret_room
"Turn back":
"You decided to find another way."
Cuando has_key es False, "Use the key" no aparece en el menú. El jugador solo ve "Turn back."
Mostrando opciones deshabilitadas en gris
En lugar de ocultar las opciones no cumplidas, puedes mostrarlas en gris para señalar "esto existe pero aún no puedes elegirlo."
init python:
config.menu_include_disabled = True
label locked_door:
menu:
"Use the key" if has_key:
"The door opened."
"Turn back":
"You decided to find another way."
Establecer config.menu_include_disabled = True muestra las opciones no cumplidas en estado deshabilitado (gris). Esto le sugiere al jugador que diferentes condiciones podrían desbloquearlas.
Excluyendo opciones ya elegidas
Usa set para eliminar automáticamente las opciones que el jugador ya eligió.
default explored = set()
label explore:
"What do you examine?"
menu:
set explored
"The desk":
"You found a letter."
"The bookshelf":
"You found an old diary."
"The window":
"You saw someone's shadow outside."
if len(explored) < 3:
jump explore
else:
"You've examined everything."
Implementando múltiples finales
Combina todo lo anterior para construir múltiples finales.
Basado en puntos: Ramificar por afinidad
Suma o resta puntos según las opciones del jugador, luego decide el final por el valor final.
default affection = 0
label start:
"You met Eileen."
menu:
"Greet her":
$ affection += 10
"Eileen looks happy."
"Walk past":
"Eileen looks lonely."
"The journey continued for a while."
menu:
"Help Eileen":
$ affection += 20
"Eileen's eyes lit up."
"Look the other way":
$ affection -= 10
"Eileen looked disappointed."
jump ending
label ending:
if affection >= 20:
jump good_ending
elif affection >= 0:
jump normal_ending
else:
jump bad_ending
label good_ending:
"You and Eileen forged an unbreakable bond."
"GOOD END"
return
label normal_ending:
"You and Eileen remained friends."
"NORMAL END"
return
label bad_ending:
"Eileen left without a word."
"BAD END"
return
Basado en flags: Ramificar por combinaciones de eventos
En lugar de puntos, decide el final según si ocurrieron eventos específicos.
default saved_cat = False
default found_letter = False
label start:
menu:
"Save the cat":
$ saved_cat = True
"Walk past":
pass
menu:
"Read the letter":
$ found_letter = True
"Ignore the letter":
pass
jump ending
label ending:
if saved_cat and found_letter:
"You uncovered the whole truth."
"TRUE END"
elif saved_cat:
"The cat came back to return the favor."
"CAT END"
elif found_letter:
"You solved the mystery of the letter."
"LETTER END"
else:
"You found nothing."
"NORMAL END"
return
En la práctica, la mayoría de los juegos combinan ambos enfoques — usan puntos (afinidad) para determinar la ruta principal, y flags para variaciones más pequeñas dentro de cada ruta.
Conclusión
Lo que cubrimos:
- Declaración menu: Sintaxis básica de opciones. Usa subtítulos o diálogo de personajes para plantear preguntas
- jump vs call:
jumpes solo ida,callregresa víareturn. Usacallpara escenas compartidas - Gestión de flags: Declara variables con
defaultpara guardar resultados de opciones - Opciones condicionales: Controla la visibilidad con condiciones
if.config.menu_include_disabledpara visualización en gris - Múltiples finales: Patrones basados en puntos (afinidad) y basados en flags (seguimiento de eventos)
Para lo básico de Ren'Py, consulta la guía de inicio. Para gestión de variables, consulta la guía de gestión de estadísticas. Para la interfaz de usuario, consulta la guía de screen language. Cuando tu juego esté listo, consulta la guía de distribución para compilar y publicar.
Recursos oficiales:
- In-Game Menus — referencia de la declaración menu
- Labels & Control Flow — detalles de label/jump/call
- Conditional Statements — detalles de if/elif/else
- r/RenPy — comunidad