BASIC WINDOW MANIPULATION

A shot at teaching the basics of Window Manipulation in RGSS3

This tutorial aims to make customizing windows accessible to everyone; at least, as much as I can manage.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Basic requirements: You're going to need VXAce, obviously. You'll also need patience. A lot of that, since you'll be editing, playtesting, adjusting, and fine-tuning over and over and over until you get the layout correct. Also, this tutorial is a huge wall of text. You've been warned people.


Tutorial Proper


Before I dive into the Script Editor, I'll define a few basic stuff first. Just a painfully excruciating, short and sweet primer.

"Short" Primer
Most windows are created by specifying four values to it: X, Y, Width, and Height.

X and Y defines the location of where the upper-left corner of the window will be placed on the screen. X is horizontal, and Y is Vertical. In VXA, the upper-left corner of the screen is (0, 0).

Width and Height defines the size of the window.

To visualize this, say we have a window that starts at (1, 2) and has a size of (4, 2).

..01234567
.##########
0#........#
1#.@@@@...#
2#.@@@@...#
3#........#
4#........#
.##########


It should appear as something like this, Where the #'s are the borders of the screen, the numbers show the coordinates, and the @'s is the newly created window. Got that? Err... I'll take that as a yes then.

The actual script for the previous window should look like this:
def my_first_window
  @my_first_window = Window_MFW.new(1, 2, 4, 2) #Comment: Remember! the order is = (X, Y, Width, Height)
end

No need to worry about this right now, of course. This is just an example. As you can see, it's all a matter of assigning the right values to the right places. Just be careful not to mix up your numbers!

Constants: Graphics.width and Graphics.height
That done, let's talk about constants. Constants are values that are unchangeable (by the user) and are determined by the game. Two constants are extremely useful in modifying windows. These are: 'Graphics.width' and 'Graphics.height'. These two will give you the Width and Height of the screen respectively.

An application of that; say you want a window that is four units high, centered and at the bottom, and is half as wide as the screen.

If manually done, you're going to have to scavenge for the width of the screen, divide it by two, and then manually adjust the window's X and Y so that it will be centered and at the bottom, without going out of the screen. Too much work right?

Graphics.width and Graphics.height saves you the trouble by automatically getting the width and height of the screen. So how do you use it? Here's how:

I'll use 'my_first_window' here again.
def my_first_window
  @my_first_window = Window_MFW.new(Graphics.width / 4, Graphics.height - 4, Graphics.width / 2, 4)
end

Whoa, whoa, whoa. Where'd all that come from?
Don't worry, I'll explain this bit by bit. Remember that the order of the values is (X, Y, Width, Height).

Let's start with the Width and the Height. The width is half as wide as the screen, right? And Graphics.width is the width of the screen. So I simply divided Graphics.width by two. The height is four units, so it's easily just placing a '4' there.

Now for the X and Y. You might ask, where in the world I got all those. 'Graphics.width / 4' is derived from 'Graphics.width / 2', or the Width of the window. As was stated, the width of the window is half the size of the screen. Since I want the window to be centered, you're going to have to calculate just how much you should put to X so that the space to the left and to the right of the window is equal.

Say the width of the screen is '8' units. Since the window is half the width of the screen, it's width will be '8 / 2' or '4'. Let each '( )' be empty units, and each '(@)' are the units occupied by the window.
(@)(@)(@)(@)( )( )( )( )
Here, X = 0

Empty units to the (L)eft and to the (R)ight of the window:
L = 0, R = 4; L != R

To center that, we are going to need a certain number that will make the empty units in the left of the window equal to those in the right. First thing we do, is calculate the number of empty units that we can work on. It can be found by subtracting the window's width from the screen's width, or '(Graphics.width - Window Width)'.

For the said window, it is 'Graphics.width - (Graphics. width / 2)' which is simply 'Graphics.width / 2'. Next, we need to divide the result by two, so that the values will be equally distributed to both sides. So it will be: '(Graphics.width / 2) / 2', which is equal to 'Graphics.width / 4'.
( )( )(@)(@)(@)(@)( )( )
Here, X = 8 / 4, or 2

Empty units to the (L)eft and to the (R)ight of the window:
L = 2, R = 2; L = R

Voila! Centred perfectly!

Now for the Y. To make a window sit at the bottom of the screen, all you have to do is subtract the window's Height from the height of the screen, or: 'Graphics.height - Window Height'. The window's height is '4', so it'll be 'Graphics.height - 4'.

And that pretty much covers the logic behind creating windows.


