Smoothly moving the 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
isak grozny
Regular
Posts: 46
Joined: Mon Apr 11, 2016 10:17 am
Projects: The Bitter Drop [Modern Fantasy][Gay Romance][BxB]
itch: grrozny
Location: Edinburgh, UK
Contact:

Smoothly moving the namebox

#1 Post by isak grozny »

So, moving the namebox to be closer to the character speaking is easy–all I've got to do is append a (namebox_xpos=0.3) or something to the dialogue block.

What I'm having a problem with is making the namebox slide smoothly from one position to the next (using a slide transition or a transform) when the speaker changes. I cannot for the life of me figure out how. Am I missing something obvious?

philat
Eileen-Class Veteran
Posts: 1909
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Smoothly moving the namebox

#2 Post by philat »

isak grozny wrote: Tue Jun 04, 2019 8:13 amAm I missing something obvious?
AFAIK, not really. There is no built-in method of checking whether the speaker has changed (unless it's been added recently and nobody told me). Rolling one yourself generally involves character callbacks, which you may or may not be willing to do. Then the issue of applying a transform to the namebox properly also requires some tinkering. It seemed like an interesting idea and I was bored at work, so I came up with the following. As always, disclaimer that there could be better ways, I guess.

Code: Select all

init python:
    def speaker_callback(name, event, **kwargs):
        if event == "begin":
            store.speaker_changed = not (last_speaker == name)
        elif event == "end":
            store.last_speaker = name
            store.prev_xpos = store.curr_xpos

    speaker = renpy.curry(speaker_callback)

    def change_namebox(xpos):
        global prev_xpos, curr_xpos
        prev_xpos = curr_xpos
        curr_xpos = xpos

## testing characters
define e = Character("Eileen", callback=speaker("Eileen"))
define a = Character("Anne", callback=speaker("Anne"))
define b = Character("Beth", callback=speaker("Beth"))
define narrator = Character(None, callback=speaker(None))

## variables used to check whether speaker has changed
default speaker_changed = False
default last_speaker = None

## variables and transform used for the namebox's position
default prev_xpos = 0.2
default curr_xpos = 0.2

transform slide_namebox(prev_xpos, curr_xpos):
    xpos prev_xpos
    linear 0.2 xpos curr_xpos

## vanilla say screen with only the four lines below added
screen say(who, what):
    style_prefix "say"

    window:
        id "window"

        if who is not None:

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

                ## change made
                if speaker_changed:
                    at slide_namebox(prev_xpos, curr_xpos)
                else:
                    xpos curr_xpos

        text what id "what"

    ## If there's a side image, display it above the text. Do not display on the
    ## phone variant - there's no room.
    if not renpy.variant("small"):
        add SideImage() xalign 0.0 yalign 1.0

label start:
    "Testing0"
    e "Testing"
    $ change_namebox(0.3)
    a "Testing2"
    a "Testing3"
    "Testing4"
    a "Testing5"
    $ change_namebox(0.5)
    b "Testing6"
    b "Testing7"
    $ change_namebox(0.2)
    e "Testing8"
    b "Testing9"
    "Testing"
    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: Smoothly moving the namebox

#3 Post by Remix »

philat wrote: Wed Jun 05, 2019 5:59 amThere is no built-in method of checking whether the speaker has changed (unless it's been added recently and nobody told me).
The newish one is

Code: Select all

renpy.get_say_image_tag()
which (as the name suggests) returns the Character("Eileen", image="eileen") image attribute of the speaking character, which can then be used to find the position of said character on the screen.

Tom posted a Patreon topic that uses it quite cleverly:
https://patreon.renpy.org/speech-bubbles.html

Character callbacks (as you posted) are also a good option.
Frameworks & Scriptlets:

philat
Eileen-Class Veteran
Posts: 1909
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Smoothly moving the namebox

#4 Post by philat »

Yeah but that only returns who's speaking, not whether the speaker has changed, which is what's required to make sure the transform only fires when the speaker has changed. You could combine that with callbacks though to do interesting things though. I did consider using get_say_image_tag to get the xpos of the speaking character before deciding that requires too many assumptions about how the images are set up ;)

I do think that this is a quality of life thing that could be added to the engine because people ask about making the namebox flash, dissolve, etc. when there's a new speaker often enough. Relatively low priority maybe.

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: Smoothly moving the namebox

#5 Post by Remix »

If the transform has a base xpos before the warper movement it doesn't mind if the transform fires again on the same character...

Code: Select all

init python:

    def calculate_namebox_xpos():

        global namebox_xpos, namebox_xpos_old

        namebox_xpos_old = namebox_xpos

        tag = renpy.get_say_image_tag()

        # If it's not found, ignore. Set namebox off screen
        if tag is None:
            namebox_xpos = -1200
            return

        # Figure out the image bounds.
        bounds = renpy.get_image_bounds(tag)

        # If it's not being shown, ignore. Set namebox off screen
        if bounds is None:
            namebox_xpos = -1200
            return

        # The xpos of the center of the namebox is the xpos of the sprite
        # plus half its width. (It needs to be rounded to an integer so
        # Ren'Py won't interpret it as a fraction of the screen.)
        x, y, w, h = bounds
        namebox_xpos = int(x + w / 2)



define a = Character("Amber", image="amber", screen="say2")
define e = Character("Eileen", image="eileen", screen="say2")

image amber = Solid("#FFA244", xysize=(120, 360))
image eileen = Solid("#DF42DB", xysize=(120, 360))

default namebox_xpos = 100
default namebox_xpos_old = 100

transform namebox_slider:
    xpos namebox_xpos_old
    parallel:
        easein_elastic 1.0 xpos namebox_xpos
    parallel:
        easein_cubic 0.4 yoffset -15
        easein_elastic 0.6 yoffset 0

screen say2(who, what):

    style_prefix "say"

    window:
        id "window"

        if who is not None:

            window at namebox_slider:
                xanchor 0.5
                id "namebox"
                style "namebox"
                text who id "who"

        text what id "what"

    on "show":

        action Function( calculate_namebox_xpos )


    ## If there's a side image, display it above the text. Do not display on the
    ## phone variant - there's no room.
    if not renpy.variant("small"):
        add SideImage() xalign 0.0 yalign 1.0

label start:

    show eileen with moveinleft
    show amber:
        anchor (0.5, 1.0)
        pos (0.8, 1.0)

    e "My line"

    a "Mine now"

    a "...and again"

    "I have no name"

    e "Phooey!"

    # This ends the game.

    return
Edit:
Changed to use placeholder Solids as sprites, added a yoffset to the transform and changed to elastic based warpers
Last edited by Remix on Thu Jun 06, 2019 10:57 am, edited 2 times in total.
Frameworks & Scriptlets:

philat
Eileen-Class Veteran
Posts: 1909
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Smoothly moving the namebox

#6 Post by philat »

True if the effect is for moving the box only -- I admittedly had started with a mind toward dissolves, brightness changes, etc. Anyhow, kudos on doing the say_image_tag code which I was too lazy to implement!

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: Smoothly moving the namebox

#7 Post by Remix »

philat wrote: Wed Jun 05, 2019 8:08 ampeople ask about making the namebox flash, dissolve, etc. when there's a new speaker often enough. Relatively low priority maybe.
Yup, lol. Most of them ask that the character flash or jump upwards briefly (or basically do whatever DDLC did by coding it in manually on each line) when they speak. Personally I've found that easiest by using a DynamicDisplayable that alters its image based on a conditional using one of these approaches (or speaking_attribute if set).
Frameworks & Scriptlets:

User avatar
isak grozny
Regular
Posts: 46
Joined: Mon Apr 11, 2016 10:17 am
Projects: The Bitter Drop [Modern Fantasy][Gay Romance][BxB]
itch: grrozny
Location: Edinburgh, UK
Contact:

Re: Smoothly moving the namebox

#8 Post by isak grozny »

Damn, turns out I never went back here and said thank you! This does exactly what I need it to do, and I've rewritten the say function so there's a short pause before the text starts, to give the namebox time to move.

Post Reply

Who is online

Users browsing this forum: henne