Screen with random words

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
sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Screen with random words

#1 Post by sculpteur »

Alright, so buckle up.

I need a rather specific screen and I'm not sure where to start.

I know that I am capable of doing it, but I also know that it will take me thirty years for a very average and rather wobbly result.

I'm afraid of going in the wrong direction, because with my current knowledge, it will be like building a bike on my own, but with wheels that will end up being square.

Anyway, let me outline the result I would like and maybe some kind soul will point me to the beginning of something I could build on.


THE SCREEN FEATURES

I want to make words appear and then disappear on the screen with a double randomness : as much on the position as on the choice of the word.

Example word list: traitor, liar, cheater, killer, butcher, pervert, crazy, sick, die, punishment, horrible, demon, guilty.
( This aims to simulate a psychedelic delirium of the main character.)
  • The appearance of words in random places on the screen.
  • Several words present on the screen at the same time without making them appear or disappear at the same time.
  • The appearance of words and their disappearance with fadein / fadeout.
  • The choice of the word that appears is random but drawn from a list of possible words beforehand.
  • For each word, a random font size but between a minimum and maximum value.
  • The color to be a variable (the same for all the words) in order to be able to change the global color when I want.



I know this is both simple and complex. Simple, because there is nothing insurmountable or new in these mechanics. Complex, because having all these characteristics coexist at the same time can be wobbly or tedious.

This is why I really need to be properly steered before embarking on chaotic code writing. Thanks!
Last edited by sculpteur on Mon Jun 13, 2022 2:21 pm, edited 2 times in total.
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#2 Post by zmook »

Here's a part of your solution. I have some code I use for floating status messages -- the kind of thing that announces "+1 Health!" in the middle of the screen, and then the text floats up and disappears.

Code: Select all


## total duration of animation
define announcer_rise_time = 6  # in seconds


transform announcer_float(x=0.5, y=0.5, delay=0):
    # animation for the announced text.
    # floats the text to the top of the screen while it fades out.
    # x,y must be floats because the linear compares them to floats and it doesn't
    # work if they don't match.
    align (x,y)
    zoom 0.01 alpha 0
    
    pause delay 
    easein_back 0.15  zoom 1 alpha 1
    
    linear 0.25*announcer_rise_time  yanchor 0.625  ypos (y+0.25*(announcer.yalign_end-y))
    linear 0.75*announcer_rise_time  xalign 0.5+1.1*(x-0.5)  yanchor 1.0  ypos announcer.yalign_end  zoom announcer.zoom_end  alpha 0.


init python:
    def announce(txt):
        display_id = "ann_%d" % hash(txt)

        curtime = time.time() # time since the epoch in seconds, as a float to 6 decimals
        xalign = 0.35 +  0.3*renpy.random.random()
        
        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[store.announcer_float(xalign,yalign_start,delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)
        
        renpy.invoke_in_thread(hide_announce)
        
        return
This is hacked out of some other code -- you'll probably have to fiddle with some styles and things to make it work, but you probably want to change those anyway.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: Screen with random words

#3 Post by sculpteur »

Hey thank you man, it's very promising, but saddly this cover only one of the aspect of the screen feature. Moreover it's the only aspect I'am already familiar with, so this is the part I need the less help lol but the code is still really interesting and I might try to tweak it as well, but for now I really need something clean and efficient to start on !
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#4 Post by zmook »

Gotcha. The announcer code I showed handles the appearance of words in random places; having several words present at once, appearing and disappearing separately; and having words fade in. From that, it sounds like you can figure out fading out, random font sizes, and setting the font color.

So, the remainder of the framework you need is something like this:

Code: Select all

define delirium_words = "traitor liar cheater killer butcher pervert crazy sick die punishment horrible demon guilty".split()


init python:
    def delirium_show_word(words):
        word = renpy.random.choice(words)
        announce(word)
        

screen delirium_screen():

    default delay_seconds = 2.5
    timer delay_seconds repeat True action Function(delirium_show_word, delirium_words)
Make sense?

One limitation in the above is that the words will appear at a fixed time cadence, and continue indefinitely until you hide the screen. If you need something different, probably the best way is to add logic to the delirium_show_word() function.

If you have trouble getting it working, or you think what you end up with is a mess, post your code and I'll be happy to take a look.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: Screen with random words

#5 Post by sculpteur »

Hey thank you for your help. I'm working on it.

I'm currently still decrypting this code but there is a part I really dont understand

Code: Select all

init python:
    def announce(txt):
        display_id = "ann_%d" % hash(txt)

        curtime = time.time() # time since the epoch in seconds, as a float to 6 decimals
        xalign = 0.35 +  0.3*renpy.random.random()

        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[store.announcer_float(xalign,yalign_start,delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)

        renpy.invoke_in_thread(hide_announce)

        return

I understand the meaning and the usefullness of almost every line but due to the fact I'm not really familiar with the Python syntax, it's going to be a pain in the ass for me to modify it and adapt to my needs.


So I'm already having an error.

because time is not define.

This line is giving me an error :

Code: Select all

curtime = time.time() # time since the epoch in seconds, as a float to 6 decimals
This is the error :
File "game/screen_3_complexescreen.rpy", line 757, in announce
curtime = time.time() # time since the epoch in seconds, as a float to 6 decimals
AttributeError: 'float' object has no attribute 'time'

So I've try to add this :
define time = 4.0 but this is not changing anything.
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#6 Post by zmook »

Oh, sorry. Like I said, that was hacked out of code I was using for something else, and 'curtime' is not even needed for the part you're probably interested in. You should delete that line.

If you wanna know what it does, it's the 'time()' function from the standard Python module 'time', which gives the real-world current clock time as a number of seconds since a fixed reference time, the "epoch". To make it work, you need to import the module.

https://www.tutorialspoint.com/python/time_time.htm

Looking over my code again, I have *also* used the 'sleep()' function from 'time', and that *is* important to the code, so you do need to do the import:

Code: Select all

init python:
    import time	# ⬅︎ add this

    def announce(txt):
        display_id = "ann_%d" % hash(txt)

        xalign = 0.35 +  0.3*renpy.random.random()
        delay = 0		# i also forgot to copy the part where I defined these variables
        yalign_start = 0.5
        zorder = 8
        layer = 'screens'

        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[announcer_float(xalign,yalign_start,delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)

        renpy.invoke_in_thread(hide_announce)

        return

# i also forgot to include this earlier
style announce_text is say_label:
    size 48
    outlines [ (absolute(1), "#ccc", 0, 0) ]
 
Last edited by zmook on Sun Jun 19, 2022 9:18 am, edited 2 times in total.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#7 Post by zmook »

sculpteur wrote: Sun Jun 19, 2022 5:03 am I understand the meaning and the usefullness of almost every line but due to the fact I'm not really familiar with the Python syntax, it's going to be a pain in the ass for me to modify it and adapt to my needs.
If you can tell me what else you don't see how to modify, I can show you.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: Screen with random words

#8 Post by sculpteur »

Hello !

Man I do appreciate the effort but your code is very depressing me lol. I got a lot of error with it (probably because I don't understand most of the things I'm doing lol).
I've got an error that I solved (Tab characters are not allowed in Ren'Py scripts.) but I took me consequent time to understand the indentation error that I needed to re-indenting was after the end of the line and not before lol. Anyway, now I get the error :

File "game/screen_3_complexescreen.rpy", line 769, in announce
at_list=[announcer_float(xalign,yalign_start,delay),])
NameError: name 'announcer' is not defined

And saddly I'm not able to fix it myself. I know a variable is not defined but I'm strugguling to much with Python unknown syntaxe to do it successfully and in a logicial way which match the current code.

So I was wondering, in order to avoid being so dependant from you and harass you with all my questions, maybe I should base this screen I need on a more "renpy" oriented solution. With ALT Transfrom, on hide: on show: linear 0, renpy.random, etc in order to be able to modify it myself.

Because right now, you're python code in my game look like this :

Code: Select all

################################################################################
## DELIRIUM WORDS SCREEN
################################################################################

## total duration of animation
define announcer_rise_time = 6  # in seconds
define delirium_words = "traitor liar cheater killer butcher pervert crazy sick die punishment horrible demon guilty".split()
define time = 4.0

transform announcer_float(x=0.5, y=0.5, delay=0):
    # animation for the announced text.
    # floats the text to the top of the screen while it fades out.
    # x,y must be floats because the linear compares them to floats and it doesn't
    # work if they don't match.
    align (x,y)
    zoom 0.01 alpha 0

    pause delay
    easein_back 0.15  zoom 1 alpha 1

    linear 0.25*announcer_rise_time  yanchor 0.625  ypos (y+0.25*(announcer.yalign_end-y))
    linear 0.75*announcer_rise_time  xalign 0.5+1.1*(x-0.5)  yanchor 1.0  ypos announcer.yalign_end  zoom announcer.zoom_end  alpha 0.

init python:
    import time# ⬅︎ add this
    def announce(txt):
        display_id = "ann_%d" % hash(txt)
        xalign = 0.35 +  0.3*renpy.random.random()
        delay = 0# i also forgot to copy the part where I defined these variables
        yalign_start = 0.5
        zorder = 8
        layer = 'screens'

        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[announcer_float(xalign,yalign_start,delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)

        renpy.invoke_in_thread(hide_announce)

        return



# i also forgot to include this earlier
style announce_text is say_label:
    size 48
    outlines [ (absolute(1), "#ccc", 0, 0) ]

init python:
    def delirium_show_word(words):
        word = renpy.random.choice(words)
        announce(word)


screen delirium_words_screen():
    default delay_seconds = 2.5

    timer delay_seconds repeat True action Function(delirium_show_word, delirium_words)


################################################################################
And even though I thought I could work on it on my own, right now I realize that I can't devote so much time to it, partly because it means I might have to learn more about Python coding. I've already wasted too much time and my next update is taking longer than expected... So either I'm going to have to give up this visual effect, because if it's a code that I don't understand it would have to it is already exploitable in the state or that it is at least in simple renpy.
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#9 Post by zmook »

I've taken that code, run it in a test project, and fixed the glitches until it works. The effect is probably too sedate for what you want, though, with words appearing at a steady pace and just drifting slowly to the top of the screen, all the same size and color. Some changes are easy, I think, like setting the announce_text style to use an appropriately psychedelic font. But if you don't see how to alter some part of the effect, just ask.

Code: Select all

################################################################################
## DELIRIUM WORDS SCREEN
################################################################################

## total duration of animation
define announcer_rise_time = 6  # in seconds
define announcer_yalign_end = 0.05
define announcer_zoom_end = 0.85

define delirium_words = "traitor liar cheater killer butcher pervert crazy sick die punishment horrible demon guilty".split()
 


transform announcer_float(x=0.5, y=0.5, delay=0):
    # animation for the announced text.
    # floats the text to the top of the screen while it fades out.
    # x,y must be floats because the linear compares them to floats and it doesn't
    # work if they don't match.
    
    align (x,y)
    zoom 0.01 alpha 0

    pause delay
    # pop in with a bubble effect
    easein_back 0.15  zoom 1 alpha 1

    # for the first quarter of the rise time, drift up linearly the first quarter of the height
    linear 0.25*announcer_rise_time  yanchor 0.625  ypos (y+0.25*(announcer_yalign_end-y))
    # for the remainder of the rise time, continue drifting up while also shrinking slightly and fading out
    linear 0.75*announcer_rise_time  xalign 0.5+1.1*(x-0.5)  yanchor 1.0  ypos announcer_yalign_end  zoom announcer_zoom_end  alpha 0.


init python:
    import time
    
    def announce(txt):
        display_id = "ann_%d" % hash(txt)
        xalign = 0.35 + 0.3*renpy.random.random()
        delay = 0
        yalign_start = 0.5
        zorder = 8
        layer = 'screens'

        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[announcer_float(xalign,yalign_start,delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)

        renpy.invoke_in_thread(hide_announce)

        return


    def delirium_show_word(words):
        word = renpy.random.choice(words)
        announce(word)



style announce_text is say_label:
    size 96
    outlines [ (absolute(1), "#ccc", 0, 0) ]



screen delirium_words_screen():
    default delay_seconds = 2.5

    timer delay_seconds repeat True action Function(delirium_show_word, delirium_words)



label start:

    scene bg room
    show eileen happy
    
    e "wait for it..."
    
    show screen delirium_words_screen
    
    e "delirium starts"
 
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: Screen with random words

#10 Post by sculpteur »

Thank you really much ! This is working great. Not as intended but at least it work !

Too bad there are not more comments on the lines and their functionalities so that I can modify the last modalities myself and stop bothering you lol

In any case, it's already very kind of you what you have done.

But unfortunately there are some points that deserve to be modified so if you have an idea of ​​which lines I should modify do not hesitate.


1) The first problem that jumped out at me is that only one word is displayed on the screen at a time when there should be between 5 and 10. The goal is for the screen to be almost full of words that appear and disappear at irregular rhythms.
For this to be more understandable I made some images which must be imagined as screenshots at a precise moment of the text animation. This is how it's suppose to look :
Image



2) I also noticed that the distribution of words appearing and disappearing is focused on the middle of the screen, in a kind of small centralized square. While text should appear at any x or y of the entire background on its 1920x1080 surface, maybe a little less to avoid player inventory or dialog.
See this pic :
Image


3) Then finally, regarding the bottom-to-top floating text effect : it's not desired. I may have expressed myself badly but at no time I wanted the text supposed to slide up as if it were the displaying of a changing characteristic or a damage number lol (I'm already using a simple floating up effect for characters stat change). The ideal would be to make it slowly drift away from the center of the screen, but if that's too complicated I'd be fine with words that stay put but gradually grow (either by increasing their size or by using a zoom function like in ALT transforms linear 1.0 zoom 0.5 or zoom 1.5, that sort of thing)
Image
Image


If necessary, here are the illustration images in original quality just in case.
https://ibb.co/hV2cTKg
https://ibb.co/9WG1Tk2
https://ibb.co/7pxsK3f
https://ibb.co/BgjvdyM

Allright, so I hope this will help you to understand and allow me to finilize the last modification of this screen because I can't wait to continue the story while being able to rely on this psychadelic effect :D

Thank you very much for the help you have already given me!
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#11 Post by zmook »

Here you go, enjoy.

Code: Select all

################################################################################
## DELIRIUM WORDS SCREEN
################################################################################

## total duration of animation
define announcer_rise_time = 6  # in seconds
define announcer_yalign_end = 0.05
define announcer_zoom_end = 4

define delirium_words = "traitor liar cheater killer butcher pervert crazy sick die punishment horrible demon guilty".split()
 



transform announcer_float(startpos=(0.5, 0.5), endpos=(1.0,1.0), delay=0):
    # animation for the announced text.
    # floats the text to the top of the screen while it fades out.
    # x,y must be floats because the linear compares them to floats and it doesn't
    # work if they don't match.
    
    # starting position for the displayable
    pos startpos
    anchor (0.5, 0.5)
    zoom 0.01 alpha 0

    pause delay
    # make the displayable appear
    easein 0.15  zoom 1 alpha 1

    # drift, zoom and fade
    linear announcer_rise_time: 
        pos endpos
        zoom announcer_zoom_end  
        alpha 0.


