Multiple conditional statements in an imagebutton

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
account183
Newbie
Posts: 2
Joined: Fri Nov 12, 2021 5:59 pm
Contact:

Multiple conditional statements in an imagebutton

#1 Post by account183 » Fri Nov 12, 2021 6:15 pm

I have three objects (imagebuttons) on screen. I want the user to click all three imagebuttons before it goes to the next screen. The order doesn't matter, but it can't move on until all three are clicked.

I'm really struggling with coding the logic on this. My initial thought was to assign each button a True/False variable, and then embed an "if" statement and an "and" statement within each imagebutton. So, for instance, if imagebuttons #1 and #2 are both clicked, then clicking #3 would go to the next screen. Whereas, if imagbuttons #2 and #3 are clicked first, then imagebutton #1 would go to the next screen. I can't get the code to work though.

As a workaround, I was thinking I could assign each button a different numerical value, but I couldn't get that to work either. Finally, I was thinking I could just link each order of clicks to different imagebutton files, but it still presents the same issue, I think.

Please help!

philat
Eileen-Class Veteran
Posts: 1853
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Multiple conditional statements in an imagebutton

#2 Post by philat » Sat Nov 13, 2021 1:24 am

The right way to do this, imo, is to do the logic outside of the screen. Pseudocode below.

Code: Select all

screen clickallthree:
    # buttons don't do anything only return value to be used in label objects
    textbutton "1" action Return("firstobj")
    
label before_screen:
    call screen clickallthree
        
label objects:
    # use returned value from buttons to do whatever needs to be done here
    # you can access returned value with _return so like if _return=="firstobj" do whatever etc.
    if [all three vars]:
        jump after_screen
    else:
        jump before_screen (i.e., call screen clickallthree but then fall down to label objects after return -- you can change the structure here to use jumps or whatever if you'd prefer, the point is that you should be looping from a call screen to another call screen until a condition is met and you break the loop) 

label after_screen:
    # proceed with story

strayerror
Regular
Posts: 154
Joined: Fri Jan 04, 2019 3:44 pm
Contact:

Re: Multiple conditional statements in an imagebutton

#3 Post by strayerror » Sat Nov 13, 2021 2:31 am

For the sake of balance, here are two options that do keep it all within the screen:

They both presuppose that you only want to click each item once, with the buttons getting disabled once clicked. It is possible to modify them if you wish to keep all buttons clickable until all have been clicked at least once, but disabling them can help nudge the player along through clicking each of them.

Code: Select all

label start:
    scene black
    call screen test1()
    'test1 complete'
    call screen test2()
    'test2 complete'
    return

# This one reads strangely until you remember that the condition in the If is
# evaluated when the screen is displayed, and not after the player clicks.
screen test1():
    default track = {1, 2, 3}
    $ check = If(len(track) == 1, Return())

    textbutton 'ONE' align (.4, .4) action RemoveFromSet(track, 1), check
    textbutton 'TWO' align (.5, .6) action RemoveFromSet(track, 2), check
    textbutton 'THREE' align (.6, .4) action RemoveFromSet(track, 3), check

screen test2():
    default track = {1, 2, 3}

    textbutton 'ONE' align (.4, .4) action RemoveFromSet(track, 1)
    textbutton 'TWO' align (.5, .6) action RemoveFromSet(track, 2)
    textbutton 'THREE' align (.6, .4) action RemoveFromSet(track, 3)

    # This is a bit cheaty, but also allows adding some delay after the final
    # click before the screen ends.
    if not track:
        timer .001 action Return()
Hope that helps and sheds a little light on some possible pure screenlang alternatives. :)

philat
Eileen-Class Veteran
Posts: 1853
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Multiple conditional statements in an imagebutton

#4 Post by philat » Sat Nov 13, 2021 2:43 am

