Ren'Py How to make the game use the small variant instead of medium on Tablets?

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
Hello guys!
I'm lost in a question that I can't find the answer at all, so maybe you who are more experienced in renpy can help me.

I'm adapting my game for mobiles (smartphones and tablets) and, as we know, renpy automatically makes smartphones use the small variant as the screen layout and the tablets use the medium variant as the screen layout.

The problem is: the range of players using tablets is very small and I don't want to create several different screens for small and medium variants.
What I really want is that the Tablets use the small variant also, being interpreted as any smartphone by renpy, since, in this way, I would only need to create the designs for the small variant and the tablets would be included in that.

Is it possible to force a specific variant to be used on all devices, no matter what?
Since I'm creating the Android version separated from the PC version, if it always be interpreted as small variant, that would solve the problem completely.

Thanks in advance for all the help! ^^
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
One thing to keep in mind is that RenPy doesn't just set a single variant when it runs. A game running on an iPhone for example, may be flagged as small phone touch ios. And yes, you can check for small, but you also check for touch.

Honestly, in my mind, you are better sticking with small, medium and large. But then I'm a simple soul.

You could check for android instead, or touch or perhaps simply not pc. ("not pc" might be wishful thinking on my part")

The full list is available here:

Just keep in mind, the lists overlap depending on the device.

Some other things to keep in mind...

When you define a screen, it can have a . If you omit it - that screen becomes the default screen with that name. But you can specify another screen with the same name, but specify variant. If the device matches the variant definition, then the alternative screen will be used, otherwise it will fall back to using the default.

In your case, you could search the source code for "variant" and change anywhere that mentions "small" to "android". That's probably a bad idea, but I just want to point out the possibility.

Better though would be to specify multiple variants.
If you (I hadn't until just now), it states:
variant [...] this should be a string or list of strings giving the variant of screen to be defined.

I'll highlight "list of strings"...

So something like this will probably work:

Python:
screen hello_world():

     text "Hello, World." size 22


screen hello_world():
     variant ["small", "medium"]

     text "Hello, World." size 30

I haven't actually tried it. So it could be variant "small", "medium" without the brackets or possibly even without the comma. The brackets denote a in python/RenPy. I'd suggest just trying it until you find a version that works.

Beyond that, there are the other places within the code that check the variant choice.
For example, the gui.rpy file has a check for if renpy.variant("small"): to set a completely different set of text sizes for small screens. You could change that to if renpy.variant("small") or renpy.variant("medium"): or if not renpy.variant("large"): for example.

Basically, just search your code for "variant" and tweak it how you like.

Just remember to always have a screen WITHOUT a variant parameter to be the default (usually full sized) screen. I've seen people change the default screen to variant "large" in order to add a variant "small", only to wonder why their games crash on tablets.

Keep in mind too why the RenPy developers only had overrides for variant "small", despite their physical size - most tablets have screen resolutions that are easily comparable to a PC screen. The difficulties usually lie in "thick fingers" and not actually reading text on the screen. I'm merely suggesting that you may be overthinking it.

Since I'm creating the Android version separated from the PC version, if it always be interpreted as small variant, that would solve the problem completely.

PLEASE say you aren't writing two entirely separate projects. The abilities to create multiple screen definitions based on the variant and check which variant is active are why it's possible to have one single game appear differently on different devices without resorting to writing multiple versions of the same game. I can understand why you might have ended up doing it way, but please... one project, with multiple screens occasionally and some rare if ... variant... is the way to go.
 
Last edited:
  • Like
Reactions: Mastur Bar

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
One thing to keep in mind is that RenPy doesn't just set a single variant when it runs. A game running on an iPhone for example, may be flagged as small phone touch ios. And yes, you can check for small, but you also check for touch.

Honestly, in my mind, you are better sticking with small, medium and large. But then I'm a simple soul.

You could check for android instead, or touch or perhaps simply not pc. ("not pc" might be wishful thinking on my part")

The full list is available here:

Just keep in mind, the lists overlap depending on the device.

Some other things to keep in mind...

When you define a screen, it can have a . If you omit it - that screen becomes the default screen with that name. But you can specify another screen with the same name, but specify variant. If the device matches the variant definition, then the alternative screen will be used, otherwise it will fall back to using the default.

In your case, you could search the source code for "variant" and change anywhere that mentions "small" to "android". That's probably a bad idea, but I just want to point out the possibility.

Better though would be to specify multiple variants.
If you (I hadn't until just now), it states:
variant [...] this should be a string or list of strings giving the variant of screen to be defined.

I'll highlight "list of strings"...

So something like this will probably work:

Python:
screen hello_world():

     text "Hello, World." size 22


screen hello_world():
     variant ["small", "medium"]

     text "Hello, World." size 30

I haven't actually tried it. So it could be variant "small", "medium" without the brackets or possibly even without the comma. The brackets denote a in python/RenPy. I'd suggest just trying it until you find a version that works.

Beyond that, there are the other places within the code that check the variant choice.
For example, the gui.rpy file has a check for if renpy.variant("small"): to set a completely different set of text sizes for small screens. You could change that to if renpy.variant("small") or renpy.variant("medium"): or if not renpy.variant("large"): for example.

Basically, just search your code for "variant" and tweak it how you like.

Just remember to always have a screen WITHOUT a variant parameter to be the default (usually full sized) screen. I've seen people change the default screen to variant "large" in order to add a variant "small", only to wonder why their games crash on tablets.

Keep in mind too why the RenPy developers only had overrides for variant "small", despite their physical size - most tablets have screen resolutions that are easily comparable to a PC screen. The difficulties usually lie in "thick fingers" and not actually reading text on the screen. I'm merely suggesting that you may be overthinking it.




PLEASE say you aren't writing two entirely separate projects. The abilities to create multiple screen definitions based on the variant and check which variant is active are why it's possible to have one single game appear differently on different devices without resorting to writing multiple versions of the same game. I can understand why you might have ended up doing it way, but please... one project, with multiple screens occasionally and some rare if ... variant... is the way to go.
I had already looked at some of these things you suggested, but it still wasn't what I intended to do.
I've come to the conclusion that what I wanted to do is probably not possible.


So something like this will probably work:

Python:
screen hello_world():

text "Hello, World." size 22


screen hello_world():
variant ["small", "medium"]

text "Hello, World." size 30
But you gave me a cool idea, I decided to create an alternative version of the screen for the medium variant and I managed to solve the problem.
The bad side is that this thing of creating variants of the screen will give me more work in the future if I want the thing to be done well, but it seems that is the way.


PLEASE say you aren't writing two entirely separate projects. The abilities to create multiple screen definitions based on the variant and check which variant is active are why it's possible to have one single game appear differently on different devices without resorting to writing multiple versions of the same game. I can understand why you might have ended up doing it way, but please... one project, with multiple screens occasionally and some rare if ... variant... is the way to go.
To be honest, I had to create 3 different versions of the same game: PC, Android and Web.

The reason is that when trying to use 1080p images and videos on older android devices, I was experiencing a lot of lag, so I had to turn all assets to 540p to make it run smoothly on these hardware limited devices.

The same goes for the Web version: You can't make the game too heavy, otherwise there will be problems running the game in the browser.

There's no way around it, making the game well done usually takes the hardest path.

Thanks for the help, buddy! ^^
Your ideas shed some light on how to solve the problem.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
Just keep in mind, the lists overlap depending on the device.
Here's the variants tree:

  • "android"
    • Android phone
    • Android tablet
    • Android tv
    • chromeOS
  • "mobile"
    • Android phone
    • iOS phone
    • Android tablet
    • iOS tablet
    • Android tv
    • Web on mobile
    • chromeOS
  • "touch"
    • Android phone
    • iOS phone
    • Android tablet
    • iOS tablet
    • chromeOS
    • Web on mobile
  • "small"
    • Android phone with diag < 6 inches
    • guessed as iPhone by Ren'Py
    • Android tablet with diag < 6 inches
    • chromeOS with diag < 6 inches
    • Android tv
    • Web on mobile with width or height < 768
  • "medium"
    • Android phone with diag >= 6 inches
    • Android tablet with diag >= 6 inches
    • guessed as iPad by Ren'Py
    • chromeOS with diag >= 6 inches
    • Android tv
    • Web on mobile with width and height >= 768
  • "tablet"
    • Android phone with diag >= 6 inches
    • Android tablet with diag >= 6 inches
    • guessed as iPad by Ren'Py
    • chromeOS with diag >= 6 inches
    • Android tv
    • Web on mobile with width and height >= 768
  • "phone"
    • Android phone with diag < 6 inches
    • guessed as iPhone by Ren'Py
    • Android tablet with diag < 6 inches
    • chromeOS with diag < 6 inches
    • Android tv
    • Web on mobile with width or height < 768
  • "large"
    • Linux
    • MacOS
    • Windows
    • Web not on mobile
  • "pc"
    • not android
    • not iOS
    • not web
  • "not pc"
    Listed in the doc, but never set. Perhaps used as negative (if not variant == "pc") but the string never appear as an effective string on the code, so I doubt.
  • "ouya"
    Listed in the doc, but never set ; the code only know about the specific icon for the console.


Some other things to keep in mind...
I'll add three:

Firstly, you shouldn't create a variant targeting a device (phone, tablet) or an OS, but targeting a "technical particularity". "touch" screens will need a different interfaces since the key screen statement can not works and you need to offer access to the functionalities through buttons. And "small" screens could also need some tweaking of your screens if your user interface is too wide.

Secondly, you don't need to provide a variant to all your screens. Be smart and rely on use to limit the number of screens having a variant.
By example:
Python:
# Main screen you use in your game
screen myFirstScreen():

    use myUI
    use myInput
    [...]

# Alternate screen you use in your game
screen mySecondScreen():

    use myUI
    use myInput
    [...]

# User Interface displaying various information
# Generic version
screen myUI():
   hbox:
        for name in girlNames:
            text "[name] :"
            text ( "{}".format( getattr( store, name + "_love" ) ) )

# User Interface displaying various information
# small screen variant
screen myUI():
   variant "small"
   hbox:
        for name in girlNames:
            text ( "{}".format( getattr( store, "shortName_" + name ) ) )
            text ( "{}".format( getattr( store, name + "_love" ) ) )

# Additional inputs
# Generic version
screen myInput():
    key "k_a" action Show( "whatever screen" )
    [...]

# Additional inputs
# touch screen variant
screen myUI():
   variant "touch"

   imagebutton:
       idle "whatever image"
       action Show( "whatever screen" )
With this, you cover "small touch", "medium touch", "small web", "everything else" while still having the less possible screens defined.


Thirdly, what screen variant will be used depend on the variants order defined by Ren'Py:
  • small / medium / large
  • tablet / phone
  • touch
  • tv
  • firetv / chromeOS
  • Android / iOS / pc
  • mobile
  • web
The first found will be the one used. So is you're playing on an Android TV, and have both a "small" and a "android" variant, it's the "small" one that will be used. Same for "chromeos" and "android" variants, the last one will be used only for devices that aren't running under chromeOS.



I'll highlight "list of strings"...

So something like this will probably work:
I haven't tested, but the Screen class __init__ method say that it should works:
Code:
        if (variant is None) or isinstance(variant, basestring):
            variant = [ variant ]
 
  • Like
Reactions: Mastur Bar

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
Here's the variants tree:

  • "android"
    • Android phone
    • Android tablet
    • Android tv
    • chromeOS
  • "mobile"
    • Android phone
    • iOS phone
    • Android tablet
    • iOS tablet
    • Android tv
    • Web on mobile
    • chromeOS
  • "touch"
    • Android phone
    • iOS phone
    • Android tablet
    • iOS tablet
    • chromeOS
    • Web on mobile
  • "small"
    • Android phone with diag < 6 inches
    • guessed as iPhone by Ren'Py
    • Android tablet with diag < 6 inches
    • chromeOS with diag < 6 inches
    • Android tv
    • Web on mobile with width or height < 768
  • "medium"
    • Android phone with diag >= 6 inches
    • Android tablet with diag >= 6 inches
    • guessed as iPad by Ren'Py
    • chromeOS with diag >= 6 inches
    • Android tv
    • Web on mobile with width and height >= 768
  • "tablet"
    • Android phone with diag >= 6 inches
    • Android tablet with diag >= 6 inches
    • guessed as iPad by Ren'Py
    • chromeOS with diag >= 6 inches
    • Android tv
    • Web on mobile with width and height >= 768
  • "phone"
    • Android phone with diag < 6 inches
    • guessed as iPhone by Ren'Py
    • Android tablet with diag < 6 inches
    • chromeOS with diag < 6 inches
    • Android tv
    • Web on mobile with width or height < 768
  • "large"
    • Linux
    • MacOS
    • Windows
    • Web not on mobile
  • "pc"
    • not android
    • not iOS
    • not web
  • "not pc"
    Listed in the doc, but never set. Perhaps used as negative (if not variant == "pc") but the string never appear as an effective string on the code, so I doubt.
  • "ouya"
    Listed in the doc, but never set ; the code only know about the specific icon for the console.




I'll add three:

Firstly, you shouldn't create a variant targeting a device (phone, tablet) or an OS, but targeting a "technical particularity". "touch" screens will need a different interfaces since the key screen statement can not works and you need to offer access to the functionalities through buttons. And "small" screens could also need some tweaking of your screens if your user interface is too wide.

Secondly, you don't need to provide a variant to all your screens. Be smart and rely on use to limit the number of screens having a variant.
By example:
Python:
# Main screen you use in your game
screen myFirstScreen():

    use myUI
    use myInput
    [...]

# Alternate screen you use in your game
screen mySecondScreen():

    use myUI
    use myInput
    [...]

# User Interface displaying various information
# Generic version
screen myUI():
   hbox:
        for name in girlNames:
            text "[name] :"
            text ( "{}".format( getattr( store, name + "_love" ) ) )

# User Interface displaying various information
# small screen variant
screen myUI():
   variant "small"
   hbox:
        for name in girlNames:
            text ( "{}".format( getattr( store, "shortName_" + name ) ) )
            text ( "{}".format( getattr( store, name + "_love" ) ) )

# Additional inputs
# Generic version
screen myInput():
    key "k_a" action Show( "whatever screen" )
    [...]

# Additional inputs
# touch screen variant
screen myUI():
   variant "touch"

   imagebutton:
       idle "whatever image"
       action Show( "whatever screen" )
With this, you cover "small touch", "medium touch", "small web", "everything else" while still having the less possible screens defined.


Thirdly, what screen variant will be used depend on the variants order defined by Ren'Py:
  • small / medium / large
  • tablet / phone
  • touch
  • tv
  • firetv / chromeOS
  • Android / iOS / pc
  • mobile
  • web
The first found will be the one used. So is you're playing on an Android TV, and have both a "small" and a "android" variant, it's the "small" one that will be used. Same for "chromeos" and "android" variants, the last one will be used only for devices that aren't running under chromeOS.





I haven't tested, but the Screen class __init__ method say that it should works:
Code:
        if (variant is None) or isinstance(variant, basestring):
            variant = [ variant ]
In the end, I ended up solving the problem by creating alternative screens for the medium variant, following the idea of the colleague above.

What I really wanted to know is: Is it somehow possible for me to edit the default renpy variant definitions?
For example: Tablets use the medium variant by default.
Is there any way, in my project specifically, for Tablets to use the small variant by default?

I searched a lot on the internet about this, but I couldn't find anything.
The impression I got is that this is hard coded on renpy and impossible to change.

Thanks for the help! ^^
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
But you gave me a cool idea, I decided to create an alternative version of the screen for the medium variant and I managed to solve the problem.

Just keep in mind as I detailed in my original post, that you can do it all with 2 screens. One "standard" screen for the PC, Mac, everything that isn't the 2nd screen... then the 2nd screen which is targeted at variant ["small", "medium"].

The bad side is that this thing of creating variants of the screen will give me more work in the future if I want the thing to be done well, but it seems that is the way.

It's certainly how it's designed to work.
But I have difficulty thinking it will be more work than maintaining THREE separate copies of the same game.

The reason is that when trying to use 1080p images and videos on older android devices, I was experiencing a lot of lag, so I had to turn all assets to 540p to make it run smoothly on these hardware limited devices.

It could be you're trying to solve the wrong problem.

Edit: Full screen background images should probably be jpg or webp image files. Some people will deliver the full game as png, but those games tend to be huge as a result. I'm surprised that you're encountering slow-down with images though. RenPy does a pretty good job of looking ahead at what images are likely to be coming up and caching them before they appear on screen.

"Slow/Laggy" video could be the video encoding. h265 for example is very CPU intensive and can become laggy even on semi-modern PCs.

If you're not already aware, mpg, mp4, avi are just names of container standards. Within each file, there can be multiple tracks (audio, video, subtitles, whatever) and those individual tracks have their own standards (called codecs). People often just think all "mp4" files are the same... but they can use lots of different encoding standards... each of which have their own pros and cons.

For Android for example, Google came up with the VP8 and VP9 codecs... and wrapped them in a webm container. VP9 is the newer, better version of VP8. But that "newer, better" usually means smaller files and higher CPU requirements. The end result of which is that certain VP9 files will be slower on older Android devices than VP8.

More generically, mp4 (and mkv) files tend to use h.264 and h.265 encoding. The h.265 files are much smaller, but also use more CPU... LOTS more.

The other factor is data bitrate. You can have a 1280x720 video file with a bitrate of 3MB/s and that file will stream to most people over the internet without lagging. But an identical 720p video with a bitrate of 12MB/s would overwhelm a lot of internet connections.
The same is true for any device playing them, even if playing direct from a hard disk. If a particular device is stuttering, then one option is to reduce the bitrate of the video. The file will ultimately end up smaller, but some of the quality will be lost. Drop the bitrate too much and the video will look like a patchwork of rough squares and blocky circles. The secret is to keep nudging the numbers down a bit until you notice a change in quality... then nudge them back up a bit.

I mention all of that to suggest that you could try re-encoding your 1080p video files to be h.264 video or VP8 and perhaps lower the bitrate (or average bitrate) a little too. As long as the resulting video is okay to your eyes, it should run just fine on even older android devices. Again, primarily so you are writing your game using 1 set of video files... rather than 2 or 3.

A good tool for re-encoding video is . The most recent versions will encode video to WEBP standard using VP8 or VP9. Personally I would still use MP4/h.264 - but that's only because I regard it as a more generic standard and less likely to cause issues on older hardware.

Maybe that's not an issue for you. But in case it is... this explanation might help.

Edit2: As far at the "overthinking things" goes... I would also point out that a lot of developers release their games to Android without jumping through all the hoops you are creating for yourself. You might also want to investigate the Cruncher tool, which lots of developers use to make their PC RenPy game into an Android RenPy game without doing a lot of stuff manually.

Edit3: Something else has just occurred to me... The last time someone was talking about their game running slow was because they only used show to display images and video. show alone can break RenPy games. 99% of the time, developers should using scene, not show. You're probably already using scene, but this edit is if you are one of the unfortunate developers who fell into the trap of not realizing that scene is almost always the right way to display full screen background images.
 
Last edited:
  • Like
Reactions: Mastur Bar

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
It could be you're trying to solve the wrong problem.

"Slow/Laggy" video could be the video encoding. h265 for example is very CPU intensive and can become laggy even on semi-modern PCs.
But in the same time there's decoding chips for h265, what would make them be proceeded faster on a mobile device than on a top level PC relying on its sole CPU ; at least if the said mobile device include the right chip. And there's video decoding chips for almost all modern codecs, but obviously no phone have them all.

The right choice here is to make the video codec match the most used chip, then to turn Ren'Py hardware acceleration on, by putting at True. This should be enough to solve the issue for 80% of the users.
While chromebooks surely have V8/V9 acceleration, I guess that the most used chip is for h264. The codec is still used a lot, and the chips are old enough to not cost much nowadays. Therefore, they are probably the only chip embedded on cheaper devices, while top devices can perfectly afford to have both a h265 and h264 chip.


It's also possible to play with Ren'Py built process to pack different videos depending on the target:
[options.rpy]
Code:
    build.archive( "moviesAlt", "android" )
    build.archive( "movies", "linux mac windows" )

    build.classify( "movies/android/**.mpg", "moviesAlt" )
    build.classify( "movies/pc/**.webm", "movies" )
Then now you just have to make your code declare the video depending of the package present:
[script.rpy]
Code:
init python:
    if renpy.loadable( "moviesAlt.rpa" ):
        movieTarget = "movies/android/"
        movieExt = ".mpg"
    else:
        movieTarget = "movies/pc/"
        movieExt = ".webm"

    renpy.image("movieName1", Movie( play=movieTarget + "movieName1" + movieExt ) )
    [...]
    renpy.image("movieNameN", Movie( play=movieTarget + "movieNameN" + movieExt ) )
    [...]
    renpy.image("movieNameX", Movie( play=movieTarget + "movieNameX" + movieExt ) )
Normally the proceeding order should also permit to have a script.rpy looking like this, instead of the code above.
[script.rpy]
Code:
init python:
    if renpy.loadable( "moviesAlt.rpa" ):
        movieTarget = "movies/android/"
        movieExt = ".mpg"
    else:
        movieTarget = "movies/pc/"
        movieExt = ".webm"

image movieName1 = Movie( play=movieTarget + "movieName1" + movieExt )
[...]
image movieNameN = Movie( play=movieTarget + "movieNameN" + movieExt )
[...]
image movieNameX = Movie( play=movieTarget + "movieNameX" + movieExt )
And I guess (but no guaranty) that image movieName1 = Movie( play="[movieTarget]movieName1[movieExt]" ) would also works.


And finally this would also works with cutscenes:
[script.rpy]
Code:
init python:
    if renpy.loadable( "moviesAlt.rpa" ):
        movieTarget = "movies/android/"
        movieExt = ".mpg"
    else:
        movieTarget = "movies/pc/"
        movieExt = ".webm"

label whatever:
    [...]
    $ renpy.movie_cutscene( movieTarget + "movieName1" + movieExt )

Edit:
Side effect possibly interesting. Since the name of the movie archive depend on the built, you can also make your code vary more easily. Like by example letting the player decide if he want small screens or not:
Code:
label whatever:
    if renpy.loadable( "moviesAlt.rpa" ):
        menu:
           "You are on an android device, do you want to use alternate screens designed for small screens ?"
           "Yes":
               $ smallScreens = True
           "No":
               $ smallScreens = False
    else:
       $ smallScreens = False
[...]
    if smallScreens:
        show screen myScreen_small
    else:
        show screen myScreen
 
  • Like
Reactions: Mastur Bar

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
As a matter of fact, I'm using a really old device.
My thinking is that if I can get the game to run smoothly on a very old mobile, it will work on pretty much all of them.
Out of curiosity, my test mobile is an LG K10 New (2017) model.

Full screen background images should probably be jpg or webp image files. Some people will deliver the full game as png, but those games tend to be huge as a result. I'm surprised that you're encountering slow-down with images though. RenPy does a pretty good job of looking ahead at what images are likely to be coming up and caching them before they appear on screen.
The project images are already in webp format.
A detail: When I say heavy, I mean the impact on the game's performance and not on the overall size, although that is also important.

"Slow/Laggy" video could be the video encoding. h265 for example is very CPU intensive and can become laggy even on semi-modern PCs.

If you're not already aware, mpg, mp4, avi are just names of container standards. Within each file, there can be multiple tracks (audio, video, subtitles, whatever) and those individual tracks have their own standards (called codecs). People often just think all "mp4" files are the same... but they can use lots of different encoding standards... each of which have their own pros and cons.

For Android for example, Google came up with the VP8 and VP9 codecs... and wrapped them in a webm container. VP9 is the newer, better version of VP8. But that "newer, better" usually means smaller files and higher CPU requirements. The end result of which is that certain VP9 files will be slower on older Android devices than VP8.

More generically, mp4 (and mkv) files tend to use h.264 and h.265 encoding. The h.265 files are much smaller, but also use more CPU... LOTS more.

The other factor is data bitrate. You can have a 1280x720 video file with a bitrate of 3MB/s and that file will stream to most people over the internet without lagging. But an identical 720p video with a bitrate of 12MB/s would overwhelm a lot of internet connections.
The same is true for any device playing them, even if playing direct from a hard disk. If a particular device is stuttering, then one option is to reduce the bitrate of the video. The file will ultimately end up smaller, but some of the quality will be lost. Drop the bitrate too much and the video will look like a patchwork of rough squares and blocky circles. The secret is to keep nudging the numbers down a bit until you notice a change in quality... then nudge them back up a bit.

I mention all of that to suggest that you could try re-encoding your 1080p video files to be h.264 video or VP8 and perhaps lower the bitrate (or average bitrate) a little too. As long as the resulting video is okay to your eyes, it should run just fine on even older android devices. Again, primarily so you are writing your game using 1 set of video files... rather than 2 or 3.

A good tool for re-encoding video is . The most recent versions will encode video to WEBP standard using VP8 or VP9. Personally I would still use MP4/h.264 - but that's only because I regard it as a more generic standard and less likely to cause issues on older hardware.

Maybe that's not an issue for you. But in case it is... this explanation might help.
I did some research on this before and ended up opting for the VP9 codec, using MKV as the container, as it seemed the best cost-benefit option in terms of performance versus file size.

Regarding the bitrate, I also had to weigh the quality vs. file size ratio and ended up getting somewhere in between.

As for MP4, I even tried using it in Renpy, but for some reason, it doesn't play the MP4 videos.
Another reason I didn't use it was issues involving copyright.
MKV container is Open Source, while MP4 has some licensing involved.
I know this is unlikely to be a problem, but it's best to avoid it.

As far at the "overthinking things" goes... I would also point out that a lot of developers release their games to Android without jumping through all the hoops you are creating for yourself. You might also want to investigate the Cruncher tool, which lots of developers use to make their PC RenPy game into an Android RenPy game without doing a lot of stuff manually.
Yes, it's always nice to be able to take a "shortcut", but the performance tests I've done have shown that it's better to build an Android version from scratch.

I even opted to recreate the layout and the screen measurements in 540p, that was the only way the game was really smooth.

Of course you have to consider that I'm using a really old mobile as a test device, for the reasons mentioned above.

Something else has just occurred to me... The last time someone was talking about their game running slow was because they only used show to display images and video. show alone can break RenPy games. 99% of the time, developers should using scene, not show. You're probably already using scene, but this edit is if you are one of the unfortunate developers who fell into the trap of not realizing that scene is almost always the right way to display full screen background images.
Yes, this problem happens because if you use the show command and don't use hide then all the images are stacking one on top of the other, which makes a snowball that weighs on performance.
But I'm already using scene too.


I appreciate all the tips (which will also help other people who will read this thread), but the truth is that I already practiced all of them.
The only way to make the game work well on such an old mobile was to cut the resolution by half.
 
  • Like
Reactions: 79flavors

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
The right choice here is to make the video codec match the most used chip, then to turn Ren'Py hardware acceleration on, by putting at True. This should be enough to solve the issue for 80% of the users.
While chromebooks surely have V8/V9 acceleration, I guess that the most used chip is for h264. The codec is still used a lot, and the chips are old enough to not cost much nowadays. Therefore, they are probably the only chip embedded on cheaper devices, while top devices can perfectly afford to have both a h265 and h264 chip.
This is great advice and something I was unaware of.
I'll test it right now to see the performance impact.

Edit: In the documentation it says this can only be used with Fullscreen videos, so I think this might not be useful as I set the videos as "image" as I need to display dialogs along with the videos.

It's also possible to play with Ren'Py built process to pack different videos depending on the target:
[options.rpy]
Code:
build.archive( "moviesAlt", "android" )
build.archive( "movies", "linux mac windows" )

build.classify( "movies/android/**.mpg", "moviesAlt" )
build.classify( "movies/pc/**.webm", "movies" )
Then now you just have to make your code declare the video depending of the package present:
[script.rpy]
Code:
init python:
if renpy.loadable( "moviesAlt.rpa" ):
movieTarget = "movies/android/"
movieExt = ".mpg"
else:
movieTarget = "movies/pc/"
movieExt = ".webm"

renpy.image("movieName1", Movie( play=movieTarget + "movieName1" + movieExt ) )
[...]
renpy.image("movieNameN", Movie( play=movieTarget + "movieNameN" + movieExt ) )
[...]
renpy.image("movieNameX", Movie( play=movieTarget + "movieNameX" + movieExt ) )
Normally the proceeding order should also permit to have a script.rpy looking like this, instead of the code above.
[script.rpy]
Code:
init python:
if renpy.loadable( "moviesAlt.rpa" ):
movieTarget = "movies/android/"
movieExt = ".mpg"
else:
movieTarget = "movies/pc/"
movieExt = ".webm"

image movieName1 = Movie( play=movieTarget + "movieName1" + movieExt )
[...]
image movieNameN = Movie( play=movieTarget + "movieNameN" + movieExt )
[...]
image movieNameX = Movie( play=movieTarget + "movieNameX" + movieExt )
And I guess (but no guaranty) that image movieName1 = Movie( play="[movieTarget]movieName1[movieExt]" ) would also works.


And finally this would also works with cutscenes:
[script.rpy]
Code:
init python:
if renpy.loadable( "moviesAlt.rpa" ):
movieTarget = "movies/android/"
movieExt = ".mpg"
else:
movieTarget = "movies/pc/"
movieExt = ".webm"

label whatever:
[...]
$ renpy.movie_cutscene( movieTarget + "movieName1" + movieExt )

Edit:
Side effect possibly interesting. Since the name of the movie archive depend on the built, you can also make your code vary more easily. Like by example letting the player decide if he want small screens or not:
Code:
label whatever:
if renpy.loadable( "moviesAlt.rpa" ):
menu:
"You are on an android device, do you want to use alternate screens designed for small screens ?"
"Yes":
$ smallScreens = True
"No":
$ smallScreens = False
else:
$ smallScreens = False
[...]
if smallScreens:
show screen myScreen_small
else:
show screen myScreen
Hmm, I don't know...
Isn't it easier to just build an Android specific build?

But thanks for the advice.
I'll do the performance test and post here about the results later. (y)
 

dyho

Newbie
Jan 31, 2020
87
243
renpy if I have in a nv images with resolutions of 1920x1080 and animations in 1280x720 do you know how to make the resolution adjust automatically I ask you since there are some nv it happens like it is DMD in gui.rpy even if it appears 1920x1080 and the resolution of the images is reduced videos on the screen are adjusted automatically