Creating a Custom Window by RPG Advocate - Printable Version +- Save-Point (https://www.save-point.org) +-- Forum: Games Development (https://www.save-point.org/forum-4.html) +--- Forum: Tutorials (https://www.save-point.org/forum-19.html) +--- Thread: Creating a Custom Window by RPG Advocate (/thread-2893.html) |
Creating a Custom Window by RPG Advocate - DerVVulfman - 03-11-2009 Creating a Custom Window
by RPG Advocate saved from Phylomortis.Com Introduction 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. Here we go 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 CODE 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 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 CODE 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 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 CODE 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. Code Sample 4 CODE 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. |