Showing posts with label renpy. Show all posts
Showing posts with label renpy. Show all posts

Wednesday, 6 September 2017

Using layers in Ren'Py

Sometimes you might want some custom layers in Ren'Py.

There is some information over in the documentation here: https://www.renpy.org/doc/html/displaying_images.html#layer

It explains what the 4 default layers (master, transient, screens and overlay) are for and the order they are in.

To add some additional ones you'll want to add a line of code to the bottom of the options.rpy file, like this:

    config.layers = [ 'zero', 'master', 'transient', 'belowmid', 'midlayer', 'abovemid', 'screens', 'overlay']
 
That gives us another four layers to play with, of course you can have more or less and in any order, just remember to test things to make sure you have the layers in the order you want!

I put a new layer called zero right at the bottom, I typically fill this with a solid colour so that the player never accidentally sees the default transparent background. Then the others that I will use for art / displayables are between transient and screens, you might find it better to have some below transient, just experiment to see what happens where!

Here is a script.rpy file as an example of showing things on custom layers:

image nrblack = "#181818"

image skyani:
    "sky1.png" with Dissolve(1.5, alpha=True)
    pause 1.5
    "sky2.png" with Dissolve(1.5, alpha=True)
    pause 1.5
    "sky3.png" with Dissolve(1.5, alpha=True)
    pause 1.5
    "sky2.png" with Dissolve(1.5, alpha=True)
    pause 1.5
    repeat 20

label start:

    show nrblack onlayer zero

    show skyani onlayer belowmid with dissolve
    centered "A simple animated sky background."
    centered "Followed by some midground."
    show midground onlayer midlayer with dissolve
    centered "Finally the foreground."
    show foreground onlayer abovemid with dissolve

    pause

    centered "Now we should hide all of the relevent layers to get ready for the next scene..."

    hide skyani onlayer belowmid
    hide midground onlayer midlayer
    hide foreground onlayer abovemid with dissolve

    "That's it!"

    return


The main thing to note is the onlayer followed by the custom layer name which you'll need on both the show and hide statements.

The two images that aren't defined (midground and foreground) are files names midground.png and foreground.png which are in the images folder, Ren'Py picks these up automatically so they don't need to be manually defined!

This particular example could more easily be achieved just by using show and letting Ren'Py put them in the order they are declared onto the screen, but if you're reading this you probably have run into some case where the standard behaviour isn't enough for your needs and layers might be useful!

Don't forget to hide the images on the layers when you are done with them! XD

Gif:


As a quick aside you may have noticed that the sky animation is set to repeat 20 times, instead of infinitely (repeat). I have started doing this mainly because I noticed quite a lot of system resources being used when multiple infinite animations are displayed at once (as you can imagine!). I'm still trying to get my head around the best practices for being efficient with animations in terms of system resource, so I can't offer much advice in that area, but with only one animation running at a time you shouldn't have any problems!


Monday, 4 September 2017

Ren'py fade text in and out

As promised here is the Screens version of the fade in out text! I'll leave the below stuff using the (old!) ui.add on this blog post (below the "--- old post below ---") as it goes into a bit more detail with the custom transform!

So, the way I went about this is to create a new rpy file for my custom screen, I called it custom.rpy, but give it any name you'd like!

This is the entire contents of that file:

screen info_fade:

    text "Look. I'm fading about." at fade_inout_2s


Then in the script.rpy I have:

transform fade_inout_2s:
        xalign 0.5
        yalign 0.5
        alpha 0.08
        easeout_back 2 alpha 0.9
        pause 0
        ease 2 alpha 0.0

label start:

    scene bg room
    "Ok, here we go."
    show screen info_fade
    pause 6
    "That was nice."
    pause
    return

The main bits there being the transform which I declared at the very top of the script.rpy file and the show screen info_fade statement.

I used show screen rather than call screen because I think calling a screen then expects some kind of user interaction, which isn't what I wanted for this effect. I've not used this in a game, so depending on what you are trying to achieve you might need to make some changes, feel free to drop me a line on twitter if you are struggling with anything - I'll help if I can! - @sleepyagents

Here is a gif:



btw I use ScreenToGif to make gifs if anyone is interested - http://www.screentogif.com/ - thanks screentogif people!

And a big thanks to xela and Zetsubou for the lemmasoft thread where I found the basis of this stuff! (link below)

--- (old post below) ---

Here is one way you can fade in and out some text in Ren'Py!

I thought I would be able to do this without looking at the lemmasoft forum, but I failed in that :'D

here is the guide I found from xela https://lemmasoft.renai.us/forums/viewtopic.php?p=336645#p336645
(thanks xela!)

I just changed it a bit as I didn't need the text to move.

You might be thinking that this would be a lot easier with an image - and you'd be correct! but that wouldn't be as accessible, though you could add some text to describe the image, I think this way is better for filesize and flexibility (variables!) anyway.

Right at the top of the script.rpy file I have:

init python:
    def fade_inout_text(text, *args, **kwargs):
        ui.add(At(Text(text, *args, **kwargs), fade_inout_2s))
         
transform fade_inout_2s:
        xalign 0.5
        yalign 0.5
        alpha 0.08
        easeout_back 2 alpha 0.9
        pause 0
        ease 2 alpha 0.0


I don't know much about the def and ui.add bits, so I'll explain a bit about the transform instead!

The xalign and yalign make sure that the text is centered, the alpha 0.08 means that the text is just visible before the animation starts (0 would be invisible), easeout_back 2 alpha 0.9 uses the easing ( see https://www.renpy.org/doc/html/atl.html#warpers for the list of available warpers/easings ) called easeout_back which has a certain effect (see gif below!) which takes 2 seconds to change to 90% visibility (alpha 0.9), of course you could use 1.0 instead for 100% visibility.
Then I added a pause of 0 seconds... followed by ease 2 alpha 0.0 which takes 2 seconds to 'ease' the text to 0% visibility / transparent.
Play around with the numbers and the warpers / easings to get the effect you want!

And then when some text needs to fade in and out during the game you can add this:

    $ fade_inout_text("this is the text that fades in and out", color="#111111", size=30)
    pause 6


You can see I added a 6 second pause after the statement to give it time to do it's thing. You could use a normal pause without an amount of time defined to let the player click to continue.

If you want to display a variable you can replace the string, e.g.

    $ fade_inout_text(my_variable, color="#111111", size=30)

I hope this has been helpful!


I just realised the code to do this with screens is in the forum thread I linked! Which is what I originally intended to do! I'll update this post soon with the code for screens which will be a little nicer haha.

Saturday, 17 September 2016

BPM in Ren'Py - Timing animations to your musics tempo


I keep meaning to write this up as a blog post! I'm sure somebody will find it useful, either directly, or make them think about some other possibilities when making VNs!

I decided I wanted to have backgrounds flicker in time with my games music and went about it in quite a long-winded manner. Now I have worked out a better way to achieve this type of effect, so I thought I would share it!



Using your music tempo / BPM in Ren'Py


Say you have some music at 130bpm and it is in a 4/4 time signature, what you want for a timed animation is the amount of time in seconds for 1 beat. Really, once you have a beat you can easily find the length of a bar and of half a beat, etc. with some simple math!

To work this out within Ren'Py you can add:


init -1 python:

    the_bpm = 130 #change the number to your musics bpm

    one_beat = 60 / float(the_bpm)



To the top of your script.rpy file.






Now python has worked out our time in seconds for one beat to be something like 0.4615384615384615 for this example and saved it as a variable called "one_beat". I also went ahead and got some more timings based on that with the following:


    two_beat = one_beat * 2

    three_beat = one_beat * 3



    one_eighth = one_beat / 2

    one_sixteenth = one_beat / 4



    one_bar = one_beat * 4

    two_bar = one_bar * 2

    four_bar = one_bar * 4

    eight_bar = one_bar * 8



Which in my script I placed under the code further up where we declare the BPM and work out the length of one beat.

Now when I create an animation with ATL I can use any of these variables instead of typing in 0.4615384615384615 or whatever! E.g.


image bpm-ani:

    "bpm ex fr1.png" with Dissolve(one_beat, alpha=True)

    pause two_beat

    "bpm ex fr2.png" with Dissolve(one_beat, alpha=True)

    pause two_beat

    "bpm ex fr3.png" with Dissolve(one_beat, alpha=True)

    pause two_beat

    "bpm ex fr4.png" with Dissolve(one_beat, alpha=True)

    pause two_beat

    repeat






Now (for the first time in the history of this blog!) I'll add a video to show what this looks AND SOUNDS like! :D


Ren'py ATL to BPM / tempo animation example from sleepy agents on Vimeo.

Here is a link to view the full rpy script file: http://projects.sleepyagents.co.uk/example-script-for-bpm-tempo-in-renpy/
(note: the indent spaces would actually be 4 spaces, not 1, in the actual rpy file)



But what about different time signatures!? Can I just have what I need in a separate .py file which I can re-use in other projects!?

Oh yeah! LydianChord made this handy tool!
https://alexh.itch.io/music-timing-calculator

Which has the directions for use on the page. It's just a matter of pasting a .py file into your base game folder and adding this into your script:

init python:
    from music_timing_calculator import MusicTimingCalculator
    
    calc = MusicTimingCalculator(tempo=120, beats_per_measure=4, num_measures=16)
    
    # Now you can use calc.one_beat, calc.one_measure, calc.song_length
    # and calc.song_length_min in your code


remembering to change the numbers on this line:

calc = MusicTimingCalculator(tempo=120, beats_per_measure=4, num_measures=16)





So that they are correct for your music. I'm planning on using this tool for future projects!



OK that was quite a long post! Just keep in mind some things in ren'py will already have a default time in seconds attached to them, e.g. dissolve takes 0.5 seconds unless you specify it's time. So you may need to look at how to change those in certain scenarios.

Have fun and let me know if you make anything with this!

^^

@sleepyagents

Sunday, 7 February 2016

Easing / Warpers in Ren'Py

Version 6.99.8 of Ren'Py which was released in December 2015 includes these cool new warpers for making animations look smoother/more natural and/or more interesting!

You can see what sort of effect you get on this site:

http://easings.net/

And here is the Ren'Py documentation:
http://www.renpy.org/doc/html/atl.html#warpers

I thought I'd share a little bit of example code for using the cool new warpers in Ren'Py.

--

Here is my code using the easein_back movement:

I have this in my Script file, with the other images I am declaring:

image onion_ani:
    "onion.png"
    xpos 250
    ypos 750
    easein_back 2.5 xpos 550 ypos 500


And then in the game it's just a matter of showing the image:

    show onion_ani
    pause (4.0)
    hide onion_ani with dissolve


The code after the image declaration shows the image at the location provided by xpos and ypos (in this case 250 and 750) then using the nice easein_back movement it goes to the new xpos and ypos ( the 2.5 you see in my example is the amount of time in seconds this takes and the 550 and 500 are the new positions).

Later after "label start:" (i.e. somewhere in the main script of the game) it's shown with the show statement. In my example I also added a 4 second pause and the hide statement, they aren't needed at all for this, but I've included them just in case it helps anybody out at all.

---

It should have been fairly obvious to me that "easein_back" should go in place of "ease". But... I've never really used "ease" - all my old ATL code uses "linear", which is why I spent a while figuring out how to use these functions! I know I always get on better with code examples than I do with documentation (especially when I'm trying to do something quickly!).