init python:
    import time, math
    
    # random number between (-0.5,0.5), for jitter
    def rr2():
        return renpy.random.random() - 0.5
    
    
    # calculates the x end position for the animation, radially away from the center
    # point with a little random jitter
    # you can mess around with this, it doesn't have to be perfect
    def announcer_pos_end(x_start, y_start):
        cp = (0.5 + 0.05*rr2(), 0.5 + 0.05*rr2())   # center point
        
        dx, dy = x_start-cp[0], y_start-cp[1]
        angle = math.atan2(dy, dx) + 0.05 * rr2()
        
        r_end = 0.5 + 0.3 * rr2()           # new radius to move to
        
        x_end = r_end * math.cos(angle) + cp[0]
        y_end = r_end * math.sin(angle) + cp[1]
        
        return (x_end, y_end)
    
    
    def announce(txt):
        display_id = "ann_%d" % hash(txt)
        delay = 0
        zorder = 8
        layer = 'screens'
        # randomize the position where the words appear
        start_x = 0.1 + 0.8*renpy.random.random()
        start_y = 0.1 + 0.8*renpy.random.random()
        endpos = announcer_pos_end(start_x, start_y)
        
        renpy.show(display_id, what=renpy.text.text.Text(txt, style="announce_text"), \
            layer=layer, \
            zorder=zorder, \
            at_list=[announcer_float((start_x, start_y), endpos, delay),])

        def hide_announce():
            time.sleep(announcer_rise_time)
            renpy.hide(display_id)

        renpy.invoke_in_thread(hide_announce)

        return


    def delirium_show_word(words):
        # we're checking frequently but only displaying a new word sometimes,
        # so that we get a randomized interval
        if renpy.random.randint(1,100) < 20:
            word = renpy.random.choice(words)
            announce(word)



