Ren'Py Help with "porting" pygame to renpy

RodneyLong

New Member
Nov 22, 2021
5
2
TLDR: Is there a tutorial out there explaining step by step, the process to port existing pygame code to work within renpy? Specifically dealing with game loops, blits, collisions...

I have a VN game idea that I want to pursue. I have a lot of the storyline fleshed out, some visual assets/characters, etc... My intention is to have the VN include a lot of different mini games that draw the player in to have a more interactive experience. Prior to getting too far down the road with regards to building out the VN within Renpy, I thought I'd better confirm that I'm capable of pulling off the mini games portion.

I was under the impression that if I were to learn Pygame, I could fairly easily integrate this into the renpy engine. So... I set out to learn Pygame and was able to put together a few simple games I created thru tutorials/training, and then gained enough confidence to build a custom card game that I want in my VN. This is where I'm at... I was very naïve to think that it would be as simple as "calling" my pygame script to run within renpy. Obviously this doesn't work and from what I can tell, building the game in pygame was a waste of time and it needs a near full redesign to work within renpy. :(

I've spent a few days now spinning my wheels looking thru different forums, asking questions in discord, etc... and I have yet to have that light bulb moment needed to pull this all together in my head. I've reviewed links to user defined displayables, there is the pong example in the tutorial, and I've looked at some code to some popular VN's here. Although I'm fairly comfortable with how to structure the game loop, manipulate the screen, blit images, and deal with collisions within pygame, I am in over my head with how this works with renpy.

Ideally, I'd like to find someone who could explain it or point me to a tutorial that helps me bridge this gap. I'm not looking for someone to port my code for me, although that might be a good way to learn it I suppose. And if I'm too dense to pick this up, then maybe outsourcing this to a dev will be my only option. Anyways, I haven't found a tutorial yet that has taken existing pygame code and shown a step by step regarding how to get it to work within renpy. I guess that's really what I'm after.

I know there are quite capable devs here as I've enjoyed some of their work, I'm sure. But also, the questions that get answered here seem very detailed and on point. I'm trying my luck as a first time poster, long time lurker. Thanks in advance for any guidance given.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
I was under the impression that if I were to learn Pygame, I could fairly easily integrate this into the renpy engine.
What is a half false impression. Ren'Py being built on top of PyGame, technically you can use PyGame in your game, but practically it's easier to use Ren'Py, relying on PyGame only for very specific parts that aren't already available.
Due to Ren'Py nature, the only part of PyGame that are really useful is the image/data manipulation. Yet you only need it for very particular cases.

Side note: Ren'Py don't effectively use PyGame, but a (big) subset of it, that haven't really be updated since a long time. So there's things that you'll not be able to use anyway.


[...] to build a custom card game that I want in my VN.
What can, relatively speaking, be easily done with Ren'Py. You've grid to place the card, imagebutton to display them, and its action property for when the player click on it. In fact, for a card game, using Ren'Py will be way easier than using PyGame, because you'll not have to care about all the visual and input part.


[...] building the game in pygame was a waste of time [...]
No, you acquired a new knowledge and a new logical approach. It will never be wasted, even if you don't notice it.


Although I'm fairly comfortable with how to structure the game loop, manipulate the screen, blit images, and deal with collisions within pygame, I am in over my head with how this works with renpy.
Hmm, just read Ren'Py documentation ?
I mean, add and imagebutton clearly do what you expect from blit. action and alternate button properties what you expect from collisions. And for advanced use of both (a spider-like game by example), there's drag.


Anyways, I haven't found a tutorial yet that has taken existing pygame code and shown a step by step regarding how to get it to work within renpy. I guess that's really what I'm after.
You're not finding it, because there isn't such thing. It's like searching for a tutorial explaining you how to cook a steak when the only thing you have is chicken.
It's not because they both are API and both usable with the same language, that they are interchangeable or that it's possible to build a corresponding chart between each element of the API.

What you need to do, is to forget about the code itself. It's not it that you've to port to Ren'Py, it's your high level algorithm.
You need to display the card in a certain way, learn how to display images in a certain way in Ren'Py. You need to react in a given way when the player click on a card, learn how to make Ren'Py react to clicks. And so on.
 

RodneyLong

New Member
Nov 22, 2021
5
2
Thanks for the feedback. I just recently found an example of "Cardgame" on the renpy site ( ) that has been helpful in terms of gaining more understanding. I imagine this is what you may have referred to with the spider game and drag.

As you mentioned, the card game probably won't be the most difficult thing to port to renpy since I'll probably be able to do that with imagebuttons, etc... and there really are no collisions to worry about outside of clicking the image.

I think my best next step will be to test that theory and try porting the card game to renpy on my own (maybe ask for help here if needed :)). If I'm successful, that should hopefully give me some confidence and experience to try tackling something more difficult. One of the more complex things I can think of for collision detection would be a space invaders game. I'll make it first in pygame and then see how out of my element I am when it comes time to port that to renpy. By then, I'll hope to be able to ask better questions where needed and have real examples.

