32blogby Studio Mitsu

Opciones y Ramificaciones en Ren'Py: De Menús a Múltiples Finales

Aprende a implementar opciones y ramificaciones en Ren'Py 8.5. Cubre sintaxis de menú, jump vs call, gestión de flags, opciones condicionales y múltiples finales.

by omitsu9 min read
Contenido

La declaración menu de Ren'Py es lo que convierte un guión lineal en una historia ramificada. Defines opciones, las conectas a flags o sistemas de puntos, y dejas que las decisiones del jugador dirijan la narrativa hacia diferentes finales.

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.

renpy
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.

renpy
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

renpy
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

renpy
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

jumpcall
RegresaNoSí, vía return
Úsalo paraRamificaciones de ruta, finalesEscenas compartidas, subrutinas
Pila de llamadasNo agregaAgrega (consumido por return)

Gestionando ramificaciones con flags

Guarda los resultados de las opciones en variables (flags) para referenciarlos en escenas posteriores.

Declarando flags

renpy
# 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

renpy
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.

renpy
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."

renpy
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ó.

renpy
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.

renpy
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.

renpy
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.

FAQ

¿Qué pasa si todas las opciones del menú son condicionales y ninguna se cumple?

Ren'Py salta el menú completo y continúa la ejecución en la siguiente línea. Esto aplica sin importar si config.menu_include_disabled está en True — las opciones en gris necesitan al menos una opción seleccionable, o el menú se omite por completo.

¿Puedo anidar un menú dentro de otro?

Sí. Puedes colocar una declaración menu dentro de un bloque de opción. Sin embargo, los menús anidados más de dos niveles se vuelven difíciles de leer rápidamente. Si la anidación se pone profunda, mueve el menú interno a un label separado y usa call para mantener el código organizado.

¿Cómo muestro qué opciones eligió el jugador en una segunda partida?

Usa la acción ChoiceReturn con una pantalla de opciones personalizada. En la pantalla, usa renpy.has_been_seen() para verificar si ya se pasó por ciertos labels, o usa un set persistent para dar un estilo diferente a las opciones previamente elegidas (por ejemplo, una marca de verificación o un color atenuado).

¿Cuál es la diferencia entre default y define para flags?

default crea una variable que se guarda en los archivos de guardado y se restaura al cargar — úsala para cualquier valor que cambie durante el juego. define crea una constante que se establece una vez en la inicialización y nunca se guarda. Si usas define para un flag, se reiniciará cada vez que se inicie el juego. Consulta nuestra guía de gestión de estadísticas para más detalles.

¿Puedo usar call con argumentos?

Sí. call label_name(arg1, arg2) pasa argumentos al label, y _return captura el valor de return "value". Esto es útil para escenas reutilizables donde, por ejemplo, un label de tienda recibe una lista de inventario como parámetro.

¿Cómo hago opciones con límite de tiempo que se auto-seleccionan?

Usa un timer en una pantalla de opciones personalizada. Cuando el timer se activa, devuelve un valor por defecto. Los foros de Lemma Soft tienen varias implementaciones listas para usar.

¿Importa el orden de las opciones en un menú?

El orden de visualización coincide con el orden en tu script. Internamente, Ren'Py no asigna ningún significado especial a la posición. Por accesibilidad, coloca la opción "segura" o por defecto primero. En móvil, la primera opción queda más cerca del pulgar del jugador.

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: jump es solo ida, call regresa vía return. Usa call para escenas compartidas
  • Gestión de flags: Declara variables con default para guardar resultados de opciones
  • Opciones condicionales: Controla la visibilidad con condiciones if. config.menu_include_disabled para 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:

Artículos relacionados: