|
>
|
| Home > Articles > Tutorials > Ruby Game Scripting System (RGSS) > RGSS and Ruby Lesson - Chapter 3
|
|
RGSS and Ruby Lesson - Chapter 3
|
|
Author: Dubealex
Updated: October 04, 2007
|
|
Introduction
|
|
You can now download the complete script
from this tutorial in a working project below...The project will be updated as
the tutorial is updated.
rgss_lesson_c3.rar
You need to have read Chapter 1 and 2 before reading Chapter 3.
Remember the RGSS Reference on the main website-- It contains many info, even regarding If Statement and the
likes.
This chapter isn't finished yet. I decided to create it little by little, a section (or more) at a time; that way it should
ease your suffering of waiting for it...Each time I update this chapter, you
will see it in the NEWS of the forum and the WebSite. I'm sorry, but I have
other thing to do, but I will come here once in a while and add a section.
All the major components you need
to understand were explained in Chapter 2, and Chapter 1 covered the basic of
what is RGSS and Ruby as seen in RMXP. With the knowledge acquiered with lesson
chapter 2, you should be able to tackle chapter 3 with more ease.
Chapter
3 will cover the Selectable/Command Window; we will learn how to create and
manage many different type of menus: Normal Menus, Horizontal Menu, Multiple
Columns Menus, Multiple Menus Field (in the same scene). We will also learn some
nice technique about the creation of CMS, like how to manage correctly your
window in your scene, how to map a picture to replace the window, how to use the
skin you want for each window, etc. As usual, we will also cover some bonus
aspect of some syntax on the way as we see them. Those bonus info will now be
called "Side-Note".
So, with that said, let's get going !
|
|
Contents
|
|
1. Selectable/Command Window Structure
2. Creating a simple horizontal menu
|
|
1. Selectable/Command Window Structure
|
|
Before trying to modify or create any menus, you should all know the structure
of the selectable window and command window in RMXP. Basically, the Window
Selectable take care of the cursor in the menus, where is the cursor and the
help window; the Window Command take care of displaying the menu items in the
window as the user specify them in his scene.
Let's just see how a
simple menu is created and what RMXP did to create it. We will check the
standard menu of the Scene_Menu class (This is the main in-game menu that
appears when you press ESCAPE while playing.) So open the page named
"Scene_Menu".
class Scene_Menu
#--------------------------------------------------------------------------
# â—? オブジェクトåˆ?æÅ“ÿ化
# menu_index : ã‚³ãÆ’Å¾ãÆ’³ãƒ‰ã?®ã‚«ãÆ’¼ã‚½ãÆ’«åˆ?æÅ“ÿä½?ç½®
#--------------------------------------------------------------------------
def initialize(menu_index = 0)
@menu_index = menu_index
end
|
This is the initialize method of the Scene_Menu. In Chapter 2 we did not created
any "initialize" method, we only did our "main" method... Why is there an
intialize method here ? Well, it's to be able to specify where we want the
cursor to appear in the menu when we call that menu from another scene. The
position of the cursor in a menu is called a "Menu Index" in RMXP, so we will
refer to that term from now on. So, if you check in Scene_Item near line #71,
you will see a line that says: $scene = Scene_Menu.new(0) , this send an
attribute to the Scene_Menu class, and the menu index will be 0, if you change
the 0 by 1, the cursor will appear at another location in the menu.
Side Note: def
initialize(menu_index = 0) On this line we
have an attribute definition as explained in earlier chapter; it is defined in
the parenthesis. As you can see, we "hard-coded" a value for the attribute with
"menu_index=0". This has the effect of telling the attribute "menu_index" to
equal 0 by default, so if we call the class without any attribute definition, it
will equal 0 and it won't crash asking for attributes. This is useful if you
want to create attribute for a method but you want default values so you don't
have to send them everytime you use that particular method.
def main
# ã‚³ãÆ’Å¾ãÆ’³ãƒ‰ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã‚’ä½Å“æË†?
s1 = $data_system.words.item
s2 = $data_system.words.skill
s3 = $data_system.words.equip
s4 = "Status"
s5 = "Save"
s6 = "Exit"
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6])
@command_window.index = @menu_index
|
This is the definition of the actual menu. S may stand for "Selection", but it's
not important to know it, what is important to know is that all the lines from
s1 to s6 are what we call "Menu Items", those are the menu selections that will
be listed in the menu window. Actually, what is defined in the s1 to s6 lines
are string (text) that will be shown in the menu. Remember that s1 to s6 are
actually variable that you can use later on; actually, you could call them the
way you want, and you could even not use them. We use them to simplify our menu
creation later on.
Side Notes: s1 =
$data_system.words.item On this line,
remember that "$" refer to a global variable. data_system refer to every data
you may have set in the database of RMXP. So the line s1 actually take the word
you specified in the database in the "items" text field.
Once all our menu item are defined, we
need to create a window for the menu and send the needed attribute with it. The
following line take care of this:
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6])
If you remember
chapter 2, here we just create an object named "@command_window"; which is of
class Window_Command. Window_Command objects need 2 attributes to be created.
Let check the Window_Command class to check it out. Open "Window_Command" page:
class Window_Command < Window_Selectable
#--------------------------------------------------------------------------
# â—? オブジェクトåˆ?æÅ“ÿ化
# width : ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?®å¹â€¦
# commands : ã‚³ãÆ’Å¾ãÆ’³ãƒ‰æâ€“†å—列ã?®é…?列
#--------------------------------------------------------------------------
def initialize(width, commands)
# ã‚³ãÆ’Å¾ãÆ’³ãƒ‰ã?®å€‹æâ€¢°ã?‹ã‚‰ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?®é«Ëœã?•ã‚’ç®â€”冺
super(0, 0, width, commands.size * 32 + 32)
@item_max = commands.size
@commands = commands
self.contents = Bitmap.new(width - 32, @item_max * 32)
self.contents.font.name = $defaultfonttype # "All Commands" window font
self.contents.font.size = $defaultfontsize
refresh
self.index = 0
end
|
Window_Command is a sub class of Window_Selectable, so we will have to take a peak at Window_Selectable later on. So, we see that the initialize metod need 2
attributes, Width and Commands. Hence the line from
Scene_Menu:
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6])
The first attribute is 160, which is the width, and the
second is [s1, s2, s3, s4, s5, s6] which concist of an array containing all our
variables s1 to s6 that contains the string (text) for our menu items. Okay, now
Window_Command uses a "super" syntax to initialize the method from it's super
class "Window_Selectable":
super(0, 0, width, commands.size * 32 + 32)
We now need to open "Window_Selectable" and take a little peak at
the initialize method in there. (Remember Chapter 2, we learned inheritance back
then.)
class Window_Selectable < Window_Base
#--------------------------------------------------------------------------
# â—? å…¬é–‹ã‚¤ãÆ’³ã‚¹ã‚¿ãÆ’³ã‚¹å¤â€°æâ€¢°
#--------------------------------------------------------------------------
attr_reader :index # ã‚«ãÆ’¼ã‚½ãÆ’«ä½?ç½®
attr_reader :help_window # ãÆ’ËœãÆ’«ãƒ—ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦
#--------------------------------------------------------------------------
# â—? オブジェクトåˆ?æÅ“ÿ化
# x : ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?® X 座æ¨â„¢
# y : ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?® Y 座æ¨â„¢
# width : ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?®å¹â€¦
# height : ã‚¦ã‚£ãÆ’³ãƒ‰ã‚¦ã?®é«Ëœã?•
#--------------------------------------------------------------------------
def initialize(x, y, width, height)
super(x, y, width, height)
@item_max = 1
@column_max = 1
@index = -1
end
|
Ok, of course this class also have a super class named Window_Base; it's normal, window_base contains all the basic of creating a window on screen in RMXP.
Window_Selectable need 4 attribute, as Window_Base they are the x position, y
position, width and height of the window to create. Let's check the super line
from our sub class "Window_Command":
super(0, 0, width, commands.size * 32 + 32)
So, the X and Y position are both 0, which means the
window will be at position 0:0 on the screen. (which is the top-left corner of
the screen.) the width is equal to a variable named "width"; which is sent by
Scene_Menu in the line:
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6])
160 is the width. The height is defined as
"commands.size * 32 + 32"; this part may have confused you a little bit... First
of all, you need to remember that "commands" is actually an array variable
defined as:
[s1, s2, s3, s4, s5, s6]
In ruby you can use
many built-in "function" with every components, such as arrays. You can check
all of those "funtions" at the following website:
http://www.rubycentral.com/book/builtins.html
If you
check the website, the definition for "size" is:
"Returns the number of elements in arr. May be zero."
So, what "commands.size" do is return a value that equal the number of item
contained in the array. In our case, the size of our array "commands" is 6. So,
the line "commands.size * 32 + 32" can now be known as:
6 * 32 + 32
Which is: 224... Our height is then 224. So our window is now
160X224 at position 0:0 on the screen. If we go way back to our Scene_Menu class
to see our last line, which is:
@command_window.index = @menu_index
This line actually set the attribute "index" of our
object "@command_window" equal to our instance variable "menu_index", that is 0
by default... But if another scene have sent an attribute when creating that
menu, it will use that value instead; this is how, for example, that the cursor
comes back to where it was when you return from the "Save Menu".
"@command_window.index" will also be used later on in the Scene_Menu to know
where the cursor is; in order to know what to do when the user press "Confirm"
on a selection. (We will see that in depth later.)
There is other stuff
to see, such as "Column Max, Row, Cursur Width, etc", all those components will
be explained so you will be able to create the type of menus you want. But
first, what you need to undestand is how a basic one column menu works, and what
you can do with it. Once we have created this type of menus, we will create a
multi-column menu, and so on with the other type of menus.
Now that the basic of a menu have been explained, we can do our own menu in our own scene.
You should already be able to create your own window, your own scene and your
own variable and objects because of chapter 1 and 2, so we will not go through
all that again.
|
|
2. Creating a simple horizontal menu
|
|
First of all, we need a simple scene to create our menu in. I created a simple
menu layout and window that you can copy and paste, we will use that layout for
our menu. This layout concist of 3 window; one to display the menu, another one
to display the help window, and another one to display the content of a
selection in the menu. This will look like that: (When Empty...)

