Custom dialogue boxes not being cleared when scene or menu statements are used

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Message
Author
makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Custom dialogue boxes not being cleared when scene or menu statements are used

#1 Post by makorays »

Alright, so, first of all, I barely even remember how my partner and I cobbled this code together, but basically we made and/or found something that enables dialogue boxes to have scrolling background images on them. Only problem is that the dialogue box never really goes away on its own, which I'd like it to do when changing scenes or showing menu items, just like how the default dialogue box works.

Code: Select all

transform maskpos:
    pos (0.0, 0.75)
transform dialoguepan:
    align (0.0, 1.0)
    block:
        offset (0, 0)
        linear 3.0 offset (-150, 80)
    repeat

init:
    default speaking_char = None
    python:
        from functools import partial
        def chartextbg(char, event, *args, **kwargs):
            if event == "begin":
                if store.speaking_char != char:
                    renpy.show("images/gui/" + char + "_bg.png", tag='dialoguelayer', layer='screens', what=AlphaMask(Fixed(At("images/gui/" + char + "_bg.png", dialoguepan)), At("images/gui/dialoguemask.png", maskpos)))
                    renpy.restart_interaction()
                    store.speaking_char = char
                    
define e = Character("Emily", callback=partial(chartextbg, "Emily"), image='e')
(For the record, I have absolutely no idea why "renpy.restart_interaction()" is even there or what it does, but I'm afraid to touch it.)
I can make it hide by adding this to it:

Code: Select all

if event == "end":
	renpy.hide('dialoguelayer', layer='screens')
...but this causes other problems. I only want it to hide when a scene or menu statement is used, but I don't know how to make that happen. Intuition would leave me to believe that those statements hide some sort of layer or image tag when used, but I don't know which, or if that's even how it works. I've looked through all the script files and I can't find where the scene or menu statements are defined, I have no idea how they actually work or what the basic differences between my dialogue box and the default one are.

What are the scene and menu statements doing that causes the default dialogue box to go away, and how might I apply that to my own? Or, alternatively, is there some sort of syntax I could use to basically go:

Code: Select all

if [scene statement happens] or [menu statement happens]:
 	renpy.hide('dialoguelayer', layer='screens')
 	store.speaking_char = None
?

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#2 Post by m_from_space »

You are not really showing your own dialogue window, but just an image on the "screens" layer that's associated with the speaking character.
makorays wrote: Tue Jul 19, 2022 7:29 am(For the record, I have absolutely no idea why "renpy.restart_interaction()" is even there or what it does, but I'm afraid to touch it.)
"Restarts the current interaction. Among other things, this displays images added to the scene, re-evaluates screens, and starts any queued transitions." As part of a Character callback event it's sometimes necessary to make changes visible (like showing that screen). You will probably see, that your custom dialogue window background might not properly work without the interaction to restart.

1. scene: hides all images on a layer (it defaults to the "master" layer) and optionally shows the image statement after the keyword

Solution for you: "scene onlayer screens ..." (but it will of course clear other images on the screens layer, too). You might want to create your own layer only for that dialogue window, so no other stuff gets hidden. https://www.renpy.org/doc/html/config.h ... fig.layers or show your background on the "master" layer instead. In this case the "scene" statement will automatically remove it.

2. menu: calls the choice() screen that's part of screens.rpy. If your menu does not include a line of dialogue, it also might hide the dialogue window in the same way that it would do when you use "pause" for example.

Solution for you: alter the choice() screen:

Code: Select all

screen choice(items):
    on "show" action Function(renpy.hide, name='dialoguelayer', layer='screens')
    ...
What are the scene and menu statements doing that causes the default dialogue box to go away, and how might I apply that to my own? Or, alternatively, is there some sort of syntax I could use to basically go:

Code: Select all

if [scene statement happens] or [menu statement happens]:
 	renpy.hide('dialoguelayer', layer='screens')
 	store.speaking_char = None
?
Your function that shows the dialogue window is a character callback. It gets executed only when a new dialogue line begins. Therefore you evaluate "if event == 'begin'". Here is more on character callbacks: https://www.renpy.org/doc/html/character_callbacks.html - You cannot detect if a scene or menu statement is getting executed with that.

You should use the Renpy documentation more often in my opinion!

It's a bit confusing that you name your image "dialoguelayer" by the way, since it's not a layer, but a name for that image. :D

Could you show what your dialogue background looks like by the way? Because I assume there would be an easier way doing it by altering the say screen.

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#3 Post by makorays »

I honestly cannot figure out what difference the restart_interaction thing is doing whether I turn it on or off but I'll just leave it there just in case I guess.

1. So I'm just supposed to type "scene onlayer screens" in place of every time I'd normally type "scene" when doing a transition? I just tried that, functionality is the same: dialogue box still isn't cleared when transitioning scenes. I double checked that everything is set up like you suggested (short of making a custom layer, but you implied it should still show results without that), no idea why it's not working.

Okay, once you told me the scene statement defaults to the master layer I was like "oh, okay, I'll just set it to be on the master layer instead of the screens layer", but this causes additional problems. The new functionality is as follows:
-The black narrator box I have now never goes away, overlapping other characters' boxes, tinting them black. It also doesn't go away when changing scenes.
-Other characters' boxes now properly go away when the scene is changed, and also go away when a new character/the narrator speaks. They still remain when a menu appears (but that part is fixed with your other suggestion).

Here's the code I'm using for the narrator character. I'm gonna be totally honest: I barely understand a single thing about any of why this is written the way it is and don't remember writing/finding it since it was so long ago.

Code: Select all

define narrator = Character(None,
	callback=partial(chartextbg, "narrator"))

define generic = Character("generic",
	callback=partial(chartextbg, "narrator"),
	namebox_background = Frame("Generic_nbox", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign))
(EDIT: Oh right, that second thing is for generic background characters and shouldn't really have anything to do with the narrator dialogue. Still no idea why the other characters are working but the narrator isn't. Only difference is it's set to "None", which I'm guessing it has to be for this to be read as the narrator?)

2. OKAY THANK YOU THANK YOU this seems to work for menus.

I had stared at that callback page for quite a while, actually, and have scoured the documentation trying to figure this stuff out. I only came here after my friends and I spent hours trying to figure this out with the documentation. I wasn't aware of the syntax needed for the 'on "show" action Function(renpy.hide)' stuff, or that it was even possible.

Oh, yeah, I'm not sure why it's named dialoguelayer, I guess when my partner and I wrote it we assumed that was how layers worked, or something? I dunno. I'll just change it to dialoguebox.

Here's what the custom dialogue box looks like. Every character has a different-colored one with different shapes like the little hearts in this one, and the whole thing slowly slides diagonally down left repeatedly to make it look like the shapes are infinitely scrolling by. The narrator's box is just solid blank.

Image

I don't 100% remember why we didn't just alter the say screen, but I suspect it's because we found it too limiting? We need the box to have the following properties (though if this is possible with editing the say screen and you think it'd be easier, let me know):
-use a different image for each character
-don't redisplay the box when the same character says two lines in a row

That last point is why the whole code is set to only display a dialogue box when the speaking character changes. Otherwise, the scrolling animation awkwardly resets on every line of dialogue. (If there was some way to sort of have that animation consistently playing at all times even when a particular image goes away or is redisplayed, rather than restarting itself every time the image is displayed, that would improve a lot of things, but I dunno if that's possible.)

Okay, so, right now I only actually have two problems.
1. The narrator's box refuses to go away. I'm sure this is my fault and will TRY to look at the code I wrote for it but I'm not sure I'll understand what the problem is.
2. Because it's set up to only display a new image when a new character speaks...if I have Maddie say a line, then change the scene, then have her say a new line, her dialogue box on that new line doesn't appear. This is why I so badly wish I could just set it up to do things 'on "scene" action'. Is that really not possible? It feels like it should be but I don't know what the syntax might be. If I could do that in a similar way you helped me do it with the menu action, I could simply write:
"on scene action -> hide dialogue box -> set speaking character to None"
...and that would be that. Or if I could just edit the way the scene statement works, that'd work fine too.

Appreciate the help so far, though. Halfway there.

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#4 Post by m_from_space »

I just tried out making this functionality possible just using a single screen and using one line inside the say screen. And it seems to work, also the animation effect doesn't change when the same character speaks multiple lines. Don't know about other effects. But the background will go away whenever the say screen goes away. So no additional programming of "scene" or "menu" necessary. Also no callbacks necessary.

Code: Select all

# variable to save who is speaking at the moment
default say_who = None

# a function for a dynamic displayable, that is used for changing the image depending on the character that is speaking
init python:
    def charBg(st, at):
        global say_who
        if say_who is None or say_who == "generic":
            say_who = "narrator"
        d = AlphaMask(Fixed(At("images/gui/{}_bg.png".format(say_who), dialoguepan)), At("images/gui/dialoguemask.png", maskpos))
        return d, None
        
# the dynamic displayable that calls the function
image bg_chars = DynamicDisplayable(charBg)

screen backgrounds:
    # only show this, if the say screen is visible
    if renpy.get_screen("say"):
        frame:
            background "bg_chars"

screen say(who, what):
    on "show" action SetVariable("say_who", who)
    ...
Now of course you need to show that screen in the beginning of the game.

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#5 Post by makorays »

Oh, that's.....95% working!!
Only problem is that whenever the dialogue boxes fade in or out, they turn into the black narrator box. I'm trying to figure out how to fix that but my brain is kind of slow right now and I'm not familiar with all the syntax. Do you know why that's happening?

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#6 Post by m_from_space »

You mentioned your black narrator box, but I have no idea what part of your code is showing a black box. Figure out how it comes into play! :)

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#7 Post by makorays »

I also have no idea what part of my code is showing the black box! I am just a humble artist trying to fumble my way into the code I need to make my art function. I really appreciate your help but this code is honestly just too advanced for me to understand enough to problem solve.

If you're asking what the black box is, it's just the background I'm using for the narrator and generic background characters, and I'm pretty sure the only relevant code for that is this stuff:

Code: Select all

define narrator = Character(None)
define generic = Character("generic", namebox_background = Frame("Generic_nbox", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign))
define am = Character("Alex\'s Mom", kind=generic)
But, like, I don't even remember how the "None" thing even works. I'm assuming it's responsible for allowing me to set the background for the narrator but I have no idea why it'd be inserting itself briefly every time I use a scene or menu statement.

I also forgot to mention I changed the say screen around a little bit to make nameboxes work? I don't know if that's even relevant, but here's my whole say screen now.

Code: Select all

screen say(who, what):
    on "show" action SetVariable("say_who", who)
    style_prefix "say"

    window:
        id "window"

        if who is not None:

            window:
                id "namebox"
                style "namebox"
                background Frame(who + "_nbox", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign)
                text who id "who"

        text what id "what"
I keep scouring my code to make sure there's nothing I'm leaving out but I honestly don't think there is. I promise you I'm trying my best here and am googling stuff between posts but I just don't have the experience to know how half this stuff works.

Here's how my backgrounds are set up in the file structure, if that helps...?
Image

EDIT: Oh wow, I just noticed the dialogue boxes are now behaving the way I said I'd love for them to work where their animations are like, consistent between each other! So even when a new character talks, the animation doesn't restart. I have no idea how you got it to function like that but thank you, now if I only knew how to not have them flash black for a sec in scene and menu transitions...

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#8 Post by m_from_space »

makorays wrote: Wed Jul 20, 2022 5:27 am

Code: Select all

define narrator = Character(None)
define generic = Character("generic", namebox_background = Frame("Generic_nbox", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign))
define am = Character("Alex\'s Mom", kind=generic)
But, like, I don't even remember how the "None" thing even works. I'm assuming it's responsible for allowing me to set the background for the narrator but I have no idea why it'd be inserting itself briefly every time I use a scene or menu statement.
"None" as the first argument in the Character() function just tells renpy that this character has no name and therefore in the dialogue window no namebox will appear. It's used for the narrator character. You can see this in your say screen where it says "if who is not None" - meaning that only when "who" has a name, the namebox will be shown.

Well I guess we could actually go back to just setting the "say_who" variable via a callback instead of using the say screen. xD

Code: Select all

default say_who = None
init python:
    from functools import partial
    def chartextbg(char, event, *args, **kwargs):
        if event == "begin":
            store.say_who = char
        return

# for the narrator and generic characters
define narrator = Character(None, callback=partial(chartextbg, "narrator"))
define generic = Character("generic", namebox_background = Frame("Generic_nbox", gui.namebox_borders, tile=gui.namebox_tile, xalign=gui.name_xalign), callback=partial(chartextbg, "narrator"))

# for every other character
define e = Character("Emily", callback=partial(chartextbg, "Emily"), image='e')
Sorry for that step back! You can delete the line from the say screen. The reason we have to do that, is that otherwise you would have to create a background for every generic character (even if they have the same color). This way we always use the "narrator" bg for generic characters. We cannot know if a character is "generic" inside the say screen, since we only have their names.
EDIT: Oh wow, I just noticed the dialogue boxes are now behaving the way I said I'd love for them to work where their animations are like, consistent between each other! So even when a new character talks, the animation doesn't restart. I have no idea how you got it to function like that but thank you, now if I only knew how to not have them flash black for a sec in scene and menu transitions...
Really? Because I didn't account for that. I just made sure that the animation is not getting reset, when the same character is speaking. But if you want an animation to not reset, when it's used by another object, just put the "animation" keyword inside the transform.

Code: Select all

transform dialoguepan:
    animation
    align (0.0, 1.0)
    block:
        offset (0, 0)
        linear 3.0 offset (-150, 80)
    repeat
What do you mean the "menu" and "scene" statements still don't work by the way? Because they should. (I never make mistakes of course! ^^) You say that they flash back?
Before every menu and scene you could write:

Code: Select all

window auto hide
That way you hide the say screen. It will reappear automatically with a new dialogue text.

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#9 Post by makorays »

What do you mean the "menu" and "scene" statements still don't work by the way? Because they should. (I never make mistakes of course! ^^) You say that they flash back?
They were flashing black, as in they became the black narrator/generic dialogue box during their fadeouts and fadeins.

Which they're not doing now that I've put that new code in, but...man, this is so close. The only problem now is what happens when one character speaks, then a scene/menu statement happens, followed by a different character. When I write:

Code: Select all

m "words"
scene bg sidewalk
"i am the narrator"
...what happens is:
>Maddie speaks
>Scene statement causes her orange dialogue box to fade out
>New scene fades in, along with that same orange dialogue box, even though the next line belongs to the narrator, and once it's finished fading in it switches to the appropriate black dialogue box. I want the fading in box to be the color of the new speaker so it doesn't awkwardly swap colors like that.

I'm trying to think of what could be done about this. The say_who variable isn't being updated until after the scene transition has completed, but I need it to happen during it.

Ah, looking at the documentation, the problem seems to be the fact that bg_chars is a dynamic displayable.
Note that these dynamic displayables always display their current state. Because of this, a dynamic displayable will not participate in a transition. (Or more precisely, it will display the same thing in both the old and new states of the transition.)
Now, will I be able to figure out how to fix this before you respond again...

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#10 Post by m_from_space »

How about changing say_who right before the scene statement? Just change it to whoever is speaking after that. ("None" for narrator/generic and the names of the other characters for everybody else.)

Code: Select all

m "words"
$ say_who = None
scene bg sidewalk
"i am the narrator"

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#11 Post by makorays »

Nah, then the opposite problem happens, where the box that's supposed to be orange while fading out becomes black all of a sudden. I'm also ideally trying to avoid having to write extra lines before nearly every scene/menu statement, so much of this has already been automated so I feel like it should be possible.

Is there a way to use the function as an image without using DynamicDisplayable? Or is there a way to make it so DynamicDisplayable respects transitions?

The doc says:
By design, dynamic displayables are intended to be used for things that change rarely and when an image defined this way is off screen (Such as a character customization system). It is not designed for things that change frequently, such as character emotions.
...so is there not a different thing we could be using here, something that's designed to change frequently and work with transitions?

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#12 Post by m_from_space »

It's a bit hard for me to really help out without having your base code and looking at what's going on while those statements happen tbh. You also mention "transitions", while you don't have a transition just writing "scene". So I assume you are talking about "with Fade(...)" statements?

Have you tried "window auto hide" before a scene change as suggested? I know you don't want to write extra lines, but those lines have meaning. I mean it's programming after all. ;)

