Basically, I need to be able to define the location of the hotspot each time using xpos/ypos and define which label it jumps to when clicked.
Well, you answered your question.
As for a less theoretical answer, there's so many possible ones, and this for every each one piece of the problem. Some of them being :
1) How to store the information related to the button(s):
a) As a dictionary of tuples:
Each entry of the dictionary is one of the button, an each element of the tuple is one of the information.
Python:
# Those information SHOULD NOT be saved. This permit you to change the values
# from one update to another if you made an error.
define myButtons = {
# One of the entries.
"thisButton": ( "gui/button/hotspot_%s.png", 262, 685, "pick_up_box" ),
# Another one.
"thatButton": ( "gui/button/that_%s.png", 321, 123, "aLabel" ),
# Continue like that.
}
Then your button would looks like that:
Code:
imagebutton:
auto myButtons["thisButton"][0]
xpos myButtons["thisButton"][1]
ypos myButtons["thisButton"][2]
action Jump(myButtons["thisButton"][3])
b) As an series of functions:
You'll always take the information from the same source, but the information will changes depending of the context.
Python:
init python:
# Function to know what image to use for the button.
def buttonImage():
# If the screen "thisScreen" is actually shown.
if renpy.get_screen( "thisScreen" ):
# Use this button.
return "gui/button/hotspot_%s.png"
# If it's the screen 'thatScreen" that is actually shown.
elif renpy.get_screen( "thatScreen" ):
# Then use this button instead.
return "gui/button/that_%s.png"
# Function to know the x position for the button.
def buttonXPos():
if renpy.get_screen( "thisScreen" ):
return 262
elif renpy.get_screen( "thatScreen" ):
return 321
# Function to know the y position for the button.
def buttonYPos():
if renpy.get_screen( "thisScreen" ):
return 685
elif renpy.get_screen( "thatScreen" ):
return 123
# Function to know the label where to jump for the button.
def buttonLabel():
if renpy.get_screen( "thisScreen" ):
return "pick_up_box"
elif renpy.get_screen( "thatScreen" ):
return "aLabel"
Then your button would looks like that:
Code:
imagebutton:
auto buttonImage()
xpos buttonXPos()
ypos buttonYPos()
action Jump( buttonLabel() )
Alternatively you can select the value according to an information past as argument.
Python:
init python:
# Function to know what image to use for the button.
def buttonImage( screenInfo ):
# If the parameter is "this".
if screenInfo == "this":
# Use this button.
return "gui/button/hotspot_%s.png"
# If it's the "that" parameter.
elif screenInfo == "that:
# Then use this button instead.
return "gui/button/that_%s.png"
# Function to know the x position for the button.
def buttonXPos( screenInfo ):
if screenInfo == "this":
return 262
elif screenInfo == "that:
return 321
# Function to know the y position for the button.
def buttonYPos( screenInfo ):
if screenInfo == "this":
return 685
elif screenInfo == "that:
return 123
# Function to know the label where to jump for the button.
def buttonLabel( screenInfo ):
if screenInfo == "this":
return "pick_up_box"
elif screenInfo == "that:
return "aLabel"
In this case the button would looks like this:
Code:
imagebutton:
auto buttonImage( "thisButton" )
xpos buttonXPos( "thisButton" )
ypos buttonYPos( "thisButton" )
action Jump( buttonLabel( "thisButton" ) )
c) Directly in the screen:
If the button is in an external screen, you can then decide to change the information directly in the screen.
Python:
# If the screen "thisScreen" is actually shown.
if renpy.get_screen( "thisScreen" ):
# OR alternatively
# if screenInfo == "this"
imagebutton:
auto "gui/button/hotspot_%s.png"
xpos 262
ypos 685
action Jump( "pick_up_box" )
elif renpy.get_screen( "thatScreen" ):
# if screenInfo == "that"
imagebutton:
auto "gui/button/that_%s.png"
xpos 321
ypos 123
action Jump( "aLabel" )
2) How to let the button know what data have to be used:
a) With the help of a global variable:
You've one variable that will store a keyword defining what button is to show.
Python:
# This time, the variable MUST be saved.
# By default there's no button shown.
default actualButton = None
Then you use it like that
Code:
label whatever:
$ actualButton = "thisButton"
show screen whatever
or like this
Code:
screen whatever():
$ store.actualButton = "thisButton"
b) By passing the information as argument to the screen:
Screen can get arguments, so you can benefit to that.
The screen would start like that
Code:
screen whatever( screenInfo ):
[...]
and the button can look like this (I'll use the way 1a, but it apply for the others)
Code:
imagebutton:
auto myButtons[screenInfo][0]
xpos myButtons[screenInfo][1]
ypos myButtons[screenInfo][2]
action Jump(myButtons[screenInfo][3])
And finally your code would be this one
Code:
label whatever:
show screen whatever("thisButton")
c
) Directly pass the data to the screen:
Like you can pass arguments to a screen, you don't necessarily need to store the data.
Code:
screen whatever( buttonImage, buttonXPos, buttonYPos, buttonLabel ):
imagebutton:
auto buttonImage
xpos buttonXPos
ypos buttonYPos
action Jump( buttonLabel )
What you use this way
Code:
label whatever:
call screen whatever( "gui/button/hotspot_%s.png", 262, 685, "pick_up_box" )
3) How to define the button(s):
Note: Again I'll just use the method 1a for the data storage, and 2a for to know what data to use. But obviously the same apply for all the methods.
a) Directly in the screen:
You can put the button in each screen that will need it
Code:
screen whatever():
[...]
imagebutton:
auto myButtons[actualButton ][0]
xpos myButtons[actualButton ][1]
ypos myButtons[actualButton ][2]
action Jump(myButtons[actualButton ][3])
b) As used screen:
Ren'py permit you to use an external screen inside another screen. This let you have only one screen for the button, while using it in many screens. Therefore you've the screen for the button
Code:
screen myButton():
imagebutton:
auto myButtons[actualButton ][0]
xpos myButtons[actualButton ][1]
ypos myButtons[actualButton ][2]
action Jump(myButtons[actualButton ][3])
that you include in your screens
Code:
screen whatever():
[...]
use myButton
c) As an independent screen:
This method works with less storage methods, but it worth being mentioned as well. The screen will be always displayed, but it will show a button only when it's needed.
Python:
screen myButton():
# If the screen "thisScreen" is actually shown, show this button.
if renpy.get_screen( "thisScreen" ):
imagebutton:
auto "gui/button/hotspot_%s.png"
xpos 262
ypos 685
action Jump( "pick_up_box" )
# If it's the screen "thatScreen" that is actually shown, then show that one.
elif renpy.get_screen( "thatScreen" ):
imagebutton:
auto "gui/button/that_%s.png"
xpos 321
ypos 123
action Jump( "aLabel" )
# And if it's none of those screens, then just show nothing
You just need to show the screen at the start of the game, and it will be shown forever unless you explicitly hide it, or you use the
scene
statement alone to clear the screen.
Code:
label start:
show screen myButton
Note that I used
renpy.get_screen
to decide which button have to be shown, but it works also with a global variable. It would obviously reduce drastically the size of the screen.
Python:
screen myButton():
# The button will be shown only if /actualButton/ have a value.
if not actualButton is None:
imagebutton:
auto buttonImage( actualButton )
xpos buttonXPos( actualButton )
ypos buttonYPos( actualButton )
action Jump( buttonLabel( actualButton ) )
In this case, you use it this way
Python:
label whatever:
# Define the button to show.
$ actualButton = "thisButton"
show screen whatever
label pick_up_box:
# Do not show a button anymore.
$ actualButton = None
All this being said, according to the example you gave, and its "pick_up_box" label, I don't think that having an "one for all" button is the solution. Those buttons aren't generics one (like navigation buttons, menu buttons, or things like that) that will be shown a lot of times, but not necessarily in the same position and with the same icon ; by example a menu button could be invalidated, or a navigation button could include the face of the girl present in this place. Instead they looks like very particular buttons that will apply once and only once ; by example, I doubt that the player will have to pick up the box every two minutes.
Therefore, using an "one for all" would be way too much works, and open the gate to way too many bugs, than having to write again and again the four lines defining a button.