Just create a new page in your script editor, and paste all the following code
in it: (You can call this page "Simple Horizontal Menu".
#===================================================
# â–? RGSS & Ruby Lesson -- Chapter 3 [SIMPLE HORIZONTAL MENU]
#===================================================
# By: Dubealex
# www.dubealex.com (Creation Asylum)
#
# Last Update: April 14, 2005
#===================================================
#===================================================
# â–¼ CLASS Scene_Chapter3_menu1 BEGINS (Simple Horizontal Menu)
#===================================================
class Scene_Chapter3_menu1
def initialize(menu_index = 0)
@menu_index = menu_index #Store the cursor position
end
#--------------------------------------------------------------------------------------------------------
def main
@window_a1=Window_a1.new #Content Window
@window_a1.update(false) #Decide whether to show/hide the content...
@window_a1.x=200
@window_a1.y=100
@window_a3=Window_a3.new #Help Window
@window_a3.update(" ") #Send the help text by default to the Help Window...
#This is what makes the scene update itself constantly:
Graphics.transition
loop do
Graphics.update
Input.update
update #Call the method DEF UPDATE starting below
if $scene != self
break
end
end
#Execute when exiting the scene:
Graphics.freeze
@window_a1.dispose
@window_a2.dispose
@window_a3.dispose
end
#--------------------------------------------------------------------------------------------------------
def update
@window_a2.update #menu
if Input.trigger?(Input::B) #Press ESCAPE to exit
$game_system.se_play($data_system.cancel_se)
$scene = Scene_Map.new
$game_map.autoplay #Because we play music in the menu...
end
end
#--------------------------------------------------------------------------------------------------------
#Options Method Start Here:
#--------------------------------------------------------------------------------------------------------
end #of the Scene !
#===================================================
# â–² CLASS Scene_Chapter3_menu1 ENDS (Simple Horizontal Menu)
#===================================================
#===================================================
# â–¼ CLASS Window_a1 BEGINS (Content Window)
#===================================================
class Window_a1 < Window_Base
def initialize
super(0, 0, 440,380)
self.contents = Bitmap.new(width-32, height-32)
self.contents.font.name = "Tahoma"
self.contents.font.size = 20
end
def update(content) #Receive the argument from the menu
if content == false #If false, don't show content
self.contents.clear
self.contents.draw_text(0, 0, 120, 32, "No Content...")
else #else, if true, show it...
self.contents.clear
self.contents.draw_text(0, 0, 440, 32, "SHOW CONTENT")
end
end
end
#===================================================
# â–² CLASS Window_a1 ENDS (Content Window)
#===================================================
#===================================================
# â–¼ CLASS Window_a3 BEGINS (Help Window)
#===================================================
class Window_a3 < Window_Base
def initialize
super(0, 0, 640,100)
self.contents = Bitmap.new(width-32, height-32)
self.contents.font.name = "Tahoma"
self.contents.font.size = 20
end
def update(help_text) #Receive argument, show relevant help text in window
self.contents.clear #Clear the content before displaying new data !
self.contents.draw_text(0, 0, 440, 32, help_text) #show the content of "help_text" variable
end
end
#===================================================
# â–² CLASS Window_a3 ENDS (Help Window)
#===================================================
|
This code won't work until you add the little menu below, because one window
isn't yet defined, the menu itself. So read on, and test it after you inserted
the menu in there.
ADDING THE BASIC MENU:
Now
we must add the stuff we want in that scene. First thing first, we will design
the menu and what it will do. So here goes:
Option 1: ITEMS -->
Will open Scene_Items. Option 2: INFOS --> Will display some text
in the content window. Option 3: MUSIC A --> Will play BGM
A. Option 4: MUSIC B --> Will play BGM B. Option 5: EXIT
--> Will exit as ESCAPE do.
Now that we know what we will do, we can
go on and create the basic structure for that menu right now, and polish each
function (method) for the options later. First of all, we will add in the simple
horizontal menu layout in our Scene main method.
So open the page you
created earlier "Simple Horizontal Menu" and go to line #30. We will add our
menu there; paste the following code at line #30:
s1 = "Items"
s2 = "Infos"
s3 = "Music A"
s4 = "Music B"
s5 = "Exit"
@window_a2 = Window_Command.new(200, [s1,s2,s3,s4,s5]) #Remember, 200 is the Width
@window_a2.y=100 #Set a position for the menu other than 0:0
@window_a2.height=380 #Force a new height for the menu window
@window_a2.index = @menu_index
|
To start it, now that the scene will work, create an event on your map and add
the following Call Script in it:
$scene=Scene_Chapter3_menu1.new
|
If you go talk to your event, you'll see the scene, but the menu won't do anything except the fact that you can press ESCAPE to exit the scene and return
to the map.
ADDING THE HELP DISPLAY:
Now
we will add the Help Text display to the menu. The text that will be displayed
in the help window (@window_a3) will changed depending on the cursor position on
the menu. To allow this, we need to always know where the cursor is in the
menu.... So we need to add the code in Def Update of our scene; since this is
the method that is constantly being "called" while we are in our
scene.
So go in Def Update (Still in the Scene Class !), and right below @window_a2.update
add this code:
#THIS IS FOR THE HELP DISPLAY WINDOW:
case @window_a2.index #window_a2 is the menu... index is it's cursor position !
when 0 #Remember that the cursor position start at 0, because it's an Array !!
@window_a3.update("Open the item selection window") #item - s1
when 1
@window_a3.update("Display some info in the content window") #infos -s2
when 2
@window_a3.update("Play BGM A") #Music A - s3
when 3
@window_a3.update("Play BGM B") #Music B - s4
when 4
@window_a3.update("Exit the menu and return to the map") #Exit - s5
end
|
Now, if you test that again, you will see that when you move your cursor from option to option, the help window at the top will display the relevant tooltip
for the selected option. How is it done ? Well, if you haven't guessed by
looking at the code, read on:
Our Help Window is named Window_a3...
here's the code for it:
1 class Window_a3 < Window_Base
2
3 def initialize
4 super(0, 0, 640,100)
5 self.contents = Bitmap.new(width-32, height-32)
6 self.contents.font.name = "Tahoma"
7 self.contents.font.size = 20
8 end
9
10 def update(help_text) #Receive argument, show relevant help text in window
11 self.contents.clear #Clear the content before displaying new data !
12 self.contents.draw_text(0, 0, 440, 32, help_text) #show the content of "help_text"
variable
13 end
14
15 end
|
Line #1 to 9 should not be a problem; if you don't understand them, try to read chapter 1 and 2, it was covered in them. Line 10 create a new method called
"Update" that we can call from our menu (from our scene) to update what is
written at the top. We are asking for an argument that we named "help_text", and
we display that argument on screen on line #12...
If we look at our menu
code, we can see this line everytime we want to change the text displayed on the
help window:
@window_a3.update("New Text")
@window_a3 is our object we created in
our Def Main of our scene, and update is the method we created in our class
Window_a3 (explained above). What follows is the argument (the help text to
display) that is sent to that update method.
ADDING THE OPTION FUNCTIONS:
We
all agree that a menu without any function isn't a really a complete menu... So
now is the time to add those function. It's not that complicated, we need one
method per option we have in the menu; in this case, we have 5 options, so we
will need to create 5 method. So we will add them right now:
Remember the
place where you added the Help Display code earlier, in Def Update (below
@window_a2.update) ? Well, the method you will have to add in the scene goes
right after that Def Update. Just look for the following comments to find
exactly where:
#Options Method Start Here:
|
Now, below that line, paste this code, I will explain it after.
def item #s1, menu_index=0
$game_system.se_play($data_system.decision_se) #play an SE
$scene = Scene_Item.new #Syntax to change scene
end
def infos #s2, menu_index=1
@window_a1.update(true)
end
def music_a #s3, menu_index=2
Audio.bgm_play("Audio/BGM/song_a.mid", 100, 100) #Play custom BGM
end
def music_b #s4, menu_index=3
Audio.bgm_play("Audio/BGM/song_b.mid", 100, 100) #Play custom BGM
end
def exit #s5, menu_index=4
$game_system.se_play($data_system.cancel_se) #play an SE
$scene = Scene_Map.new #Syntax to change scene
$game_map.autoplay #Because we play music in the menu...
end
|
Side Note: Using method for menu
options You do not need (it's not necessary)
to use method for each option menu, especially if they are simple and short as
this sample menu. But I decided to show it that way because sometimes, menu
option could do long and more complicated operation, and in this case, it's
better to break them down into different method. If you would want to test it
without using method, you can simply replace each method call from within the
Case Statement by the content of each method, and voilÃ? . I prefer to use
method, that way it's better classified.
A little note, the lines that start with Audio.bgm_play have to be configured with the names of your own audio files, present in Audio\BGM. Change
the name between parenthesis, and you are set to go.
There isn't much
to explain, for those are very simple operations. I don't think I have to
explain the code itself. Each of those method will be called by a new code we
will add in our Def Update, just below the code we added for the Help Display
window. So, look for this code in Def Update of our Scene:
@window_a3.update("Exit the menu and return to the map") #Exit - s5
end
|
And below it, add the following code:
#THIS IS FOR THE OPTION FUNCTIONS:
if Input.trigger?(Input::C) #Do the following if ENTER is pressed...
case @window_a2.index #window_a2 is the menu... index is it's cursor position !
when 0 #Remember that the cursor position start at 0, because it's an Array !!
item #item - s1
when 1
infos #infos -s2
when 2
music_a #Music A - s3
when 3
music_b #Music B - s4
when 4
exit #Exit - s5
end
end
|
Now, if you go and test your menu, it will be completed with all the function and help display. For the Content Window, you can just add as much line as you
want or show any other stuff in place of text, you can tweak this code and do
what you want with it, it's the goal of a tutorial after all
I know this was kind of "basic", but you can
tweak those code and do way more, like changing the bgm, showing pictures or
changing window/picture from places to another places dynamically, instead of
just showing the help window...
I do not have the time to continue doing tutorial at the moment...
|
|
More in the 'RGSS and Ruby Lesson' series:
• RGSS and Ruby Lesson - Chapter 1
• RGSS and Ruby Lesson - Chapter 2
• RGSS and Ruby Lesson - Chapter 3
|
|