Just wanted to add that I presumed the goal is to do something on each button click when recommending the return out and loop call screen method (e.g., because all evaluation is happening out of screen anyway, it's easy to add interactions like character makes short remark about what you picked up, perhaps says there might be a few things of interest left in the area, etc.). If the goal is only to click three things in succession, doing it in screen probably makes more sense.

User avatar
Alex
Lemma-Class Veteran
Posts: 2981
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Multiple conditional statements in an imagebutton

#5 Post by Alex » Sat Nov 13, 2021 7:10 am

account183 wrote:
Fri Nov 12, 2021 6:15 pm
... My initial thought was to assign each button a True/False variable, and then embed an "if" statement and an "and" statement within each imagebutton. So, for instance, if imagebuttons #1 and #2 are both clicked, then clicking #3 would go to the next screen. Whereas, if imagbuttons #2 and #3 are clicked first, then imagebutton #1 would go to the next screen. I can't get the code to work though. ...
The third option (that might suit in some cases or not in others) would be

Code: Select all

screen buttons_scr():
    
    tag my_screen # only one screen with the same tag will be shown onscreen
    
    default flag_1 = False # screen variable (default value on each screen show)
    default flag_2 = False
    default flag_3 = False
    
    vbox:
        align(0.5, 0.05)
        textbutton "Click Me 1":
            if flag_2 and flag_3:
                action [SetScreenVariable("flag_1", True), Show("the_other_scr")]
            else:
                action ToggleScreenVariable("flag_1", True, False) # toggles value (True/False)
                
        textbutton "Click Me 2":
            if flag_1 and flag_3:
                action [SetScreenVariable("flag_2", True), Show("the_other_scr")]
            else:
                action ToggleScreenVariable("flag_2", True, False)
                
        textbutton "Click Me 3":
            if flag_1 and flag_2:
                action [SetScreenVariable("flag_3", True), Show("the_other_scr")]
            else:
                action ToggleScreenVariable("flag_3", True, False)
            
screen the_other_scr():
    
    tag my_screen
    
    modal True
    # clicking will hide the screen and let player proceed through the hard pause
    key 'dismiss' action [Return(), Hide("the_other_scr")] 
    frame:
        align(0.5, 0.5)
        xysize(400, 200)
        text "Well done!" align(0.5, 0.5)

# The game starts here.
label start:
    "..."
    show screen buttons_scr
    $ renpy.pause(hard=True) # will stop the game untill screen Return something
    "Done"
    "?!"
https://www.renpy.org/doc/html/screens.html#key
https://www.renpy.org/doc/html/screen_a ... enVariable
https://www.renpy.org/doc/html/other.html#renpy.pause

account183
Newbie
Posts: 2
Joined: Fri Nov 12, 2021 5:59 pm
Contact:

Re: Multiple conditional statements in an imagebutton

#6 Post by account183 » Sat Nov 13, 2021 11:33 am

Thank you all so much for the help! I got it to work! It was really great getting to see the different approaches. I'm still new to all this, so I wasn't able to fully appreciate the elegance of each option.

To provide some more color, basically I was coding an "I spy" type mini-game where the player needs to find three hidden objects in a scene. After clicking an object, it switches from "idle" to "hover" state (essentially, from camouflaged to highlighted). I was able to accomplish this by adding an additional action to each imagebutton to show a screen. However, the next issue I ran into was how to clear those screens when the player moves on. I addressed this with "renpy.hide_screen".

I'm sure there must be a better way to do this, but thank you so much again!

Here's how I coded it:

Code: Select all

label game:

    scene bg
    call screen test1()
    scene bg2
    "Congrats!"
    call next

    screen ObjectAScreen:
        add "ObjectA_hover.png" xpos 1000 ypos 300

    screen ObjectBScreen:
        add "ObjectB_hover.png" xpos 700 ypos 400

    screen ObjectCScreen:
        add "ObjectC_hover.png" xpos 1200 ypos 600

    screen test1():
        default track = {1, 2, 3}
        $ check = If(len(track) == 1, Return())

        imagebutton auto "ObjectA_%s.png" xpos 1000 ypos 300 focus_mask True action [RemoveFromSet(track, 1), check, Show("ObjectAScreen")]
        imagebutton auto "ObjectB_%s.png" xpos 700 ypos 400 focus_mask True action [RemoveFromSet(track, 2), check, Show("ObjectBScreen")]
        imagebutton auto "ObjectC_%s.png" xpos 1200 ypos 600 focus_mask True action [RemoveFromSet(track, 3), check, Show("ObjectCScreen")]

    label next:

        python:
            renpy.hide_screen("ObjectAScreen")
            renpy.hide_screen("ObjectBScreen")
            renpy.hide_screen("ObjectCScreen")

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot]