Button "PRESSED" state, I got it working! Or I should say [SOLVED]

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
JessicleCat
Newbie
Posts: 7
Joined: Sun Jan 19, 2020 4:48 am
Contact:

Button "PRESSED" state, I got it working! Or I should say [SOLVED]

#1 Post by JessicleCat » Sun Jan 19, 2020 1:29 pm

I was working on my project, and I discovered that Ren'Py doesn't have a "button_pressed" state, for when the mouse button is down over a button. I want to have nice responsive "tactile" pushy buttons, so I searched and searched but all I could find about it was a post from 2014 where PyTom confirmed that Ren'Py didn't, as of then, support a "pressed" state for buttons. I did a lot more searching and all I found was the "Konami Code", that creates a listener for key presses, and I thought that could be modified to listen for mouse button presses... and after a lot of experimenting and reading documentation for both Ren'Py and Pygame, I got it sort of working!

For a newbie like me that's pretty exciting! :D

Image

Basically, an imagebutton says "I'm being hovered!" as its "hovered" action, and "I'm no longer being hovered!" as its "unhovered" action, and the listener listens for a MOUSEBUTTONDOWN event where someone is also saying "I'm being hovered!" and then overlays the "pressed" version of the button at the button's position, until the MOUSEBUTTONUP event.

Here's the full version (I hope it's okay that I used a background from The Question, for testing purposes):
https://easyupload.io/pegen4 --- UPDATE: This is the new, improved version, described in the next post.
(If you don't want to download the 32mb dist, I'll show the relevant code)

In the script.rpy, I just have:

Code: Select all

show screen button_screen
screens.rpy is where the "magic" happens (such as it is):

Code: Select all

##### UPDATE: Don't even look at my old nonsense code. See the completed, working code in the next post!
What I want to do next is to change it so that I can have multiple buttons in multiple different positions all use the same code. I know vaguely how to do that - like, if "[button_name]_hovering" then show "[button_name]_pressed" at "[button_name]_pos" and just predefine positions for every button I'll be using and keep the names consistent... but I'm not super clear on the syntax or how to do it right without messing anything up. :?

I've been really pushing my limits for a couple of days of working on this, and that's exciting...

But I'd really appreciate some help! :oops:

UPDATE: I got some help from bobcgames and Remix on the Renpy Discord, and now it's doing everything (see below)
Last edited by JessicleCat on Sun Jan 19, 2020 6:35 pm, edited 3 times in total.

User avatar
JessicleCat
Newbie
Posts: 7
Joined: Sun Jan 19, 2020 4:48 am
Contact:

Re: Button "PRESSED" state, I got sort of working

#2 Post by JessicleCat » Sun Jan 19, 2020 5:14 pm

UPDATE:

Here's an updated version of the code in screens.rpy which successfully uses multiple buttons (in this case, two). It seems to work! :D

script.rpy still just uses:

Code: Select all

show screen button_screen
screens.rpy uses the following (or this could be in a separate .rpy file I guess, in this case I put it in screens):

Code: Select all

###############################################################################
# Pressable imagebuttons                                                      #
###############################################################################

#a string containing a button name ("button0" is NOT used for any buttons)
default button_number = "button0"

#define a name for the "_pressed" version of each button, for simplicity they
#should match the button names used by the imagebutton "auto"
image button1_pressed = Image("images/button1_pressed.png")
image button2_pressed = Image("images/button2_pressed.png")

#define a position for each button that will be on the screen
transform button1_pos:
    xalign 0.3
    ypos 550

transform button2_pos:
    xalign 0.7
    ypos 550

# This checks whether the left mouse button has been pressed, then displays
# the "_pressed" version of the button over it at the same position.
# It's based on the Konami Code cookbook entry.
init python hide:

    class ButtonListener(renpy.Displayable):

        def __init__(self):

            renpy.Displayable.__init__(self)

            import pygame

        # This function listens for events.
        def event(self, ev, x, y, st):
            import pygame
            LEFT = 1
            RIGHT = 3

            if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == LEFT:
                #if the left mouse button is down, and we're on a non-zero button:
                if button_number != "button0":
                    renpy.notify("You're holding the button.")
                    renpy.show(store.button_number + "_pressed", at_list=[globals()['{}_pos'.format(button_number)]], zorder=100, layer='screens')
                else:
                    return
            elif ev.type == pygame.MOUSEBUTTONUP and ev.button == LEFT:
                #hide the image when the left mouse button goes back up.
                renpy.hide(store.button_number + "_pressed", layer='screens')
                return
            return

        # Return a small empty render, so we get events.
        def render(self, width, height, st, at):
            return renpy.Render(1, 1)


    # Create a ButtonListener to actually listen for button presses.
    store.button_listener = ButtonListener()

    # This adds button_listener to each interaction.
    def button_overlay():
        ui.add(store.button_listener)

    config.overlay_functions.append(button_overlay)

screen button_screen:
    vbox:
        #doesn't have to be a vbox, but it has to be a container that can use the transform
        at button1_pos
        imagebutton:
            auto "images/button1_%s.png"
            focus_mask True
            action Notify("You clicked the button.")
            alternate Notify("You right-clicked the button.")
            #use the hovered action to set "button_number" to the name of the button
            hovered [Notify("You hovered the button."), SetVariable("button_number", "button1")]
            #use the unhovered action to set "button_number" back to "button0".
            unhovered [Notify("You unhovered the button."), SetVariable("button_number", "button0")]
    vbox:
        at button2_pos
        imagebutton:
            auto "images/button2_%s.png"
            focus_mask True
            action Notify("You clicked the button.")
            alternate Notify("You right-clicked the button.")
            hovered [Notify("You hovered the button."), SetVariable("button_number", "button2")]
            unhovered [Notify("You unhovered the button."), SetVariable("button_number", "button0")]
            
Here's the project, including everything:
https://easyupload.io/pegen4

Here are just the additional buttons:
https://easyupload.io/npribt

It's just a set of buttons with _hover, _idle, _insensitive, _selected_hover, and _selected_idle, like standard imagebutton graphics - plus a _pressed graphic for each.

User avatar
gas
Miko-Class Veteran
Posts: 538
Joined: Mon Jan 26, 2009 7:21 pm
Contact:

Re: Button "PRESSED" state, I got it working! Or I should say [SOLVED]

#3 Post by gas » Mon Jan 20, 2020 7:21 am

You should post it in the cookbook section too, people can find it helpfull.
10 ? "RENPY"
20 GOTO 10

RUN

Post Reply

Who is online

Users browsing this forum: Google [Bot]