I figure if I can make a space invaders game work then I should be in pretty good shape with any other ideas I have.

Thanks again!
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
I figure if I can make a space invaders game work then I should be in pretty good shape with any other ideas I have.
Well, it would be a bit more complicated, but not impossible.

It would need three classes, one to represent the enemy, one for the shoot, and one for the player sprite. Then the screen would more or less looks like that:
[Note: It's 3AM here, and I wrote it on the fly, so it's really a raw draft and I can make errors]
Python:
screen spaceInvaders():

    # Make everything move every 1/10th second
    timer 0.1 repeat True action Function( advance )

    # User interface
    # Add a shoot / Note: "AddToSet" also works with list
    key "K_SPACE" action AddToSet( Shoot( player.x, player.y - 20 )
    # Move left
    key "K_LEFT" action If( player.x > 0, SetField( player, "x", player.x - 1 ), NullAction() )
    # Move right
    key "K_RIGHT" action If( player.x < config.screen_width, SetField( player, "x", player.x + 1 ), NullAction() )

    # Proceed all the enemies
    for o in allEnemies:
        # Display the sprite at its expected position
        add expression o.sprite pos( o.x, o.y )

    # Proceed all the shoots
    for o in allShoots:
        # Display the sprite at its expected position
        add expression o.sprite pos( o.x, o.y )

   # And finally the player
   add expression player.sprite pos( player.x, player.y )
Then you have the "advance" function, where you'll:
  • browse all the sprites to make them move the way you want.
  • Browse all the shoots to make them move the way you want.
  • Handle the collision between the two ; it would be the hardest part, but it's not too difficult.

As I implied above, compared to the code that would be needed with PyGame, it's really easier to do it with Ren'Py. You just need to define the screen correctly, then you just need a function to change the positions and handle the collisions. Everything else will be handled directly by Ren'Py.

For the collisions, it's probably even possible to let Ren'Py directly deal with them. Using drag instead of add should permit to automatically trigger a function when a enemy and a shoot collide. And it should be possible to even just rely on screen actions ; probably RemoveFromSet to remove both the enemy and shoot, and a SetVariableValue to increase the score.
 

lobotomist

Active Member
Sep 4, 2017
834
746
i see you usually preefer image buttons over sprite managers, but how would you add animations to your buttons,specially if i have something with more animations.
Also wouldn't having so many buttons cause lag?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
i see you usually preefer image buttons over sprite managers, but how would you add animations to your buttons,specially if i have something with more animations.
imagebutton expect either the path to an image, or a displayable. And movies can be a displayable:
Python:
image myButton = Movie( play="movies/myButton.webm" )

screen whatever():
    imagebutton:
        idle "myButton"
        action [...]
ATL animations also are a displayable, therefore they can also works:
Python:
image myButton:
    "frame1.png"
    pause 0.1
    "frame2.png"
    pause 0.1
    repeat

screen whatever():
    imagebutton:
        idle "myButton"
        action [...]
And as last resort, you can still build the button yourself:
/!\ WARNING, wrote on the fly /!\
Python:
screen whatever():

    button:
        action [...]
        add expression "movies/myButton.webm"

Also wouldn't having so many buttons cause lag?
Yes and no.

The game can slow down when there's too many buttons, but it's not because of the buttons themselves. It's their hovered (and potentially tooltip, I'm not sure) property that cause it.
With the previous version of my variable viewer, I encountered slowdown when I had more than 400 entries, so 800 buttons defined. I solved it by adding a security that made the viewer use the hovered property only when there's less than 400 entries. And it was enough to totally get rid of the slowdown, while still having the same number of buttons defined.
The new version is built differently, but globally it can goes up to ~200 buttons displayed on the screen, with ~10% having a hovered property, this without slowdown. It's the processing when you scroll through a big list of entries that can slow down Ren'Py. Yet it happen because vpgrid have an optimization issue ; past a certain time, it would be better to rely on a dichotomous search to find the first entry to display, but it would complicate the algorithm.

So, globally you're safe. There's more risk that your screens are slowed down because there's too much embedded python inside them, than because there's too many buttons.
 
  • Like
Reactions: lobotomist

Greslux

Member
Apr 24, 2022
243
335
" building the game in pygame was a waste of time "

Recently, I was thinking about connecting paygame and renp, as a question - will it be possible to embed something from paygame into renp. Then I realized that the whole problem would be that it would not be possible to import the paygame as it is usually done. import pygame as pg I began to learn Pygame to practice python, however, I soon came to the same opinion as you, that this was a waste of time. Paygame is very limited in terms of possibilities. Despite the fact that quite complex projects are being made at Pygame, they still won’t be able to bring anything interesting in the future. Sooner or later, the developer will run into the limitations of the paygame. I made a snake, I made one game from a Python book (aliens and a spaceship), and when I wanted to make something of my own, I realized that I needed to forget paygame. I haven't seen any guides on your question and I'm 99% sure there aren't any. But I don't think porting the code will be that hard. I have now opened my old projects and most of the code is ordinary python, that is, most of the code of algorithms and classes is written in python. Many things can be omitted from the code and forgotten about, like creating a frame counter, updating the screen, all those back-end get_rect(), init(), clock(), update(), fill() and so on. Because Renp does a lot for us. If you have a universal algorithm / function / class description, then this code will be universal if you get rid of the paygame syntax.
 
  • Like
Reactions: RodneyLong

RodneyLong

New Member
Nov 22, 2021
5
2
anne O'nymous thx for responding and giving me the confidence to keep learning. So far, I have my mini card game "ported" and working within renpy now. I did not have to use UDD, but I do think I have a much better understanding of that now as well. I have done some off hand testing with it and I'm learning.

I did run into one issue with the card game that I couldn't work my way thru. It's a cosmetic issue, not functional, but it would be great to learn of a solution to it.

In my game, any player can throw a specific card to clear the discard pile and then that player can go again, essentially getting back to back turns. The way I have the code, when an imagebutton is selected for a player, that player takes their turn. If that player plays the "clearing card", I am putting the played card into the discard pile and then I clear the discard pile right after that. Since all this happens in the same function, I'm not able to blit the clearing card to the pile and pause 1/2 a second prior to clearing the pile. Since it happens so fast that you can't see the intermediate step of showing the played card in the discard pile, it looks to the player like the pile magically cleared without any indication as to why. I've tried adding pauses via time.sleeps, but I don't think there is any chance to redraw the screen while in that function. I've even tried to split some steps in different functions and call the functions back to back on the imagebutton, but no luck with that.

The short of it is, I'm looking for a way to blit/show/update the screen while in the middle of a function or even as a separate function call. Possible?

Thanks!
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
anne O'nymous thx for responding and giving me the confidence to keep learning.
You're welcome.


The short of it is, I'm looking for a way to blit/show/update the screen while in the middle of a function or even as a separate function call. Possible?
Not really, the screens are updated automatically and there's not function to force their refresh.

But an image button can have more than one action, you just have to use a list as value for the action property. Therefore, perhaps that if you split your code in more than one function, Ren'Py will update the screen in between ; but I'm not sure.
Python:
screen whatever():
    imagebutton:
        idle "idle.jpg"
        action [ Function( whatever ), Function( renpy.pause, 0.5), Function( whateverElse ) ]
/!\ I'm not sure that the pause will works, I never tested it /!\


Else, in last resort, showing a screen force Ren'Py to refresh it, since it will display it. But it's really in last resort, because it come with many cons. Showing the screen mean that Ren'Py will reset it, so if you use screen variables (default myVar = "blabla"), viewport, and few other things, it will break your screen.
Python:
screen whatever():
    imagebutton:
        idle "idle.jpg"
        action [ Function( whatever ), Hide( "whatever" ), Show( "whatever" ), Function( whateverElse ) ]
 

RodneyLong

New Member
Nov 22, 2021
5
2
I was able to get it to work after some trial and error. For what it's worth, here is what I did...

imagebutton:
action [do_something, ui.callsinnewcontext("new_label"), do_something_else]

new_label:
show screen new_screen
if thing == this
pause .35

new_screen:
<copied everything I had in my original screen here (removed actions from all buttons)>
 

gojira667

Member
Sep 9, 2019
272
255
How about using timer 0.5 action [Function( whateverElse )]? Gate it behind a discardClear var that you set when discarding that specific card.
 

Greslux

Member
Apr 24, 2022
243
335
I stumbled across this thread today and immediately remembered this question. Maybe this can help you