Renpy Speech Bubble Namebox

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.
Post Reply
Message
Author
User avatar
luat1995
Newbie
Posts: 24
Joined: Mon Nov 07, 2016 8:27 am
Completed: Home Alone
Github: https://github.com/luatsenpai
itch: https://luatsenpai.i
Location: vietnamese
Contact:

Renpy Speech Bubble Namebox

#1 Post by luat1995 »

Hello, I use the template at https://github.com/RenpyRemix/speech-bubbles
But I have some problems
Namebox does not appear in the position I want
Image
How to fix it? Sorry, i'm not good at english
My code:

Code: Select all

## To view example in your game add
##
##  call speech_bubble_example
##
## somewhere in your running label script



            ###########################################
            #                                         #
            #           To use in your game           #
            #                                         #
            #   Create your characters and set them   #
            #   to use the speech bubble screen.      #
            #   The example at the end has a couple   #
            #   of characters to see how.             #
            #   Maybe delete the example bits (at     #
            #   the end of this file) once happy      #
            #                                         #
            ###########################################




                            ###################
                            #                 #
                            #     Styles      #
                            #                 #
                            ###################

#
# https://github.com/RenpyRemix/speech-bubbles/blob/master/explain_frames.md
#

# Characters who use the speech bubbles will need their what_style pointed
# at a style similar to this 
#
# The first two settings are quite important. They let the bubbles
# shrink to the text bounds and position the first letter

style bubble_speech_text:
    xsize None # needed - otherwise it uses a gui setting
    align (0,0) # also likely needed

    # just standard font specific stuff
    color "#66CC66"
    # font ""
    kerning -1.0
    size 26
    bold True


# A rotated version of the bubble image
image speech_bubble_90:
    # using contains so it rotates before crop
    contains:
        "images/speech_bubble.png"
        rotate_pad False
        transform_anchor True
        anchor (0.0, 1.0)
        rotate 90.0
    # crop (as rotation increased the size)
    crop (0, 0, 152, 261)


# Styles for the different frames
# Each direction the tail points uses different values so has its own style

style bubble_speech_baseright_frame:

    # our background picture
    background Frame(
        "images/speech_bubble.png", 
        left = Borders(32, 33, 88, 80)
        )

    # These are the distance between the text area and frame outer edge
    left_padding 24
    top_padding 22
    right_padding 23
    bottom_padding 73
    # We *could* do all that in one line with
    # padding (24, 22, 23, 73) # (left, top, right, base)

    minimum (121, 114)

    # Now the anchor (the pixel of this widget to place at the stated pos)
    # This should generally reflect where the end of the tail lies
    anchor (1.0, 1.0)
    # You could add a slight offset if wanted (so show_pos is on the tail)
    offset (12, 7)


style bubble_speech_baseleft_frame:

    # our background picture
    background Frame(
        Transform("images/speech_bubble.png", xzoom=-1),
        left = Borders(88, 33, 32, 80)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 22, 24, 73) #right, top, left, bottom

    minimum (121, 114)
    anchor (0.0, 1.0)
    offset (-12, 7)


