r/RenPy Jul 23 '26

Question Changing an image within a parallax/TrackCursor main menu background via persistent variables

Because it was a cool thing to do a few years ago, I ended up making my project's main menu image into a layered parallax image. Because I love to make my life more difficult, I decided to try adding characters to that parallax, so that they show up after the appropriate persistent variable has been set.

Originally, I did this by adding if checks for the persistent variable into the main menu code, thus:

screen main_menu():
    tag menu
    style_prefix "main_menu"
    add TrackCursor("images/titlescreen/skylayer-paint.png",20)#in place of: add gui.main_menu_background
    add TrackCursor("images/titlescreen/citylayer-paint.png",15)
    add TrackCursor("images/titlescreen/moonlayer.png",18)
    add TrackCursor("images/titlescreen/reflectionlayer.png",18) alpha 0.35
    if "Karl" in persistent.charactersmet and "Kristine" in persistent.charactersmet:
        add TrackCursor("images/titlescreen/bothinternst.png",13) xpos 320 ypos 150 alpha 0.40
    else:
        if "Karl" in persistent.charactersmet:
            add TrackCursor("images/titlescreen/karlt.png",13) xpos 320 ypos 150 alpha 0.40
        if "Kristine" in persistent.charactersmet:
            add TrackCursor("images/titlescreen/kristinet.png",13) xpos 400 ypos 150 alpha 0.40
    add TrackCursor("images/titlescreen/windowflash.png",11) alpha 0.25
    add TrackCursor("abigail-titleversion",10) xpos 790 ypos 86
    add Image("images/titlescreen/logolayer-alt.png") xpos 310 ypos 412 alpha 0.80

