|
> |
| Home > Articles > Tutorials > Ruby Game Scripting System (RGSS) > RGSS For Dummies Tutorial 7: Windows for Dummies
|
|
RGSS For Dummies Tutorial 7: Windows for Dummies |
|
Author: RPG
Updated: September 04, 2007
|
|
Introduction
|
|
I thought it would be nice to have a practical tutorial for a change. After all,
the last tutorials had lots of talk and little code. In this tutorial, you will
learn about creating windows and scenes. We will add a new "About" option to the
main menu; this option will simply show a window with some information about the
game.
|
|
Contents
|
|
1. Basic Stuff
2. The Window Class
3. Creating the Window Class
4. Creating the Scene Class
5. Adding the 'About' item to the Main Menu
6. Annoying Play Time WIndow
7. Conclusion
8. Summary
|
|
1. Basic Stuff
|
|
Before we jump to creating the about window, it's better to get a basic idea
about how menus work. As mentioned in the previous tutorial, scenes control
input, processing, and output. Each menu option (item for example) has its own
Scene class, as well as a window class. The window class (Window_Item for
example) defines the shape and contents of the window, this class has a refresh
method that actually draws text or images on the windows. Note that the window
class only controls how the window looks like, but not how the user interacts
with the window. This is why there is a scene class (such as Scene_Item), which
detects input and does various actions depending on the input (like using an
item if you press the action key). Our goal is to add an 'About' option to the
main menu, so we will need an about window class (I'll call it Window_About, you
can call it whatever you like though) and an about scene class (I'll call it
Scene_About). We will also need to modify the main menu to add a new About
option under 'exit'.
|
|
2. The Window Class
|
|
Let me introduce you to the Window family (Window class heirarchy). It's an
ancient noble family known for it's ability to provide boxes to interact with
users. The head of the family is the very old Mr. Window, he has a basic drawing
board (window). He doesn't have any paper (bitmap) though, just a wooden drawing
board.
Mr. Window has one son (child class) named Window_Base. Window_Base inherited his father's drawing board, but couldn't find papers
either. However, he learned new abilities (methods) such as drawing names of
heroes, drawing HP and MP, drawing item icons, etc.
Later, Window_Base had
many children. All of them inherited his abilities and added to them. For
example, his eldest daughter Window_Help had a paper (bitmap) along with the
drawing board; on that paper, she can draw some information during battle (like
magic and enemy names). Window_Base' second son Window_Gold also had a paper
that could be used to display the amount of gold held by party. Other children
include Window_PlayTime, Window_Steps, Window_BattleResult, etc.
One of
Window Base' children was special. Although Window_Selectable didn't get drawing
papers like his siblings, he got a special ability that allows him to directly
interact with users by providing selectable items. He was able to detect user
input to move the cursor through various items on the drawing board.
Window_Selectable was a sad person because he didn't have paper, but he was
happy to know that his children did have papers and that made them very useful
in both battle and field. The first of his children was Window_Command, which
was a basic selectable window with the ability to draw (has a bitmap) items to
be selected. Examples of command windows would be the "start / load / exit"
window at the title screen, the left menu in the main menu, and the battle menu
(attack, defend, etc.). Window_Selectable had many other children like window
items (you can select items), parts of the equip menu, etc.
What was that
about? It was an introduction to the window classes. At the top there's the
built-in Window class, it has basic properties but no contents bitmap (you need
to create the bitmap yourself, window.contents = Bitmap.new(100, 200)). The
Window Base class adds more drawing methods to the Window class.
Window_Selectable inherits Window_Base but adds the ability to move a cursor
through items. The other windows either inherit Window_Base or
Window_Selectable.
To create your own window, you should also inherit one
of them. If you need a basic window to show some text or images, but without
providing choices, inherit from Window_Base. If you need an interactive window
with choices, inherit from Window_Selectable. Since our About window will only
show some text and offers no choices, our Window_About will inherit Window_Base.
You can find what the default classes inherit from by checking the name in the
class definition, for example 'class Window_Xxxx < Window_Base' means that
Window_Xxxx inherits from Window_Base.
Before actually getting to the
code, note that these two basic windows provide no bitmaps. Bitmaps are like
drawing papers, you can draw text or images on bitmaps. The basic windows
actually have a 'contents' member that is used to represent the bitmap, but it's
empty (nil). Therefore, the only way to draw anything on the window is to create
the bitmap by specifying its size (or an image file to load the bitmap from).
|
|
3. Creating the Window Class
|
|
All you need in a Window class is an initialize method, and a refresh method.
The initialize method sets the basic properties of the class (position, width,
height, etc.) and creates a bitmap. Setting size and position could be done
through a call to the initialize method of Window_Base using the super keyword.
So if you do super(0,0,100,200) you create a window at the upper left of the
screen with a width of 100 and a height of 200 pixels. As for creating the
bitmap, you just assign Bitmap.new(width, height) to your window's contents
(self.contents). Since the window have a border, you'll always need to make your
bitmap 32 pixels smaller in both width and height, or else the bitmap will be
too big for the window. Bitmap.new(width - 32, height - 32) will do that for
you.
As for the refresh method, this is where you draw stuff. Drawing refers to placing stuff at the window, such as text or pictures. You start with
clearing anything already on the bitmap (like erasing stuff on a paper before
drawing) by invoking the clear method of the contents bitmap
(self.contents.clear). After that you can use the draw_text method to draw any
text you need. The syntax for draw_text is: draw_text(x, y, width, height,
string), you can also add an extra number after string to specify how the text
is aligned. x and y set the position of text on the bitmap, where 0,0 is the
upper left pixel and bitmap width, bitmap height is the lower right pixel. width
and height parameters specify the size of the 'text box' that the text is drawn
in. If the string is longer than the width then it will be cut off. Finally,
string is the text you want to draw. The draw_text method is part of the bitmap
class, so it's called from the bitmap (self.contents.draw_text(x, y, width,
height, string)).
Open a new project in RMXP, go to the Script Editor
and right click on Arrow_Base (right under Window_DebugRight). Select Insert
(the first item) in the drop down menu, a new empty code section will be
creating it. Select the empty section and call it Window_About (type the name in
the text box under the scripts list to the left). Inside the empty page to the
right, type the following:
# Class Window_About inherits from Window_Base
class Window_About < Window_Base
# The initialize method.
# Called when the Window_About window is created.
def initialize
# First set the window size by calling the initialize
# method of window base with a size of 640 * 480
super(0, 0, 640, 480)
#Then create the contents bitmap. The width and
# height are set to windiw width - 32 and height - 32
self.contents = Bitmap.new(width - 32, height - 32)
# Call the refresh method to draw text
refresh
end
# The refresh method.
# Called to draw stuff on the contentsbitmap.
def refresh
#Clear any existing contents.
self.contents.clear
# Draw some text at the given position,
# refer to the previous paragraph for more info.
self.contents.draw_text(0, 0, 200, 32, "About My Game")
self.contents.draw_text(0, 32, 200, 32, "1. My game is the best.")
self.contents.draw_text(0, 64, 200, 32, "2. It's better than yours.")
self.contents.draw_text(100, 200, 200, 32, "Monkeys rule!")
end
#This end closes the class definition block
end
|
|
|
4. Creating the Scene Class
|
|
We also need two methods for the scene class. main and update. The main method
will be called when we enter the About scene. You need to have some sort of loop
in main to update graphics and input. This can be done using the simple do loop
which keeps looping until you break out of it. And the condition for breaking
will be changing the scene (like going back to main menu). Before entering the
loop, we need to use a transition to make the new window appear in a smoother
way, this is done using Graphics.transition. Graphics is a module that controls
RMXP's graphic engine, it has several methods such as transition and update. We
also need to create the Window_About object before the loop. Creating a window
calls the window's initialize method and then shows the window. Once inside the
loop, you update the Graphics and Input, if you don't do it then nothing you
draw will be shown and the scene won't respond to input (you'll be stuck in an
infinite loop!). After that the update method is called, then a check is made to
see if the scene changed (user pressed the cancel key). If the scene isn't equal
to Scene_About (self), then we break out of the loop. Once out we freeze the
graphics (must be done before doing a transition, which the next scene will do
before its main loop), freezing the graphics simply stops any drawing during the
transition. Finally, the Window_About object that we created must be disposed.
Disposing means removing it from memory and erasing the window.
The update method is called in each iteration of the main loop. The Scene_About
update method just checks if the cancel key (B) is pressed, if it is, the cancel
system sound is played, and the scene is changed back to the main menu. Changing
the scene is creating a new scene using Scene_Xxxx.New and assigning it to the
$scene global variable. In this case, $scene = Scene_Menu.new(6) will do the
trick. The number 6 is just there to tell Scene_Menu that we need the menu
cursor at item index 6, which will be the About item. If you omit the number
(just Scene_Menu.new), the cursor will be at the first menu item by default, I
suggest you try it to see what I mean.
Go to the Script Editor and right
click on Main (the last item in the scripts list). Select Insert (the first
item) in the drop down menu, a new empty code section will be create it. Select
the empty section and call it Scene_About (type the name in the text box under
the scripts list to the left). Inside the empty page to the right, type the
following:
class Scene_About
#The main method.
# This method has the main loop which updates
# graphics and input, it also calls the update method.
def main
# Create a Window_About object called @about_window
@about_window = Window_About.new
# Perform a transition
Graphics.transition
# Loop forever
loop do
# Update graphics
Graphics.update
# Update input
Input.update
# Call the update method
update
# If the current scene isn't Scene_About
if $scene != self
# Exit the loop
break
end
end
# Freeze the graphics (prepare for transition)
Graphics.freeze
# Get rid of @about_window
@about_window.dispose
end
# The update method.
# Checks if cancel is pressed and exits this scene
def update
# If the cancel key (B) was pressed...
# Input::C = Decision Key, Input::B = Cancel key
# Inpit::LEFT = Left key, Input::Up = Up key etc.
if Input.trigger?(Input::B)
# Play the cancel sound effect
$game_system.se_play($data_system.cancel_se)
# Exit this scene by setting $scene to Scene_Menu
# 6 means the cursor should be at the 7th menu item
$scene = Scene_Menu.new(6)
end
end
#This end closes the class definition block
end
|
|
|
5. Adding the 'About' item to the Main Menu
|
|
1. In the script editor, click on Scene_Menu from the list to the left. 2. In
the main method, find the following lines:
s1 = $data_system.words.item
s2 = $data_system.words.skill
s3 = $data_system.words.equip
s4 = "Status"
s5 = "Save"
s6 = "Exit"
|
3. Add the following line after (s6 = "Exit"):
4. Change the next line (@command_window = Window_Command.new(160, [s1, s2, s3,
s4, s5, s6])) to:
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6, s7])
|
What you just did what add a new item to the command window that is used to hold
the menu items. The initialize method of Window_Command takes the width of the
command window and an array of strings as a parameter. Each string will
represent one menu item. So, we add a new string called s7 and set its value to
"About", then we add it to the arguments passed to Window_Command's initialize
method.
5. We're not done yet, we need to decide what happens when 'About' is
selected. Scroll down in Scene Menu and go to the update_command method. You'll
see a case statement with lots of when's. Find the last when:
when 5 # Japanese stuff
# Blah SE blah
$game_system.se_play($data_system.decision_se)
# Blah
$scene = Scene_End.new
|
6. Add the following right after $scene = Scene_End.new:
when 6
$game_system.se_play($data_system.decision_se)
$scene = Scene_About.new
|
Make sure there is an 'end' after the code you just added. This code simply
checks if the 7th item was pressed (index 6), plays the decision sound effect
and then changes the scene to scene about.
And that's it, run the game,
go to menu, choose 'About' and the new menu should be shown. Press escape to
exit.
|
|
6. Annoying Play Time Window
|
|
You might notice that the play time window is over the About option. The easiest
way to fix it would be to go to Window_PlayTime and make it smaller by getting
rid of the text over the game time.
1. Find the following line in the main
method of Scene_Menu:
@playtime_window = Window_PlayTime.new
@playtime_window.x = 0
@playtime_window.y = 224
|
2. Change the last line to:
This shifts down the playtime window a bit.
3. Go to the Window_PlayTime
script, find the following line in the refresh method:
self.contents.draw_text(4, 0, 120, 32, "Time")
|
(The text for "time" could be different in your RMXP version, it could be "Play
Time", "Game Time", something like that)
4. Delete that line. 5. Find the
last line in Window_PlayTime refresh method (self.contents.draw_text(4, 32, 120,
32, text, 2)) and change it to:
self.contents.draw_text(4, 0, 120, 32, text, 2)
|
What you did is delete the "time" text" and shift the time text up (y is 0
instead of 32 in draw_text).
6. In the initialize method of Window_PlayTime,
change super(0, 0, 160, 96) to:
Doing so makes the play time window smaller.
7. That's it, test the game now. :)
If the text doesn't show for some reason, add the following
line somewhere in main (last script section). Just put it before the loop...
Font.default_name = "Arial"
|
You could have any font name instead of "Arial"...
The final product:

|
|
7. Conclusion
|
|
Whew, finally done. I know this tutorial might seem complicated at first, but
you don't need to understand everything. It just gives you a general idea about
windows and scenes. You can change the about menu to display everything you
like. You can also examine other scenes and windows to see how they are coded. I
hope this tutorial was useful for you.
|
|
8. Summary
|
|
1. No, I'm tired.
|
 |
More in the 'RGSS For Dummies' series:
• RGSS For Dummies Tutorial 1: The Basics
• RGSS For Dummies Tutorial 2: Variables
• RGSS For Dummies Tutorial 3: Control Flow
• RGSS For Dummies Tutorial 4: Containers and Methods
• RGSS For Dummies Tutorial 5: Object Oriented Programming and More!
• RGSS For Dummies Tutorial 6: Game Programming 101
• RGSS For Dummies Tutorial 7: Windows for Dummies |
|