style bubble_speech_topright_frame:

    # our background picture
    background Frame(
        Transform("images/speech_bubble.png", yzoom=-1), 
        left = Borders(32, 80, 88, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (24, 73, 23, 22) #left, bottom, right, top

    minimum (121, 114)
    anchor (1.0, 0.0)
    offset (12, -7)


style bubble_speech_topleft_frame:

    # our background picture
    background Frame(
        Transform("images/speech_bubble.png", zoom=-1),
        left = Borders(88, 80, 32, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 73, 24, 22) #right, bottom, left, top

    minimum (121, 114)
    anchor (0.0, 0.0)
    offset (-12, -7)



style bubble_speech_leftbase_frame:

    # our background picture
    background Frame(
        "speech_bubble_90",
        left = Borders(80, 32, 33, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 24, 22, 23)#bottom, left, top, right

    minimum (114, 121)
    anchor (0.0, 1.0)
    offset (-7, 12)


style bubble_speech_lefttop_frame:

    # our background picture
    background Frame(
        Transform("speech_bubble_90", yzoom=-1), 
        left = Borders(80, 88, 33, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 23, 22, 24)#bottom, right, top, left

    minimum (114, 121)
    anchor (0.0, 0.0)
    offset (-7, -12)


style bubble_speech_righttop_frame:

    # our background picture
    background Frame(
        Transform("speech_bubble_90", zoom=-1), 
        left = Borders(33, 88, 80, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 23, 73, 24)#top, right, bottom, left

    minimum (114, 121)
    anchor (1.0, 0.0)
    offset (7, -12)


style bubble_speech_rightbase_frame:

    # our background picture
    background Frame(
        Transform("speech_bubble_90", xzoom=-1), 
        left = Borders(33, 32, 80, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 24, 73, 23)#top, left, bottom, right

    minimum (114, 121)
    anchor (1.0, 1.0)
    offset (7, 12)
#################################################################################
# Just one to test we can pass (show_type="bubble_thought") and have it
# pick up a different style
#########################################################################
image thought_bubble_90:
    # using contains so it rotates before crop
    contains:
        "images/thought_bubble.png"
        rotate_pad False
        transform_anchor True
        anchor (0.0, 1.0)
        rotate 90.0
    # crop (as rotation increased the size)
    crop (0, 0, 261, 152)
style bubble_thought_baseright_frame:

    # our background picture
    background Frame(
        "images/thought_bubble.png", 
        left = Borders(32, 33, 88, 80)
        )

    # These are the distance between the text area and frame outer edge
    left_padding 28
    top_padding 32
    right_padding 32
    bottom_padding 60
    # We *could* do all that in one line with
    # padding (24, 22, 23, 73) # (left, top, right, base)

    minimum (121, 114)

    # Now the anchor (the pixel of this widget to place at the stated pos)
    # This should generally reflect where the end of the tail lies
    anchor (1.0, 1.0)
    # You could add a slight offset if wanted (so show_pos is on the tail)
    offset (12, 7)


style bubble_thought_baseleft_frame:

    # our background picture
    background Frame(
        Transform("images/thought_bubble.png", xzoom=-1),
        left = Borders(88, 33, 32, 80)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 22, 24, 73)

    minimum (121, 114)
    anchor (0.0, 1.0)
    offset (-12, 7)


style bubble_thought_topright_frame:

    # our background picture
    background Frame(
        Transform("images/thought_bubble.png", yzoom=-1), 
        left = Borders(32, 80, 88, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (24, 73, 23, 22)

    minimum (121, 114)
    anchor (1.0, 0.0)
    offset (12, -7)


style bubble_thought_topleft_frame:

    # our background picture
    background Frame(
        Transform("images/thought_bubble.png", zoom=-1),
        left = Borders(88, 80, 32, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 73, 24, 22)

    minimum (121, 114)
    anchor (0.0, 0.0)
    offset (-12, -7)



style bubble_thought_leftbase_frame:

    # our background picture
    background Frame(
        "thought_bubble_90",
        left = Borders(80, 32, 33, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 24, 22, 23)

    minimum (114, 121)
    anchor (0.0, 1.0)
    offset (-7, 12)


style bubble_thought_lefttop_frame:

    # our background picture
    background Frame(
        Transform("thought_bubble_90", yzoom=-1), 
        left = Borders(80, 88, 33, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 23, 22, 24)

    minimum (114, 121)
    anchor (0.0, 0.0)
    offset (-7, -12)


style bubble_thought_righttop_frame:

    # our background picture
    background Frame(
        Transform("thought_bubble_90", zoom=-1), 
        left = Borders(33, 88, 80, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 23, 73, 24)

    minimum (114, 121)
    anchor (1.0, 0.0)
    offset (7, -12)


style bubble_thought_rightbase_frame:

    # our background picture
    background Frame(
        Transform("thought_bubble_90", xzoom=-1), 
        left = Borders(33, 32, 80, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 24, 73, 23)

    minimum (114, 121)
    anchor (1.0, 1.0)
    offset (7, 12)
#####################################################################
image shout_bubble_90:
    # using contains so it rotates before crop
    contains:
        "images/shout_bubble.png"
        rotate_pad False
        transform_anchor True
        anchor (0.0, 1.0)
        rotate 90.0
    # crop (as rotation increased the size)
    crop (0, 0, 261, 152)
style bubble_shout_baseright_frame:

    # our background picture
    background Frame(
        "images/shout_bubble.png", 
        left = Borders(32, 33, 88, 80)
        )

    # These are the distance between the text area and frame outer edge
    left_padding 54
    top_padding 47
    right_padding 54
    bottom_padding 61
    # We *could* do all that in one line with
    # padding (24, 22, 23, 73) # (left, top, right, base)

    minimum (121, 114)

    # Now the anchor (the pixel of this widget to place at the stated pos)
    # This should generally reflect where the end of the tail lies
    anchor (1.0, 1.0)
    # You could add a slight offset if wanted (so show_pos is on the tail)
    offset (12, 7)


style bubble_shout_baseleft_frame:

    # our background picture
    background Frame(
        Transform("images/shout_bubble.png", xzoom=-1),
        left = Borders(88, 33, 32, 80)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 22, 24, 73)

    minimum (121, 114)
    anchor (0.0, 1.0)
    offset (-12, 7)


style bubble_shout_topright_frame:

    # our background picture
    background Frame(
        Transform("images/shout_bubble.png", yzoom=-1), 
        left = Borders(32, 80, 88, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (24, 73, 23, 22)

    minimum (121, 114)
    anchor (1.0, 0.0)
    offset (12, -7)


style bubble_shout_topleft_frame:

    # our background picture
    background Frame(
        Transform("images/shout_bubble.png", zoom=-1),
        left = Borders(88, 80, 32, 33)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (23, 73, 24, 22)

    minimum (121, 114)
    anchor (0.0, 0.0)
    offset (-12, -7)



style bubble_shout_leftbase_frame:

    # our background picture
    background Frame(
        "shout_bubble_90",
        left = Borders(80, 32, 33, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 24, 22, 23)

    minimum (114, 121)
    anchor (0.0, 1.0)
    offset (-7, 12)


style bubble_shout_lefttop_frame:

    # our background picture
    background Frame(
        Transform("shout_bubble_90", yzoom=-1), 
        left = Borders(80, 88, 33, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (73, 23, 22, 24)

    minimum (114, 121)
    anchor (0.0, 0.0)
    offset (-7, -12)


style bubble_shout_righttop_frame:

    # our background picture
    background Frame(
        Transform("shout_bubble_90", zoom=-1), 
        left = Borders(33, 88, 80, 32)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 23, 73, 24)

    minimum (114, 121)
    anchor (1.0, 0.0)
    offset (7, -12)


style bubble_shout_rightbase_frame:

    # our background picture
    background Frame(
        Transform("shout_bubble_90", xzoom=-1), 
        left = Borders(33, 32, 80, 88)
        )

    # The distance between content and outer edge (left, top, right, base)
    padding (22, 24, 73, 23)

    minimum (114, 121)
    anchor (1.0, 1.0)
    offset (7, 12)
                            ####################
                            #                  #
                            #     Screens      #
                            #        &         #
                            #      Python      #
                            #                  #
                            ####################
                # 
                # You probably will not need to edit this part
                #
                # Except maybe the callback if you want the default
                # values to be different

#
# https://github.com/RenpyRemix/speech-bubbles/blob/master/explain_screens.md
#

default retained_dialogues = []

init python:

    # This is just a list of style names that we want to remember for when
    # multiple dialogues (bubbles) appear at once
    retained_styles = (
        renpy.screenlang.text_property_names 
        + renpy.screenlang.position_property_names)


    #This function gets called after each dialogue is shown
    # It is responsible for calculating what will be shown with the
    # next dialogue
    def hide_dialogue(current_dialogue=None, screen="bubble_say"):
        """
        Decrease all `retain` values by one and rebuild global
        shown_dialogues only from those set to still be shown

        Then add the current dialogue if it has been set to retain
        """
        global retained_dialogues

        next_retained_dialogues = []

        for k in retained_dialogues:

            k[1] -= 1

            if k[1] > 0:

                next_retained_dialogues.append(k)

        retained_dialogues = next_retained_dialogues

        if current_dialogue and not current_dialogue[0][0].endswith('.rpym'):

            # This is where you could add a feature so one dialogue could 
            # alter setting for a retained dialogue (such as move it)

            if current_dialogue[1] > 0:

                # retain this one, so add it to the global

                # first mirror the style applied to the text and add it
                # to the kwargs

                widget = renpy.get_widget(screen, 'what')
                if widget:
                    widget_style = {
                        k : getattr(widget.style, k)
                        for k in dir(widget.style)
                        if k in retained_styles
                    }
                    current_dialogue[-1]['what_style'] = widget_style

                retained_dialogues.append(list(current_dialogue))


    # We use this callback so we can use simple arguments rather than
    # keywords each time
    def say_arguments_callback(who, *args, **kwargs):

        if hasattr(who, "screen") and who.screen == "bubble_say":

            # First we convert any passed args into kwargs 
            # (if the named kwarg has not been set)
            #
            # Args are a utility to pass common values quickly
            # (xpos, ypos, tail)

            if not "show_pos" in kwargs:
                # Default POS as a list Not tuple
                kwargs['show_pos'] = list(kwargs.get('show_pos', (800, 400))) 

                if args and args[0] is not None:
                    kwargs['show_pos'][0] = args[0]
                if len(args) > 1 and args[1] is not None:
                    kwargs['show_pos'][1] = args[1]

            if not "show_tail" in kwargs:
                # Default tail style
                kwargs['show_tail'] = 'baseright' 

                if len(args) > 2 and args[2] is not None:
                    kwargs['show_tail'] = args[2]

            # You could amend to pass others as args too

            kwargs['show_type'] = kwargs.get('show_type', "bubble_speech")
            kwargs['show_xmax'] = kwargs.get('show_xmax', 320)
            #kwargs['show_xmin'] = kwargs.get('show_xmin', 0)

        kwargs['interact'] = kwargs.get('interact', True)

        return (), kwargs

    config.say_arguments_callback = say_arguments_callback


screen bubble_say(who, what, **kwargs):

    # This is the main container screen
    # It uses child screens to display each bubble, one for 
    # each dialogue that is set to be shown at this time

    # A tuple of information about the current dialogue line
    $ current_dialogue = (
        renpy.get_filename_line(),
        kwargs.pop('retain', 0),
        who,
        what,
        kwargs )

    # First the older (retained) dialogues
    for old_dialogue in retained_dialogues:

        $ old_who, old_what, old_kwargs = old_dialogue[2:]

        use bubble_subscreen(old_who, **old_kwargs):

            # Just standard Text here, no id needed
            # Styled to match how the 'retained' line was shown
            add Text(old_what, **old_kwargs['what_style'])

    # The current line (including the "what" id)
    use bubble_subscreen(who, **kwargs):


        text what id "what"
    if who is not None:

        window:
            id "namebox"
            style "namebox"
            text who id "who"



 
    # When this screen is hidden (at the next interaction from the player)
    # we pass the tuple of current dialogue info to the function
    on "hide":

        action Function(hide_dialogue, current_dialogue)



screen bubble_subscreen(who, **kwargs):

    # Each line of dialogue is shown in one of these subscreens
    # To use the correct Frame style we can pass keywords
    # show_type = the prefix part of the style
    # show_tail = the suffix part of the style
    #
    # The prefix_suffix then can use _frame as a style name

    style_prefix "{}_{}".format(kwargs['type'], kwargs['tail'])
    
    fixed:

        pos kwargs['pos']

        frame:

            xmaximum kwargs['xmax']

            # set the min width as show_xmin if passed else use default
            # (do not set smaller than the frame settings though)
            if "xmin" in kwargs:
                xminimum kwargs['xmin']

            # this single word tells this screen where to use 
            # the indented widgets/attributes (the text part)
            transclude

        if check_bubble_positions:
            add Solid('#FFF', xysize=(2, 40), anchor=(1, 20))
            add Solid('#FFF', xysize=(40, 2), anchor=(20, 1))

# Utility settings to draw a white cross at the specified 'show_pos'
# Maybe useful to setup Frame styles or fine tune positions
default check_bubble_positions = False

# On/Off toggle of the white cross using [Alt] + [c] keys together
init python:

    if config.developer:

        config.underlay.append(
            renpy.Keymap(
                alt_K_c = lambda: renpy.run(
                    ToggleVariable("check_bubble_positions"))))





            ###########################################
            #                                         #
            #   You can delete the example characters #
            #   and label below once happy            #
            #                                         #
            ###########################################



                            #####################
                            #                   #
                            #     Characters    #
                            #         &         #
                            #       Sample      #
                            #                   #
                            #####################


# 
# https://github.com/RenpyRemix/speech-bubbles/blob/master/explain_usage.md
#




define speech_bubble_a = Character(
    "Amber",
    screen="bubble_say", 
    what_color="#282", 
    what_style="bubble_speech_text",
    show_tail="leftbase")

define speech_bubble_y = Character(
    "yumi", 
    screen="bubble_say", 
    who_color="#000", 
    what_style="bubble_speech_text")#bubble_thought_baseright_frame
define think_bubble_y = Character(
    "yumi", 
    screen="bubble_say", 
    who_color="#000", 
    what_style="bubble_speech_text")
    

label speech_bubble_example:

    $ quick_menu = False

    window hide

    scene expression "#777"

    speech_bubble_k """A few lines showing the
    speech bubble system in action...""" (950, 300, "righttop")

    speech_bubble_a "Style default (baseright)
    \nYou can press Alt+C to show the used pos" (640, 320, show_xmax=500, what_color="#888")

    speech_bubble_k "Style baseleft" (640, 320, "baseleft")

    speech_bubble_a "Style leftbase" (640, 320, "leftbase")

    speech_bubble_k "Style lefttop" (640, 320, "lefttop")

    speech_bubble_a "Style topleft" (640, 320, "topleft")

    speech_bubble_k "Style topright" (640, 320, "topright")

    speech_bubble_a "Style righttop" (640, 320, "righttop")

    speech_bubble_k "Style rightbase" (640, 320, "rightbase")

    speech_bubble_a "... and back to the game" (
        640, 320, show_type="bubble_thought")

    return

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Renpy Speech Bubble Namebox

#2 Post by Remix »

You *almost* have it, just your who part wants to go together with the what part (so both are transcluded inside the bubble...

Something like:

Code: Select all


screen bubble_say(who, what, **kwargs):

    # This is the main container screen
    # It uses child screens to display each bubble, one for 
    # each dialogue that is set to be shown at this time

    # A tuple of information about the current dialogue line
    $ current_dialogue = (
        renpy.get_filename_line(),
        kwargs.pop('retain', 0),
        who,
        what,
        kwargs )

    # First the older (retained) dialogues
    for old_dialogue in retained_dialogues:

        $ old_who, old_what, old_kwargs = old_dialogue[2:]

        use bubble_subscreen(old_who, **old_kwargs):

            # Just standard Text here, no id needed
            # Styled to match how the 'retained' line was shown
            add Text(old_what, **old_kwargs['what_style'])
            
            ## For older (still showing bubbles) do similar here to that shown below 

    # The current line (including the "what" id)
    use bubble_subscreen(who, **kwargs):

        ## Your who part would go here
        ## Indented the same as the what text
        ## 
        ## You could style it or put it in a container such as vbox to control position etc
        ##
        ##
        
        vbox:
        
            text who id "who"
        
            text what id "what"
        
        
    # When this screen is hidden (at the next interaction from the player)
    # we pass the tuple of current dialogue info to the function
    on "hide":

        action Function(hide_dialogue, current_dialogue)
Note that I have not used the "namebox" id or style name. If you do style it I would advise just using a different name and creating a style from scratch.

If you needed things like colour/font etc to be preserved for older bubbles when showing multiple bubbles, you would need to edit the hide_dialogue function to record the "who" styling in a manner similar to the "what" styling and then use that recorded styling for that text.
Frameworks & Scriptlets:

User avatar
luat1995
Newbie
Posts: 24
Joined: Mon Nov 07, 2016 8:27 am
Completed: Home Alone
Github: https://github.com/luatsenpai
itch: https://luatsenpai.i
Location: vietnamese
Contact:

Re: Renpy Speech Bubble Namebox

#3 Post by luat1995 »

Remix wrote: Sat Mar 19, 2022 8:16 am You *almost* have it, just your who part wants to go together with the what part (so both are transcluded inside the bubble...

Something like:

Code: Select all


screen bubble_say(who, what, **kwargs):

    # This is the main container screen
    # It uses child screens to display each bubble, one for 
    # each dialogue that is set to be shown at this time

    # A tuple of information about the current dialogue line
    $ current_dialogue = (
        renpy.get_filename_line(),
        kwargs.pop('retain', 0),
        who,
        what,
        kwargs )

    # First the older (retained) dialogues
    for old_dialogue in retained_dialogues:

        $ old_who, old_what, old_kwargs = old_dialogue[2:]

        use bubble_subscreen(old_who, **old_kwargs):

            # Just standard Text here, no id needed
            # Styled to match how the 'retained' line was shown
            add Text(old_what, **old_kwargs['what_style'])
            
            ## For older (still showing bubbles) do similar here to that shown below 

    # The current line (including the "what" id)
    use bubble_subscreen(who, **kwargs):

        ## Your who part would go here
        ## Indented the same as the what text
        ## 
        ## You could style it or put it in a container such as vbox to control position etc

        ##
        
        vbox:
        
            text who id "who"
        
            text what id "what"
        
        
    # When this screen is hidden (at the next interaction from the player)
    # we pass the tuple of current dialogue info to the function
    on "hide":

        action Function(hide_dialogue, current_dialogue)
Note that I have not used the "namebox" id or style name. If you do style it I would advise just using a different name and creating a style from scratch.

If you needed things like colour/font etc to be preserved for older bubbles when showing multiple bubbles, you would need to edit the hide_dialogue function to record the "who" styling in a manner similar to the "what" styling and then use that recorded styling for that text.

Thank

Image

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]