Adding A Window to a Scene
Part One: Scene_Map
This time, we're going to do something you might actually use one day.
This is the minigame I've created:

Little Cecelia dropped her evil uncle's coin collection down a drain in his mansion. Now she needs to find them all and pick them up before he finds out she lost them! Unfortunately, her twisted uncle has a dangerous maze underneath his house. Cecelia needs to navigate the maze in under the time limit and pick up all the coins without falling off a ledge. Falling down costs her 10 HP. Feel free to download the game I'm linking at the end of the lesson and check out the events.
So we're going to need a new window, aren't we? Let's open up the script editor, and insert a new one named Window_HUD.
CODE
class Window_HUD < Window_Base
end
end
So far, so good. You should recognize this from last lesson.
CODE
class Window_HUD < Window_Base
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
end
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
end
A little bit more meat than our last window, no? Let's go over the new stuff.
CODE
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
@actor = $game_party.actors[0]
Remember when I said $ indicates a global variable? $game_party is a global variable that contains a Game_Party object. Among other things, Game_Party keeps an array (numbered list of objects) of all the actors in your party named actors. So $game_party.actors[0] gets the first person in the party. Arrays are 0-based, which means that the object at the first position is always at index 0. It takes some getting used to, I know.
The @ symbol indicates that the variable is an "instance variable." In plain English, that variable belongs to Window_HUD, and no one outside Window_HUD can see it. So our Window_HUD object will always know what actor it's supposed to be looking at.
CODE
# current hp of actor
@hp = @actor.hp
@hp = @actor.hp
This is how much HP the lead actor has. If you look at the Game_Actor class:
CODE
class Game_Actor < Game_Battler
Game_Actor is decended from Game_Battler. And Game_Battler has the following:
CODE
attr_reader :hp # HP
Attr are a special way of allowing things outside the class to access the class's instance variables. This is the only way anyone else can read or write to them. There are three types: attr_reader (read only, can't change), attr_writer (write only, can't see it), and attr_accessor (read or write). So if we were to change our class above to:
CODE
class Window_HUD < Window_Base
attr_accessor :actor
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
end
attr_accessor :actor
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
end
Then somewhere outside of this class we could do this:
CODE
@hud_window = Window_HUD.new
@hud_window.actor = $game_party.actors[2]
@hud_window.actor = $game_party.actors[2]
Which would change the @actor instance variable to point to the third (remember, 0-based!) actor in the party.
All of that means to say we just got the actor's current hp and stored it in an instance variable named @hp.
CODE
# current number of coins
@coins = $game_variables[1]
@coins = $game_variables[1]
Remember those variables you set in events? $game_variables stores them all. So $game_variables[1] is the same as Variable 0001 in the event editor. So we've just taken whatever number is in variable 1, and put it in the instance variable @coins.
CODE
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
This is how you draw an image on the window. The first line gets the bitmap of the image. I've imported an icon named hp.png and coins.png in the game. RPG::Cache gets the image and caches it for easier loading, the icon() method tells it to get something from the icon folder. For a list of RPG::Cache's methods, go to the help file and go to RGSS Reference Manual -> Game Library -> RGSS Built-In Modules -> RPG::Cache. There's a method for each type of resource. You can even add methods to it, but that's a lesson for another day.
The blt() (block transfer) method draws a bitmap on another bitmap (in this case, the window's bitmap).
This is the help file's description of blt:
QUOTE
blt(x, y, src_bitmap, src_rect[, opacity])
Performs a block transfer from the src_bitmap box src_rect (Rect) to the specified bitmap coordinates (x, y).
opacity can be set from 0 to 255.
Performs a block transfer from the src_bitmap box src_rect (Rect) to the specified bitmap coordinates (x, y).
opacity can be set from 0 to 255.
Not all that helpful, is it?
x and y are the coordinates on the bitmap (window) to draw the new bitmap on. 0, 0 would be the upper left corner. src_bitmap is the bitmap to draw, in this case, the icon we just loaded. src_rect is trickier. This tells the interpreter how much of the bitmap to draw. Since my icon is 24x24 pixels, I've told it to draw a rectangle that starts at 0, 0 (upper left) and is 24 pixels wide and 24 pixels tall. In other words, the whole icon. However, I could just as easily done this:
CODE
Rect.new(12, 12, 12, 12)
Which would only draw the lower right 12x12 pixels, or this:
CODE
Rect.new(0, 0, 24, 1)
Which would only draw the very top row of 24 pixels.
Not that useful with icons, but this is how you can show just one frame of a characterset, among other uses. We may cover this later.
Opacity is optional. If you don't enter anything, as we have, it's assumed to be 255, or completely opaque. You can choose to enter a number between 0 (completely transparent, or invisible) and 255 if you wish. It could look like this:
CODE
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24), 160)
CODE
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
This is similar to what we did before, drawing some text on the screen. The only difference is that we're trying to draw a number, so we have to convert it to a string, first. the to_s() method takes a numerical object, like 50, and turns it into a string, '50'.
Okay, so now we have a basic window. Let's add it to the scene. Open up the script editor and click on Scene_Map. Find this line:
CODE
# Make message window
@message_window = Window_Message.new
@message_window = Window_Message.new
Right after it, add:
CODE
@hud_window = Window_HUD.new
We've now created a new window. But don't forget, we need to dispose it eventually! In the case of scenes, windows are disposed when the scene changes from one to another. You'll usually find them shortly below the main loop. Look for this line:
CODE
@message_window.dispose
and add below it:
CODE
@hud_window.dispose
Now we have a window that shows up directly on the map and is automatically disposed whenever the player enters the menu, battle, or any other scene. But wait! It doesn't do anything! No matter how the player's hp changes or how many coins he picks up, the HUD stays static. That can't be right.
We're going to add a method called update(). Update is a method intended to be called every frame.
CODE
class Window_HUD < Window_Base
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
# run each and every frame
def update
# only refresh if something has changed. Prevents lag.
if (@hp != @actor.hp) or (@coins != $game_variables[1])
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# do anything the parent windows need to do each frame
super
end
end
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
# run each and every frame
def update
# only refresh if something has changed. Prevents lag.
if (@hp != @actor.hp) or (@coins != $game_variables[1])
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# do anything the parent windows need to do each frame
super
end
end
Let's take a closer look at this new method:
CODE
# only refresh if something has changed. Prevents lag.
if (@hp != @actor.hp) or (@coins != $game_variables[1])
if (@hp != @actor.hp) or (@coins != $game_variables[1])
This is a conditional branch (yes, like the ones in the event editor). Like the ones in the event editor, it tests to see if something is true, and does something inside it if it is. The != means "not equal", so what this is saying is if the hp we stored isn't equal to the current hp or the number of coins we have stored isn't equal to the actual number we have picked up then do something. We could do without this and just refresh every frame, but that's a sure-fire way to cause lag. Only refresh your window if something on it changed.
CODE
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
We reset our instance variables to the true current values in preparation to redraw them, then refresh.
CODE
# do anything the parent windows need to do each frame
super
super
Like the super in initialize, this calls the same method in the parent class. In this case, it's calling update in Window_Base.
Now we have an update method, but we need to set it up so it's called every frame. Head back to Scene_Map, and look for this line:
CODE
@message_window.update
and add this below it:
CODE
@hud_window.update
Now we almost have it, we just need a few refinements. First, we only want the window to show up during the minigame. Second, we want the window to be semi-transparent so the player can see what's behind it.
CODE
class Window_HUD < Window_Base
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# don't show this window by default
self.visible = false
# make the window semi-transparent so the player can see what's behind it
self.opacity = 160
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
# run each and every frame
def update
# we're only visible if this switch is on
self.visible = $game_switches[1]
# don't update if we can't see the window. Prevents lag.
if !self.visible
return
end
# only refresh if something has changed. Prevents lag.
if (@hp != @actor.hp) or (@coins != $game_variables[1])
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# do anything the parent windows need to do each frame
super
end
end
def initialize
super(0, 0, 110, 96)
self.contents = Bitmap.new(width - 32, height - 32)
# don't show this window by default
self.visible = false
# make the window semi-transparent so the player can see what's behind it
self.opacity = 160
# get the first actor in the party to display their data
@actor = $game_party.actors[0]
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# clear the window and redraw it
def refresh
self.contents.clear
# draw the hp icon on the window
bitmap = RPG::Cache.icon('hp')
self.contents.blt(0, 4, bitmap, Rect.new(0, 0, 24, 24))
# draw the actual HP of the actor
self.contents.draw_text(32, 0, 96, 32, @hp.to_s)
# draw the coin icon on the window
bitmap = RPG::Cache.icon('coins')
self.contents.blt(0, 36, bitmap, Rect.new(0, 0, 24, 24))
# draw the variable holding the number of coins
self.contents.draw_text(32, 32, 96, 32, @coins.to_s)
end
# run each and every frame
def update
# we're only visible if this switch is on
self.visible = $game_switches[1]
# don't update if we can't see the window. Prevents lag.
if !self.visible
return
end
# only refresh if something has changed. Prevents lag.
if (@hp != @actor.hp) or (@coins != $game_variables[1])
# current hp of actor
@hp = @actor.hp
# current number of coins
@coins = $game_variables[1]
refresh
end
# do anything the parent windows need to do each frame
super
end
end
Let's look at the changes.
CODE
# don't show this window by default
self.visible = false
self.visible = false
This "hides" the window. The method visible is actually not in Window_Base, but in Window_Base's parent class, Window. Window is a hidden class, but you can find a list of its methods in the Help file under RGSS Built-In Classes. Since Window_HUD is descended from Window, it can do anything Window can do.
CODE
# make the window semi-transparent so the player can see what's behind it
self.opacity = 160
self.opacity = 160
This makes the window semi-transparent. Feel free to play with transparencies until you get a feel for what's too transparent and what's not.
CODE
# we're only visible if this switch is on
self.visible = $game_switches[1]
# don't update if we can't see the window. Prevents lag.
if !self.visible
return
end
self.visible = $game_switches[1]
# don't update if we can't see the window. Prevents lag.
if !self.visible
return
end
Like $game_variables, $game_switches keeps all of the switches you use in the event editor. Switches are "booleans", which means they're either true or false (corresponding to on or off). The first line sets the visibility to the first switch (which I turn on when the minigame begins). In other words, if switch 1 is on, the window is visible. If it's off, it's not.
The next line is another lag prevention technique. The ! means not, so this says: If I'm not visible, then return. Return is a special keyword that tells the interpreter to exit the current method without looking at any of the code below it. You can also return a value, which we'll probably get into later. For now, all you really need to know is that this will exit the method without checking the number of coins or hp, saving on calculations.
Homework
Make a simple HUD that shows HP, SP, and gold. Or any other 2-3 values you choose. You can use plain text or icons. Hint: get the party's current gold via $game_party.gold.
Demo So Far
http://www.pcis-studios.com/ccoa/Window%20Demo.exe