style announce_text is say_label:
    size 96
    outlines [ (absolute(1), "#ccc", 0, 0) ]



screen delirium_words_screen():
    # how often do we *check* to maybe display a new word?
    default check_time = 0.1

    timer check_time repeat True action Function(delirium_show_word, delirium_words)

colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

sculpteur
Veteran
Posts: 312
Joined: Fri Nov 17, 2017 6:40 pm
Completed: Apocalypse Lovers
Projects: Apocalypse Lovers
Organization: Awake_Production
Location: France
Discord: https://discord.gg/apocalypse-lovers
Contact:

Re: Screen with random words

#12 Post by sculpteur »

Waw really nice, this is working great !
I've tweaken it a little in order to be more dynamic or slower in fonction of the situation. The render is truly amazing!

Just a question about the way the list of word is define.
Each word is separated by a space, that's which is delimitating them from each other. But what if I want to use small sentences instead of words.
Like this :
define delirium_words = "Traitor Cheater Fucking Liar".split()

For separate them into this :
1 - Traitor
2 - Cheater
3 - Fucking Liar

Or even this :

define delirium_words = "Haven't you done enough? You're going to die!".split()
To display this :
1 - Haven't you done enough?
2 - You're going to die!
Image

“He asked me to calm down, close my eyes and be quiet. He explained to me that if I was afraid, the shadow that ran barefoot in the street would feel it. I got scared seeing Jumanji on TV, so let me tell you, we didn't stay hidden for long and had to start running again.”
Jessica's Diary.

User avatar
zmook
Veteran
Posts: 421
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Screen with random words

#13 Post by zmook »

sculpteur wrote: Sun Jun 26, 2022 3:15 pm Each word is separated by a space, that's which is delimitating them from each other. But what if I want to use small sentences instead of words.
Using a single string and splitting on spaces is just a convenience, because it's easier to type (and to cut and paste from the sample you provided earlier). What we're really doing is just creating a list of "words", and python has lots of valid ways of doing that. You can get more fancy with "split" and tell it to use commas as the splitting delimiter, or you can just do it explicitly:

Code: Select all

define delirium_words = ["Traitor", "Cheater", "Fucking Liar", ]
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

Post Reply

Who is online

Users browsing this forum: Bing [Bot], piinkpuddiin