edit:
By the way, your biggest problem with all this is not custom backgrounds for characters - that's actually very easy. The problem ist that you want them to be animated. The say screen is notoriously annoying regarding that, since it shows and hides itself between every dialogue line (even though you don't see it as a player). Therefore it resets everything. And for some reason the "animation" keyword doesn't apply to transforms inside the say screen. I had that problem with other people wanting to do stuff with the screen.

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#13 Post by makorays »

Oh, does the default scene statement not employ transitions? It dissolves everything so I figured that's what it was using. I dunno what it's actually doing to make it dissolve, if that's the case.

Oh dang. I DID try "window auto hide" when you first suggested it, and it didn't seem to help, but combining it with changing the say_who before a transition actually makes everything work exactly how I want it to. But man, I feel like there's gotta be a way to avoid having to do that every single time I bring up a menu or change the scene...maybe I should just figure out how to define a custom scene statement?

The animations have been working flawlessly for a while now, by the way, it was just the weirdness when scene and menu statements cause them to fade.

If you'd like, I can put together a couple simplified script files showing all the relevant code here. Let me just do that real quick.

User avatar
m_from_space
Eileen-Class Veteran
Posts: 1238
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#14 Post by m_from_space »

I just now set up something that simulates your game and now understand what you mean by that small flash of the background whenever you make a scene statement.