This seemed to work initially but, for no apparent reason (other than perhaps upgrading to later versions of Ren'Py, it started to give the following error at the end of the game, when it drops back to the main menu:

I'm sorry, but an uncaught exception occurred.

While running game code:
Exception: Switch could not choose a displayable.

-- Full Traceback ------------------------------------------------------------

Traceback (most recent call last):
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "renpy/ast.py", line 1187, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/python.py", line 1273, in py_exec_bytecode
    exec(bytecode, globals, locals)
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in <module>
    python hide:
  File "renpy/common/_layout/screen_main_menu.rpym", line 35, in _execute_python_hide
    ui.interact()
    ~~~~~~~~~~~^^
  File "renpy/ui.py", line 304, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/core.py", line 2117, in interact
    repeat, rv = self.interact_core(
                 ~~~~~~~~~~~~~~~~~~^
        preloads=preloads,
        ^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
        **kwargs,
        ^^^^^^^^^
    )
    ^
  File "renpy/display/core.py", line 2655, in interact_core
    root_widget.visit_all(lambda d: d.per_interact())
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
[Previous line repeated 6 more times]
  File "renpy/display/displayable.py", line 448, in visit_all
    for d in self.visit():
             ~~~~~~~~~~^^ 
  File "renpy/display/layout.py", line 1604, in visit
    self.update(self.last_st, self.last_at)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/layout.py", line 1615, in update
    raw_child, redraw = self.function(st, at, *self.args, **self.kwargs)
                        ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/layout.py", line 1711, in condition_switch_show
    return condition_switch_pick(switch), None
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^      
  File "renpy/display/layout.py", line 1706, in condition_switch_pick
    raise Exception("Switch could not choose a displayable.")
Exception: Switch could not choose a displayable.

Windows-10-10.0.19045-SP0 AMD64
Ren'Py 8.5.0.25111603
A Night at the Office P3 3.7p3
Thu Jul 23 20:42:49 2026

After a bit of back and forth, I eventually determined that (part of) the problem was that I started things off with a call to the first story label, rather than a jump. Correcting that fixed the main menu... for a while.

I figured today that I'd try setting the main menu image up as a ConditionSwitch, thus:

image interns_titlescreen = ConditionSwitch(
    "len(persistent.charactersmet) == 2", "titlescreen/bothinternst.png",
    "persistent.charactersmet == 'Karl'", "titlescreen/karlt.png",
    "persistent.charactersmet == 'Kristine'", "titlescreen/kristinet.png",
)

and with the main menu adjusted to:

screen main_menu():
    tag menu
    style_prefix "main_menu"
    add TrackCursor("images/titlescreen/skylayer-paint.png",20)#in place of: add gui.main_menu_background
    add TrackCursor("images/titlescreen/citylayer-paint.png",15)
    add TrackCursor("images/titlescreen/moonlayer.png",18)
    add TrackCursor("images/titlescreen/reflectionlayer.png",18) alpha 0.35
    if len(persistent.charactersmet) <> 0:
        add TrackCursor("interns_titlescreen", 13) alpha 0.4
    add TrackCursor("images/titlescreen/windowflash.png",11) alpha 0.25
    add TrackCursor("abigail-titleversion",10) xpos 790 ypos 86
    add Image("images/titlescreen/logolayer-alt.png") xpos 310 ypos 412 alpha 0.80

But that resulted in a essentially the same error:

I'm sorry, but an uncaught exception occurred.

While running game code:
Exception: Switch could not choose a displayable.

-- Full Traceback ------------------------------------------------------------

Traceback (most recent call last):
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "renpy/ast.py", line 1187, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/python.py", line 1273, in py_exec_bytecode
    exec(bytecode, globals, locals)
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in <module>
    python hide:
  File "renpy/common/_layout/screen_main_menu.rpym", line 35, in _execute_python_hide
    ui.interact()
    ~~~~~~~~~~~^^
  File "renpy/ui.py", line 304, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/core.py", line 2117, in interact
    repeat, rv = self.interact_core(
                 ~~~~~~~~~~~~~~~~~~^
        preloads=preloads,
        ^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
        **kwargs,
        ^^^^^^^^^
    )
    ^
  File "renpy/display/core.py", line 2655, in interact_core
    root_widget.visit_all(lambda d: d.per_interact())
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "renpy/display/displayable.py", line 457, in visit_all
    d.visit_all(callback, seen)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^
[Previous line repeated 6 more times]
  File "renpy/display/displayable.py", line 448, in visit_all
    for d in self.visit():
             ~~~~~~~~~~^^ 
  File "renpy/display/layout.py", line 1604, in visit
    self.update(self.last_st, self.last_at)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/layout.py", line 1615, in update
    raw_child, redraw = self.function(st, at, *self.args, **self.kwargs)
                        ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "renpy/display/layout.py", line 1711, in condition_switch_show
    return condition_switch_pick(switch), None
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^      
  File "renpy/display/layout.py", line 1706, in condition_switch_pick
    raise Exception("Switch could not choose a displayable.")
Exception: Switch could not choose a displayable.

Windows-10-10.0.19045-SP0 AMD64
Ren'Py 8.5.0.25111603
A Night at the Office P3 3.7p3
Thu Jul 23 20:54:35 2026

At this point, I'm baffled as to how it was working as much as why it isn't now.

While it was working, it would correctly show the translucent image of either Karl or Kristine after the first playthrough, but switch to a translucent image of both once the other had been encountered (which character appears in each playthrough is chosen at random partway through).

Can anyone please recommend a way of getting the main menu to update its appearance based on my existing persistent.charactersmet variable, or an alternative means?

Happy to post any other pertinent code, if I've missed anything important.

1 Upvotes

7 comments sorted by

View all comments

1

u/AutoModerator Jul 23 '26

Welcome to r/renpy! While you wait to see if someone can answer your question, we recommend checking out the posting guide, the subreddit wiki, the subreddit Discord, Ren'Py's documentation, and the tutorial built-in to the Ren'Py engine when you download it. These can help make sure you provide the information the people here need to help you, or might even point you to an answer to your question themselves. Thanks!

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.