The code for Ristorante will actually be left unarchived so you can see the finished result once the game is done. I just thought that doing this might help out others doing NaNoRenO right now. :O
Code: Select all
##############################################################################
# Main Menu
#
# Screen that's used to display the main menu, when Ren'Py first starts
# http://www.renpy.org/doc/html/screen_special.html#main-menu
screen main_menu:
# This ensures that any other menu screen is replaced.
tag menu
imagemap:
ground "ui/mm_ground.png"
idle "ui/mm_idle.png"
hover "ui/mm_hover.png"
if not persistent.beaten:
hotspot (0, 40, 378, 85) action Start()
else:
hotspot (0, 40, 378, 85) action Start("real")
hotspot (0, 136, 360, 89) action ShowMenu("load")
hotspot (0, 235, 341, 85) action ShowMenu("preferences")
hotspot (0, 325, 320, 93) action Quit(confirm=False)
hotspot (0, 423, 295, 86) action Help()
if persistent.beaten:
hotspot (816, 16, 207, 67) action Start()
hotspot (790, 88, 233, 61) action ShowMenu("bonus")
I basically use imagemaps for everything because that way I can fully customize how my screens look in Photoshop before coding them for Ren'Py. This is the main menu used in Ristorante… 100% imagemap. I have a main menu that changes depending on whether or not the prologue has been cleared or not. In my prologue, at the end, there is this variable trigger:
Code: Select all
$ persistent.beaten = True
Code: Select all
##############################################################################
# Input
#
# Screen that's used to display renpy.input()
# http://www.renpy.org/doc/html/screen_special.html#input
screen input:
window:
xalign 0.5
yalign 0.5
has vbox
text prompt:
yoffset 36
style "say_dialogue"
xoffset 82
input:
id "input"
style "say_dialogue"
color "#8e6439"
yoffset 36
xoffset 107
Code: Select all
##############################################################################
# Save, Load
#
# Screens that allow the user to save and load the game.
# http://www.renpy.org/doc/html/screen_special.html#save
# http://www.renpy.org/doc/html/screen_special.html#load
# Since saving and loading are so similar, we combine them into
# a single screen, file_picker. We then use the file_picker screen
# from simple load and save screens.
screen load_save_slot:
$ file_text = "%2s. %s\n %s" % (
FileSlotName(number, 4),
FileTime(number, empty=_("Empty Slot.")),
FileSaveName(number))
add FileScreenshot(number) xpos 61 ypos 69
text file_text xpos 215 ypos 92 size 18 color "#261d0c"
screen file_picker:
key "w" action FileLoad(1, page="quick", confirm=True, newest=False)
key "m" action MainMenu(confirm=True)
key "p" action ShowMenu("preferences")
key "mouseup_3" action ShowMenu("keys_map")
key "K_ESCAPE" action Return()
imagemap:
ground "ui/sl_ground.png"
idle "ui/sl_idle.png"
hover "ui/sl_hover.png"
selected_idle "ui/sl_idle.png"
hotspot (528, 39, 14, 23) clicked FilePage(1)
hotspot (566, 40, 22, 23) clicked FilePage(2)
hotspot (611, 39, 18, 23) clicked FilePage(3)
hotspot (653, 40, 18, 21) clicked FilePage(4)
hotspot (694, 40, 17, 22) clicked FilePage(5)
hotspot (735, 41, 21, 20) clicked FilePage(6)
hotspot (776, 39, 22, 23) clicked FilePage(7)
hotspot (819, 39, 20, 23) clicked FilePage(8)
hotspot (860, 39, 23, 24) clicked FilePage(9)
hotspot (900, 39, 27, 23) clicked FilePage(10)
hotspot (22, 121, 444, 235) clicked FileAction(1):
use load_save_slot(number=1)
hotspot (483, 121, 444, 235) clicked FileAction(2):
use load_save_slot(number=2)
hotspot (22, 356, 444, 235) clicked FileAction(3):
use load_save_slot(number=3)
hotspot (483, 356, 444, 235) clicked FileAction(4):
use load_save_slot(number=4)
hotspot (523, 68, 62, 31) action ShowMenu("load")
hotspot (589, 70, 59, 29) action ShowMenu("save")
hotspot (653, 70, 60, 31) action Help()
hotspot (787, 72, 62, 27) action Quit()
hotspot (718, 71, 65, 27) action MainMenu()
hotspot (877, 69, 62, 29) action Return()
screen save:
key "s" action Return()
# This ensures that any other menu screen is replaced.
tag menu
use file_picker
add "ui/sl_save.png"
screen load:
key "l" action Return()
# This ensures that any other menu screen is replaced.
tag menu
use file_picker
add "ui/sl_load.png"
init -2 python:
style.file_picker_frame = Style(style.menu_frame)
style.file_picker_nav_button = Style(style.small_button)
style.file_picker_nav_button_text = Style(style.small_button_text)
style.file_picker_button = Style(style.large_button)
style.file_picker_text = Style(style.large_button_text)
config.thumbnail_width = 75
config.thumbnail_height = 42
This is Ristorante's save/load screen—another imagemap! You can think of it as being in layers… The file_picker screen is the save/load screen itself. I put the navigation there, but I also defined where the save slots are.
In the case of Ristorante, there are four save slots per page. So I figured out the coordinates/sizes of each save slot and made those into the FileAction hotspots you see above. You also have to assign each slot a number, which is what the "use load_save_slot()" thing is. So then basically no matter which page of the save/load you're on, this code will be repeated. Even though we only define 1-4, Ren'Py will automatically know that on page 2, the slots are 5, 6, 7, and 8, so don't worry about that. You can use the developer tools to figure out the proper hotspot coordinates of your save slots. I personally just use the slice tool in Photoshop and copy the coordinates out of that, but you should do whatever works for you.
Moving on, the load_save_slot screen basically defines what each save/load slot looks like. You've already placed where each slot is on the page, but this screen tweaks each save slot. You can change the text, for example, or add in another variable like [chapter] or something. I changed the position/color of the text and changed the size/position of the thumbnail to fit my box. (I changed the thumbnail size in the init block at the bottom of this code, though) Be sure that instead of "FileSlotName(number, 4)", the 4 is however many slots you have per page. (it's 4 in my case)
You might notice that underneath the file_picker screen I have a number of codes that start with "key". This is how you create binding keys. I have another screen like this that basically is my own set of keybindings. (the same ones used for BCM minus quick save/load) Looks like this:
Code: Select all
##############################################################################
# Keymap screen
#
screen keys:
zorder 100
key "K_PAGEUP" action Rollback()
key "K_PAGEDOWN" action RollForward()
key "K_TAB" action Skip()
key "s" action ShowMenu("save")
key "l" action ShowMenu("load")
key "m" action MainMenu(confirm=True)
key "p" action ShowMenu("preferences")
Code: Select all
label start:
show screen keys
Code: Select all
##############################################################################
# Preferences
#
# Screen that allows the user to change the preferences.
# http://www.renpy.org/doc/html/screen_special.html#prefereces
screen display_pref:
add "mouseovers/prefs_display.png"
screen transitions_pref:
add "mouseovers/prefs_transitions.png"
screen skip_pref:
add "mouseovers/prefs_skip.png"
screen after_pref:
add "mouseovers/prefs_after.png"
screen text_pref:
add "mouseovers/prefs_text.png"
screen auto_pref:
add "mouseovers/prefs_auto.png"
screen bgm_pref:
add "mouseovers/prefs_bgm.png"
screen se_pref:
add "mouseovers/prefs_se.png"
screen preferences:
tag menu
key "s" action ShowMenu("save")
key "l" action ShowMenu("load")
key "w" action FileLoad(1, page="quick", confirm=True, newest=False)
key "m" action MainMenu(confirm=True)
key "p" action Return()
key "K_ESCAPE" action Return()
mousearea:
area (0,30,332,119)
hovered Show("display_pref", transition=sdissolve)
unhovered Hide("display_pref", transition=sdissolve)
mousearea:
area (0,151,306,117) #transitions
hovered Show("transitions_pref", transition=sdissolve)
unhovered Hide("transitions_pref", transition=sdissolve)
mousearea:
area (0,273,285,118) #skip
hovered Show("skip_pref", transition=sdissolve)
unhovered Hide("skip_pref", transition=sdissolve)
mousearea:
area (0,395,283,131) #after choices
hovered Show("after_pref", transition=sdissolve)
unhovered Hide("after_pref", transition=sdissolve)
mousearea:
area (607, 29, 325, 129) #text speed
hovered Show("text_pref", transition=sdissolve)
unhovered Hide("text_pref", transition=sdissolve)
mousearea:
area (587, 162, 293, 124) #auto-forward
hovered Show("auto_pref", transition=sdissolve)
unhovered Hide("auto_pref", transition=sdissolve)
mousearea:
area (565, 289, 288, 123) #bgm volume
hovered Show("bgm_pref", transition=sdissolve)
unhovered Hide("bgm_pref", transition=sdissolve)
mousearea:
area (540, 416, 329, 126) #se volume
hovered Show("se_pref", transition=sdissolve)
unhovered Hide("se_pref", transition=sdissolve)
imagemap:
ground "ui/prefs_ground.png"
idle "ui/prefs_idle.png"
hover "ui/prefs_hover.png"
selected_idle "ui/prefs_selected.png"
selected_hover "ui/prefs_selected_hover.png"
alpha False
hotspot (127, 92, 120, 56) action Preference("display", "fullscreen")
hotspot (2, 92, 118, 56) action Preference("display", "window")
hotspot (128, 333, 152, 60) action Preference("skip", "seen")
hotspot (4, 331, 104, 61) action Preference("skip", "all")
hotspot (2, 206, 108, 62) action Preference("transitions", "all")
hotspot (128, 206, 108, 62) action Preference("transitions", "none")
hotspot (125, 461, 157, 65) action Preference("after choices", "stop")
hotspot (2, 462, 110, 59) action Preference("after choices", "skip")
bar pos (675, 129) value Preference("text speed") style "pref_slider"
bar pos (636, 510) value Preference("sound volume") style "pref_slider"
bar pos (627, 385) value Preference("music volume") style "pref_slider"
bar pos (634, 257) value Preference("auto-forward time") style "pref_slider"
imagemap:
ground "ui/prefs_menu_ground.png"
idle "ui/prefs_menu_idle.png"
hover "ui/prefs_menu_hover.png"
hotspot (949, 279, 61, 30) action ShowMenu("load")
hotspot (946, 315, 66, 31) action ShowMenu("save")
hotspot (947, 354, 65, 31) action Help()
hotspot (948, 427, 64, 31) action Quit()
hotspot (947, 392, 64, 27) action MainMenu()
hotspot (944, 500, 68, 31) action Return()
init -2 python:
style.pref_slider.left_bar = "ui/slider_left.png" #full
style.pref_slider.right_bar = "ui/slider_right.png" #empty
style.pref_slider.xmaximum = 162 # width of your left_bar image.
style.pref_slider.ymaximum = 30 # height of your left_bar image. Probably will be the height of the red part of the bar plus the slider's height.
style.pref_slider.thumb = "ui/pixel.png"
style.pref_slider.thumb_offset = 1 # Half of your thumb's width in pixels
style.pref_slider.thumb_shadow = None
Time for the gargantuan preferences screen. >_> I'll just start from the top and go down. Each of those _pref screens was made for the mouseovers. It's kind of a waste since each one is just an image, but I can't think of an easier way to do it, so whatever. Scroll down and you see the keymap again.
Scroll down some more and you see each mousearea. I have it set so that when you hover over a certain preference (both the title and the buttons), it'll trigger the mouseover. This will make the "image tooltip" pop up at the bottom of the screen to explain what that particular preference does. I actually will use this for the main menu and bonus menus, too, I just haven't coded them in yet because I'm lazy. Anyway, mouseovers are a lot like hotspots, just that you use "area" instead of hotspot. You then define actions for what happens when that hotspot is hovered over or unhovered. I use this in BCM, too, for the dropdown menu. So whenever you hover over the top part of the screen, the little dropdown menu slides down so you can save/load/etc. (on top of the keymap xD)
Here we get to the actual preferences imagemap once you scroll down some more. Because I've made idle/hover/selected transparent, I went ahead and added the "alpha False" property. This makes it so that you can click the entirety of a hotspot area. If alpha were true, you could only click on the parts of the hotspot that weren't transparent. @_@ This makes it kind of a pain when you're using a thin font or something… The player then has to click right on the text, which can be difficult and frustrating.
I put the navigation on its own imagemap/layer because I thought I'd be reusing it, but then it turned out I didn't. XD; So I could've put all that navigation on the original imagemap if I combined the layers, but oh well.
You will notice that on the imagemap are things that say "bar pos". Well, the bars I use on the preferences screen aren't built in to the imagemap, but what you can do is define where on the imagemap they would show up. That's why there's only two coordinates instead of four like for the hotspots. So you position each bar where you want it to show up and define what preference it's for—and voila! A bar will show up in each one of those spots. Of course, it will be the Ren'Py default bar, so that's why at the bottom I changed how the bar looks under the init block. Aleema's style tutorial has good explanations on how to customize that, though.
Code: Select all
screen nagasaki_map:
zorder 50
add "ui/map_ground_inner.png"
add "map_clouds"
add "ui/map_ground_border.png"
add "ui/map_ornament.png"
Also remember that you can have lots of actions assigned to a button. I link to a tutorial for that at the end of this post, but for example here's one of the buttons on the BCM map:
Code: Select all
imagebutton:
idle "ui/map_markers_03.png"
hover "ui/map_markers_hover_03.png"
action Return("dorms")
xpos 279
ypos 127
hovered Show("nagasaki_map_zoom_dorms", transition=dissolve)
unhovered Hide("nagasaki_map_zoom_dorms", transition=sdissolve)
Aaaaaaand I think that just about covers all of my GUI "secrets"… Using imagemaps and screens, you can do a whole lot of stuff. Every one of my menus in BCM is a screen rather than a label that you jump to. (just make sure that you add "tag menu" so that the Return() will work properly) You can easily add text, images, mouseareas, imagemaps, bars, and buttons to your GUIs using screen language. n_n This post was pretty much just a crash course, but if you have any questions I can try to answer them? I didn't go super in depth because I don't really know what all to put in a tutorial…
Here are some of my LSF bookmarks that are related to GUI/customization in no particular order (also the SL documentation goes a LONG way):
Change the music played when viewing a screen
Detailed instructions on making your own CG gallery
Aleema's customizing menus tutorial (REQUIRED READING)
Aleema's customizing textbox tutorial (ALSO REQUIRED READING)
Making an inventory with screen language
How to gray out previously chosen choices
Having an imagemap remember what you've already clicked
Allow players to reset preferences to default
Gray out skip button while skipping
Making HP/MP/etc bars with SL
Display percent (of game) complete
Changing menus based on variable
Assigning several actions to a hover/click/whatever
Custom preferences using SL
Stop textbox from disappearing during transitions
Note that some of these might be outdated so you'll have to change %(variable)s to [variable] or make other tweaks where necessary. Reading documentation, searching the forums, and doing lots of trial and error in your own game goes a very long way. Also, INDENTATION IS KEY. I think improper indentation is responsible for like 80% of errors* or something. (*percentage possibly made up)
I hope this was useful to people