My workaround for that is the following.

Code: Select all

def charBg(st, at):
    global say_who
    if say_who == "hide":
        return Null(), None
    if say_who is None or say_who == "generic":
        say_who = "narrator"
    d = AlphaMask(At("images/gui/{}_bg.jpg".format(say_who), dialoguepan), At("images/gui/dialoguemask.png", maskpos))
    return d, None
Before every scene statement just write:

Code: Select all

$ say_who = "hide"

makorays
Newbie
Posts: 11
Joined: Tue Jul 19, 2022 7:07 am
Tumblr: makorays
Contact:

Re: Custom dialogue boxes not being cleared when scene or menu statements are used

#15 Post by makorays »

I just tried that; had to change

Code: Select all

d = AlphaMask(At("images/gui/{}_bg.jpg".format(say_who), dialoguepan), At("images/gui/dialoguemask.png", maskpos))
to

Code: Select all

d = AlphaMask(Fixed(At("images/gui/{}_bg.png".format(say_who), dialoguepan)), At("images/gui/dialoguemask.png", maskpos))
in order to work with my setup, and it does save me from having to type window auto hide, but now the dialogue box just cuts out and in rather than fading, and I'd like it to fade.

I've attached a simplified test project with all the relevant code if you wanna look at exactly what I've got right now. I only edited script.rpy and screens.rpy, you can ctrl+f for the word "alteration" to see what I changed in screens.
testing grounds.zip
(1.83 MiB) Downloaded 49 times
I realize it's already possible to do what I want if I just commit to writing two extra lines in front of every scene/menu statement but I'm both a perfectionist and incredibly curious to know what the most efficient way to do this is. If you feel like I'm wasting your time, don't be afraid to let me know. :V

Post Reply

Who is online

Users browsing this forum: halnye