Modifying an actual window: Title Command
If you've been using Ace for at least 30 minutes or so, I'm sure you're already bored of the same old, static command window you see in the game's title screen. Here's a remedy to that.

This is the original Window_TitleCommand. You can find it under 'Windows' using the script editor (F11).
#==============================================================================
# ** Window_TitleCommand
#------------------------------------------------------------------------------
#  This window is for selecting New Game/Continue on the title screen.
#==============================================================================

class Window_TitleCommand < Window_Command
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    super(0, 0)
    update_placement
    select_symbol(:continue) if continue_enabled
    self.openness = 0
    open
  end
  #--------------------------------------------------------------------------
  # * Get Window Width
  #--------------------------------------------------------------------------
  def window_width
    return 160
  end
  #--------------------------------------------------------------------------
  # * Update Window Position
  #--------------------------------------------------------------------------
  def update_placement
    self.x = (Graphics.width - width) / 2
    self.y = (Graphics.height * 1.6 - height) / 2
  end
  #--------------------------------------------------------------------------
  # * Create Command List
  #--------------------------------------------------------------------------
  def make_command_list
    add_command(Vocab::new_game, :new_game)
    add_command(Vocab::continue, :continue, continue_enabled)
    add_command(Vocab::shutdown, :shutdown)
  end
  #--------------------------------------------------------------------------
  # * Get Activation State of Continue
  #--------------------------------------------------------------------------
  def continue_enabled
    DataManager.save_file_exists?
  end
end

Let's break it down, piece by piece.

First off, All text after a Pound Sign '#' are comments. Comments are blocks of text that is not executed or run by the program. You'll find that comments are generally used to provide some information about what a certain block of code does. They can also be used to nullify or 'comment out' a line or lines of code, so that they will not be run. This is useful, especially if your directly editing the default scripts (like what we're going to do). I'll explain more later.

Next, is the 'Class Window_TitleCommand < Window_Command'. This defines the name of the class, and the class that it is under. Think of classes as Boxes. Window_TitleCommand is a box that contains the Title Command Window and its settings; while Window_Command is a Box that contains the Window_TitleCommand Box, along with several other Boxes that are present in the default script.

Then we have the functions. Functions are simply either a set of commands, or a definition of a certain variable. Functions in Ruby follow this format:
def <name of the function>
. <stuff that the function does>
end


In RGSS3, all functions are labeled by comment headers. These are (thankfully) written in plain english (most of the time). So you just have to read the headers, and you'll most likely know what it does.


Now, off to modifying!

If you've noticed, everything is already out in the open and ready for you to modify.

The function 'window_width' returns the width of the window.

The function 'update_placement' sets the X and Y of the window.

'make_command_list' sets the commands that appear on the window.

'continue_enabled' asks 'DataManager' if a save file exists. If it does, then the continue command is enabled; otherwise, it is disabled.

If you have noticed, there is no function for the window's height. This is because the window's height is automatically adjusted based on the number of commands you put in. You can, of course, change it if you so wish.

Since 'window_width' is self-explanatory, I'll skip ahead to update_placement.

'self.x' here automatically centers the window (whose process I have explained earlier). If you wish to change this, I suggest you comment it out instead of straight-up erasing it, in case you want to revert things back to normal.

The same goes for 'self.y', apparently.

A small note, the height of a line (the area in the window that a line of text occupies) is '24'. So the default 'TitleCommand' is '24 * (number of commands + 1)', where the extra '24' is the window padding (space between the text and the border of the window). Again, this is the default value.


So I assume you've already moved the title command window to some sleek corner, and resized it to your heart's desire. Now say, you want to go an extra step further. Say, you want the title command window to have a special, separate look from the rest of the windows in your game. Guess what, it's easy to do so!

First thing you do, is have the window skin ready. If you don't know what that is, open up the resource manager (F10) and go to Graphics/System. You'll find a window.png there. That is the window skin. Export it, and modify it using your favourite image editor. Then name it whatever you like, except the name of the window that you will use for the rest of the game (If you're sticking with the default, just don't name it 'window'. Or else, it will replace the window skin for ALL of the windows in the game.). Then, put it on your game's Graphics/System folder.

Done? Here's how you'll make it work. Under initialize, insert this line anywhere within the function:

self.windowskin = Cache.system("Name_of_Special_Window_Skin")


See? It isn't that hard right?


Final Notes
I hope this tutorial helped you gain some form of understanding of how windows work in Ace, and I hope that this tutorial has enabled you to, you know, make a game that's more custom and personal.

Thanks for sticking with it 'till the end!
~Karin's Soulkeeper