Thanks to nyaatrap on lemmasoft forums for the original post http://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=35749

And of course to renpytom (https://twitter.com/renpytom) for including them and Robert Penner (http://robertpenner.com/easing/) who, like, invented the original code :D

Thursday, 16 April 2015

Ren'Py Multiple Audio Channels or Tracks

I keep meaning to do this post about audio channels in Ren'Py.

It was when I was working on my Nanoreno game, New Pisces, that I realised I would need to dig a bit deeper than just the Music, Sound and Voice channels that are standard in a new Ren'Py project. I wanted to have at least 12 loops of audio playing at the same time.

(This might seem like a lot, but the loops are quite stripped back - not full songs - and the 'gameplay' focuses on the interactive audio.)

After saving my 24+ audio files as mostly wav and ogg depending on the filesize (I tend to convert my wav files to ogg if they are over 1mb in the interest of keeping overall filesize low - I've been using http://media.io/ to convert the files) I started to look at how to get multiple music channels.

The Ren'Py documentation on Audio is here http://www.renpy.org/doc/html/audio.html where I saw:
 "New channels can be registered with renpy.music.register_channel()."

I think I first tried putting that code into the options.rpy file which didn't work and eventually I had a go with it in the script.rpy file - which works just fine! I also added "init python:" which I think I must've discovered on the lemmasoft forums ( http://lemmasoft.renai.us/forums/ ) when searching for solutions. In case it's helpful to anybody here is my code from the very top of my script.rpy file:

# You can place the script of your game in this file.

init python:
    renpy.music.register_channel("one", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("two", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("three", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("four", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("five", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("six", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("seven", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("eight", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("nine", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("ten", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("eleven", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("twelve", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("zero", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
    renpy.music.register_channel("zeroone", mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)

#my variables

define slowdis = Dissolve(2.0, alpha=False, time_warp=None)
define vslowdis = Dissolve(3.0, alpha=False, time_warp=None)
define pixelfast = Pixellate(0.3, 8)


Then to get my file playing on the desired channel I used:
    play one "00.ogg"

I also wanted to change the volume of certain channels at various points of the game, for that I used:
    $ renpy.music.set_volume(volume=0.2, delay=0.8, channel='one')

Here the volume is expressed as a decimal with 1.0 being full volume and 0.0 being silent, I believe this is accurate to more than one decimal place, but didn't do lots of testing to be sure that it doesn't round up or down. The delay property is the amount of time in seconds the change in volume takes, so the fade between the old and new volume.

Hopefully that has been helpful, if you'd like to ask me questions on this (or anything really!) the best way to get in touch is via twitter ( @sleepyagents )

Tuesday, 9 December 2014

Day 9 - Variables in Ren'Py - dice roll d20

The plan is to have some stats which is a more RPG-like thing, and I love the idea of having these decided by a dice roll as with pen and paper games like d&d.

I had to read a little of the Ren'Py documentation:

At the bottom of that page I spotted:
# return a random integer between 1 and 20
$ d20roll = renpy.random.randint(1, 20)
Which is just what I needed. My code now includes:

    $ vitality = renpy.random.randint(1, 20)
    $ skill = renpy.random.randint(1, 20)
    $ luck = renpy.random.randint(1, 20)    
    
    "Your vitality is [vitality]"
    "Your skill is [skill]"
    "Your luck is [luck]"

Which I have tested and that seems to work as desired. When the skill checks come a bit later on in the game I'll need to add some logic, so I'll be consulting the documentation again at that point to make sure I get my syntax correct.

--

Update 18/10/2015:

I should've updated this post a long time ago! So here is how you would do a skill check in Ren'Py, using an example from my (ever) unfinished pizza game:

    $ skill += renpy.random.randint(1, 20)

#The above line takes the variable named skill and adds another random d20 number to it and saves that as the new value for skill
 
    "[skill]"

#Displays that new number to the player

    if skill >= 30:
        jump wall
    else:
        jump walk

#That last bit here is an else/if statement that checks if the skill roll is equal to or above above 30. If it is above 30 then the scene jumps to "wall" or if it's below then the scene will be "walk"

This example is quite specific in that the game only checks against skill once, so I didn't bother saving the additional "skill check" roll as a new variable, but the logic and syntax should be pretty similar.

In fact I just tried a quick tester and it seems to work!

    $ skill = renpy.random.randint(1, 20)
    "Your skill is [skill]"
 
    $ skillRollOne = renpy.random.randint(1, 20)
 
    $ skillRollOne = skill + skillRollOne
 
    "[skillRollOne]"
 
    if skillRollOne >= 30:
        jump wall
    else:
        jump walk

That is similar to the above, only your original skill value isn't overwritten when you do the skill check.

I hope this is helpful to some people out there and yes I am quite a novice at programming, so if any programmers out there read this and notice bad practice please let me know so that I can update the post!