|
This tutorial explains how to create custom windows for your game using RGSS. The example used in this tutorial is of a window that shows a custom window when you acquire an item.
The first thing you should know about creating a custom window is that in order
to look like all the other windows in your game, your new window class should
inherit from Window_Base (or Window_Selectable if the user is supposed to select
something in the window). In this case, I've inherited from Window_Base, since
this window is designed to simply show information. The skeleton of your window
should look something like the one in Code Sample 1. The image below the code
sample shows what you get when you show this skeleton window. In this case, the
Initialize function takes two arguments, one for the type of item to be
displayed (item, weapon, or armor), and the other for the ID of the item within
that category. The first statement in the Initialize function should always be a
call to super (comment 1 in Code Sample 1). The four arguments are, from left to
right, the X coordinate of the window's upper-left pixel on the screen, the Y
coordinate of the window's upper-left pixel on the screen, the width of the
window in pixels, and the height of the window in pixels. The second thing you
should notice is that when a window is initialized, the last statement should
always be a call to the window's Refresh method (comment 2 in Code Sample 1), so
the window's contents have been initialized (at this point, the window is just
empty). Finally, for this example, the type and ID instance variables are
attr_accessors, since we are going to have to be able to set them and compare
with them when the window is inserted into the Scene_Map class (comment 3 in
Code Sample 1).
Code Sample 1
class Window_ItemGet < Window_Base
# ------------------------
attr_accessor :type # 3
attr_accessor :id
# ------------------------
def initialize(type, id)
super(220, 180, 220, 96) # 1
self.contents = Bitmap.new(width - 32, height - 32)
self.back_opacity = 255
self.contents.font.name = "Arial"
self.contents.font.size = 18
@type = type
@id = id
refresh # 2
end
# ------------------------
def refresh
self.contents.clear
end
# ------------------------
def update
super
end
end
|

Skeleton window created from code in Code Sample 1
The next step is to put the information we want to show in the window's Refresh
function. The first statement in almost any refresh method should be to clear
the window's contents. Since we want the text to show in the normal color, the
font color is first changed to the normal color. In the case of this example, I
want the word "Acquired" to always show on the first line. To draw any string
within a window, you can use the self.contents.draw_text method. The five
parameters, from left to right, are the X coordinate within the window bitmap to
draw the text, the Y coordinate within the window bitmap to draw the text, the
width of the space alloted for the text, the height of the space allotted for
the text, and the text itself. What appears below the word "Acquired" depends on
the type and ID instance variables. The three "if" statements determine which
type of item I'm dealing with. If the type is 1, I'm dealing with an item. If
the type is 2, I'm dealing with a weapon. If the type is 3, I'm dealing with a
defensive item. Once I know which type of item I'm dealing with, I use the
Window_Base#draw_item method to draw that item's icon and name. The code for all
this is shown in Code Sample 2. The picture below Code Sample 2 shows what
happens when I show the window with a weapon called "Sword of Scripting".
Code Sample 2
def refresh
self.contents.clear
self.contents.font.color = normal_color
self.contents.draw_text(4, 0, 180, 32, "Acquired")
if @type == 1
self.draw_item_name($data_items[@id], 4, 32)
end
if @type == 2
self.draw_item_name($data_weapons[@id], 4, 32)
end
if @type == 3
self.draw_item_name($data_armors[@id], 4, 32)
end
end
|

Window after filling in the Refresh method
The next step is to plug the window into the Scene_Map class so that it can be
displayed when the player acquires a new item. The first thing that needs to be
done is change the Main function so that the proper variables are initialized.
The Main function for Scene_Map is shown in Code Sample 3, with the changes from
the default highlighted in red. The first thing to notice is that a new instance
variable, @acquire_window, has been added. This is an instantiation of the class
just defined above (comment 1 in Code Sample 3). Since we don't want it to show
until we want to use it, the new window's visibility is set to false (comment 2
in Code Sample 3). The "@itemdelay" instance variable will be used later to tell
the class how long to show the item window (comment 3 in Code Sample 3). The
"@item_acquired" instance variable will be used to feed the type and ID of the
item to the window (comment 4 in Code Sample 3). We need to be able to modify
this array from outside the class, so it is made an attr_accessor (comment 5 in
Code Sample 3). Finally, any new windows placed in a Scene should have a dispose
statement placed at the end of the Main method (comment 6 in Code Sample 3).
Code Sample 3
class Scene_Map
# ---------------------
attr_accessor :item_acquired # 5
# ---------------------
def main
@spriteset = Spriteset_Map.new
@message_window = Window_Message.new
@acquire_window = Window_ItemGet.new(1, 0) # 1
@acquire_window.visible = false # 2
@itemdelay = -1 # 3
@item_acquired = [0, 0] # 4
Graphics.transition
loop do
Graphics.update
Input.update
update
if $scene != self
break
end
end
Graphics.freeze
@spriteset.dispose
@message_window.dispose
@acquire_window.dispose # 6
if $scene.is_a?(Scene_Title)
Graphics.transition
Graphics.freeze
end
end
|
In order to manage actually showing the window, the Update method of the
Scene_Map class needs to be changed. The changes to the class are shown in red
in Code Sample 4 (the entire method isn't shown). The changes are set up so that
only a couple of scripting commands are required to make the window appear, and
the Scene_Map class takes care of making it disappear after a few seconds. When
event commands like the ones shown in the image below are used, it triggers the
statement at comment 1 in Code Sample 4, refreshing the item acquisition window
and making it visible. It also sets the @itemdelay instance variable to 125,
meaning that the window should stay visible for 125 frames. The statement at
comment 2 in Code Sample 4 decrements @itemdelay each frame. The statement at
comment 3 makes the window invisible and resets @itemdelay to the sentry value
of -1. The type and ID of the item to show are reset to 0, to wait for the next
time the item acquisition window needs to be shown.

Making the Item Acquisition window appear
Code Sample 4
def update
loop do
$game_map.update
$game_system.map_interpreter.update
$game_player.update
$game_system.update
$game_screen.update
unless $game_temp.player_transferring
break
end
transfer_player
if $game_temp.transition_processing
break
end
end
@spriteset.update
if @itemdelay > 0
@itemdelay -= 1 # 2
end
if @itemdelay == 0 # 3
@itemdelay = -1
@acquire_window.visible = false
@item_acquired[0] = 0
@item_acquired[1] = 0
end
@message_window.update
if @item_acquired[0] != 0 &&
@item_acquired[1] != 0 && @itemdelay < 0 # 1
@acquire_window.type = @item_acquired[0]
@acquire_window.id = @item_acquired[1]
@acquire_window.refresh
@acquire_window.visible = true
@itemdelay = 125
end
[...]
|
Which scene you need to modify will depend on where you want the window to
appear and what you're using it for. The steps above are, however, generally
applicable to any information window you might want to make. Windows from which
the user must select a command are a bit more complicated, and will be covered
later.
|