- Joined
- Jul 4, 2021
- Messages
- 81
- Reaction score
- 267
- First Language
- Catalan
- Primarily Uses
- RMXP
On this tutorial, I will talk in detail about the Windowskins in RPG maker XP.
The Windowskin is the graphic used to draw the windows that appear in the game.
PART 1. Parts of the Windowskin
Here you can see the limits of each part of the graphic
A. This part is the back of the windowskin.
B. This part is the frame of the window.
C. Those are the scroll arrows that appear on item lists.
D. This part is the cursor.
E. Those little squares are each one of the 4 frames of that little icon that appears at the bottom of the message window. That icon is called pause.
F. Those are the 2 frames of the battle arrow that appears over the sprites when you pick them.
The display of most of those parts (A-E) is defined in the internal class Window, and that means you can't access the code that controls how they're displayed, but don't lose your hope; you can overwrite that class with a RGSS script, paste it over Main and customize that one instead.
The last arrows (F) have their own non-internal class called Arrow_Base. Even if they are on the same graphic, it may be easier to consider they're not part of the window themselves.
Something I want to highlight about the template is that, as you can see, the cursor actually has a small border around it that is not stretched, unlike the central part. I'll talk a bit more about this later.
It doesn't matter how big the cursor is, the border mantains its thickness.
PART 2. Windowskin properties
The window has some properties that define how those parts are displayed.
Some can be modified (for example the window's opacity), but others are internal.
Modifiable:

Non modifiable:

PART 3. Stretch and tiling
When the window is bigger that the graphic, some parts of the graphic are stretched and some tile until they fill all that plane.
On this example, the parts I painted with green blinds aren't stretched, but those with grey blinds are.
You can change the back stretch mode with a little script over Main, that changes the "stretch" variable commented before. That means you can also change that on each window independly or based on the current windowskin.
In summary, the back has no border and its stretch depends on a variable, frames have a 16px border and don't stretch, and the cursor has a 2px border and stretches.
PART 4. RGSS Rewrite of the Window Class
In order to modify some of the window properties more freely, you can use a script that overwrites the window methods in RGSS. That makes their displaying a bit more slow, but we have much more control over them. There are many scripts that overwrite that class, but since I'm as cool as a cucumber I've made one specially for this tutorial, free to use. I used Selwyn's rewrite as a reference.
PART 5. Script adaptations
The Window script posted above defines in a single method the drawing of the sprites (used as a shortcut), this way it's easier to customize it taking into account both the border and the stretch mode.
That property is defined in Back, Frames, Cursor, and finally in Blind if you're using the Window Blind Add-On (see below).
It's also possible to change the cursor's windowskin independently, using cursor_rect.skin = name
Examples:
self.cursor_rect.skin = "001-Blue01"
@window.cursor_rect.skin = "Dark_Skin"
This dynamic cursor skin can be useful if you want to change it based on a condition (for example, when the current choice is disabled).
Therefore, we can make other basic changes, implemented as "AddOns" below this base script.
The method update_pause defines how the pause graphic is loaded. There you can change it easily so that graphic is loaded using an independent graphic instead, for example this one. This way it can be as big as you want, and have more frames.
The method update_cursor defines the blinking of the cursor and its opacity when it's disabled. Disabling its blinking is very simple.
You could also make a cursor with multiple frames as in RM2k/3, to do that you can use the previous script for pause as a reference. Similarly, on the method draw_arrows you can change how the scroll arrows are displayed, in case you want them bigger, or animated, etc.
Inside the methods that define X and Y, you can find these:
@pause_s.x = x + (@width / 2) - 8
@pause_s.y = y + @height - @margin
That controls the position of the pause, so you can easily change it as well, like this:
Now margin is a modifiable property too, but I recommend not changing that.
The method set_arrows defines the position of the scroll arrows, which I don't recommend changing either.
The method draw_back defines how the background is displayed.
It gets the graphic with the rect (0, 0, 128, 128) from the windowskin and then uses this
That 0 is the margin, which means changing it you can make things like this image.

Right after that, the Frame is defined in a very similar way inside the method draw_frame, where m = 16 is the margin.
Changing that to true allows the borders of the frames to stretch, which may be interesting in some cases. You can check it here.
Finally (this is getting long), the last interesting method is get_cursor_sprite, which defines the display of the cursor. The default 2px border is very limiting, so you can now change it to something more wide. You can also make it tile.
As before, all that is defined on this line:
Here's my version
The Windowskin is the graphic used to draw the windows that appear in the game.

PART 1. Parts of the Windowskin
Here you can see the limits of each part of the graphic


A. This part is the back of the windowskin.
B. This part is the frame of the window.
C. Those are the scroll arrows that appear on item lists.
D. This part is the cursor.
E. Those little squares are each one of the 4 frames of that little icon that appears at the bottom of the message window. That icon is called pause.
F. Those are the 2 frames of the battle arrow that appears over the sprites when you pick them.
The display of most of those parts (A-E) is defined in the internal class Window, and that means you can't access the code that controls how they're displayed, but don't lose your hope; you can overwrite that class with a RGSS script, paste it over Main and customize that one instead.
The last arrows (F) have their own non-internal class called Arrow_Base. Even if they are on the same graphic, it may be easier to consider they're not part of the window themselves.
Something I want to highlight about the template is that, as you can see, the cursor actually has a small border around it that is not stretched, unlike the central part. I'll talk a bit more about this later.

It doesn't matter how big the cursor is, the border mantains its thickness.
PART 2. Windowskin properties
The window has some properties that define how those parts are displayed.
Some can be modified (for example the window's opacity), but others are internal.
Modifiable:

Non modifiable:

PART 3. Stretch and tiling
When the window is bigger that the graphic, some parts of the graphic are stretched and some tile until they fill all that plane.


On this example, the parts I painted with green blinds aren't stretched, but those with grey blinds are.
You can change the back stretch mode with a little script over Main, that changes the "stretch" variable commented before. That means you can also change that on each window independly or based on the current windowskin.
Ruby:
class Window
alias stretch_mode_ini initialize unless $@
def initialize(*args)
stretch_mode_ini(*args)
self.stretch = false
end
end
In summary, the back has no border and its stretch depends on a variable, frames have a 16px border and don't stretch, and the cursor has a 2px border and stretches.
Here are some windowskins that will only look good with the stretch mode disabled.






PART 4. RGSS Rewrite of the Window Class
In order to modify some of the window properties more freely, you can use a script that overwrites the window methods in RGSS. That makes their displaying a bit more slow, but we have much more control over them. There are many scripts that overwrite that class, but since I'm as cool as a cucumber I've made one specially for this tutorial, free to use. I used Selwyn's rewrite as a reference.
Ruby:
#==============================================================================
# ** [XP] Window - Hidden RGSS Class
#------------------------------------------------------------------------------
# Author: Wecoc (no credits required)
#------------------------------------------------------------------------------
# I used Selwyn's Window rewrite as reference.
#==============================================================================
#==============================================================================
# * Bitmap
#==============================================================================
class Bitmap
#--------------------------------------------------------------------------
# * Erase
#--------------------------------------------------------------------------
def erase(*args)
if args.size == 1
rect = args[0]
elsif args.size == 4
rect = Rect.new(*args)
end
fill_rect(rect, Color.new(0, 0, 0, 0))
end
#--------------------------------------------------------------------------
# * Cut
#--------------------------------------------------------------------------
def cut(*args)
case args.size
when 1 # (rect)
rect = args[0]
x, y, width, height = *rect.size
when 4 # (x, y, width, height)
x, y, width, height = *args
end
return Bitmap.new(1, 1) if width <= 0 or height <= 0
bitmap = Bitmap.new(width, height)
bitmap.blt(0, 0, self, Rect.new(x, y, width, height))
return bitmap
end
end
#==============================================================================
# * Tiled_Sprite
#==============================================================================
class Tiled_Sprite
attr_reader :bitmap, :skin, :margin, :stretch
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize(bitmap, m=1, stretch=true)
w = bitmap.width
h = bitmap.height
@margin = m
@stretch = stretch
@skin = {}
@skin[7] = bitmap.cut( 0, 0, m, m)
@skin[9] = bitmap.cut(w-m, 0, m, m)
@skin[1] = bitmap.cut( 0, h-m, m, m)
@skin[3] = bitmap.cut(w-m, h-m, m, m)
@skin[8] = bitmap.cut( m, 0, w-(m*2), m)
@skin[4] = bitmap.cut( 0, m, m, h-(m*2))
@skin[6] = bitmap.cut(w-m, m, m, h-(m*2))
@skin[2] = bitmap.cut( m, h-m, w-(m*2), m)
@skin[5] = bitmap.cut( m, m, w-(m*2), h-(m*2))
end
end
#==============================================================================
# * Bitmap
#==============================================================================
class Bitmap
#--------------------------------------------------------------------------
# * Draw Tiled Sprite
#--------------------------------------------------------------------------
def draw_tiled(sprite)
for i in 1..9
draw_tiled_part(sprite, i)
end
end
#--------------------------------------------------------------------------
# * Draw Tiled Sprite (each part)
#--------------------------------------------------------------------------
def draw_tiled_part(sprite, id)
src_bitmap = sprite.skin[id]
m = sprite.margin
bx = (self.width - m * 2).to_f / src_bitmap.width
by = (self.height - m * 2).to_f / src_bitmap.height
dx = (src_bitmap.width * (bx.ceil.to_f - bx)).floor
dy = (src_bitmap.height * (by.ceil.to_f - by)).floor
case id
when 1
blt(0, self.height - m, src_bitmap, src_bitmap.rect)
when 3
blt(self.width - m, self.height - m, src_bitmap, src_bitmap.rect)
when 7
blt(0, 0, src_bitmap, src_bitmap.rect)
when 9
blt(self.width - m, 0, src_bitmap, src_bitmap.rect)
when 2
if sprite.stretch == false
for i in 0..bx.ceil
rect = src_bitmap.rect
rect.width = dx if i == bx.ceil
blt(m + i * src_bitmap.width, self.height - m, src_bitmap, rect)
end
else
dest_rect = Rect.new(m, self.height - m, self.width - m * 2, m)
stretch_blt(dest_rect, src_bitmap, src_bitmap.rect)
end
when 4
if sprite.stretch == false
for i in 0..by.ceil
rect = src_bitmap.rect
rect.height = dy if i == by.ceil
blt(0, m + i * src_bitmap.height, src_bitmap, rect)
end
else
dest_rect = Rect.new(0, m, m, self.height - m * 2)
stretch_blt(dest_rect, src_bitmap, src_bitmap.rect)
end
when 6
if sprite.stretch == false
for i in 0..by.ceil
rect = src_bitmap.rect
rect.height = dy if i == by.ceil
blt(self.width - m, m + i * src_bitmap.height, src_bitmap, rect)
end
else
dest_rect = Rect.new(self.width - m, m, m, self.height - m * 2)
stretch_blt(dest_rect, src_bitmap, src_bitmap.rect)
end
when 8
if sprite.stretch == false
for i in 0..bx.ceil
rect = src_bitmap.rect
rect.width = dx if i == bx.ceil
blt(m + i * src_bitmap.width, 0, src_bitmap, rect)
end
else
dest_rect = Rect.new(m, 0, self.width - m * 2, m)
stretch_blt(dest_rect, src_bitmap, src_bitmap.rect)
end
when 5
if sprite.stretch == false
for iy in 0..by.ceil
for ix in 0..bx.ceil
rect = src_bitmap.rect
rect.width = dx if ix == bx.ceil
rect.height = dy if iy == by.ceil
blt(m + ix * src_bitmap.width, m + iy * src_bitmap.height,
src_bitmap, rect)
end
end
else
dest_rect = Rect.new(m, m, self.width - m * 2, self.height - m * 2)
stretch_blt(dest_rect, src_bitmap, src_bitmap.rect)
end
end
end
end
#==============================================================================
# * Cursor_Rect
#==============================================================================
class Cursor_Rect < ::Sprite
attr_reader :width, :height, :skin, :margin, :sprite
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize(viewport)
super(viewport)
@width = 0
@height = 0
@margin = 16
@skin = nil
@sprite = nil
end
#--------------------------------------------------------------------------
# * Margin
#--------------------------------------------------------------------------
def margin=(margin)
@margin = margin
get_cursor_sprite
set(x, y, width, height)
end
#--------------------------------------------------------------------------
# * Skin
#--------------------------------------------------------------------------
def skin=(skin)
@skin = skin
get_cursor_sprite
end
#--------------------------------------------------------------------------
# * Get Cursor Sprite
#--------------------------------------------------------------------------
def get_cursor_sprite
return if @skin == nil
src_bitmap = @skin.cut(128, 64, 32, 32)
@sprite = Tiled_Sprite.new(src_bitmap, 2, true)
end
#--------------------------------------------------------------------------
# * Set Width
#--------------------------------------------------------------------------
def width=(width)
return if @width == width
@width = width
if @width == 0 and self.bitmap != nil
self.bitmap.dispose
self.bitmap = nil
end
draw_rect
end
#--------------------------------------------------------------------------
# * Set Height
#--------------------------------------------------------------------------
def height=(height)
return if @height == height
@height = height
if @height == 0 and self.bitmap != nil
self.bitmap.dispose
self.bitmap = nil
end
draw_rect
end
#--------------------------------------------------------------------------
# * Set Coords
#--------------------------------------------------------------------------
def set(x, y, width, height)
self.x = x + @margin
self.y = y + @margin
if @width != width or @height != height
@width = width
@height = height
if width > 0 and height > 0
draw_rect
end
end
end
#--------------------------------------------------------------------------
# * Clear cursor
#--------------------------------------------------------------------------
def empty
self.x = 0
self.y = 0
self.width = 0
self.height = 0
end
#--------------------------------------------------------------------------
# * Draw cursor
#--------------------------------------------------------------------------
def draw_rect
return if @skin == nil or @sprite == nil
if @width > 0 and @height > 0
self.bitmap = Bitmap.new(@width, @height)
self.bitmap.draw_tiled(@sprite)
end
end
end
#==============================================================================
# * Window
#==============================================================================
class Window
attr_reader :x, :y, :z, :width, :height, :ox, :oy
attr_reader :opacity, :back_opacity, :contents_opacity
attr_reader :stretch, :visible, :pause, :margin
attr_accessor :active
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize
@viewport = Viewport.new(0, 0, 0, 0)
@cr_vport = Viewport.new(0, 0, 0, 0)
@width = 0
@height = 0
@ox = 0
@oy = 0
@opacity = 255
@back_opacity = 255
@contents_opacity = 255
@margin = 16
@frame = Sprite.new
@bg = Sprite.new
@window = Sprite.new(@viewport)
@pause_s = Sprite.new
@arrows = []
for i in 0...4
@arrows.push(Sprite.new(@cr_vport))
@arrows[i].bitmap = Bitmap.new(16, 16)
@arrows[i].visible = false
end
@cursor_rect = Cursor_Rect.new(@cr_vport)
@cursor_fade = true
@pause_s.visible = false
@pause = false
@active = true
@stretch = true
@visible = true
self.x = 0
self.y = 0
self.z = 100
self.windowskin = RPG::Cache.windowskin($game_system.windowskin_name)
end
#--------------------------------------------------------------------------
# * Set Contents
#--------------------------------------------------------------------------
def contents=(bmp)
@window.bitmap = bmp
if bmp != nil
if bmp.width > @viewport.rect.width or bmp.height > @viewport.rect.height
draw_arrows
end
end
end
#--------------------------------------------------------------------------
# * Get Contents
#--------------------------------------------------------------------------
def contents
return @window.bitmap
end
#--------------------------------------------------------------------------
# * Dispose
#--------------------------------------------------------------------------
def dispose
@bg.dispose
@frame.dispose
@window.dispose
@cursor_rect.dispose
@viewport.dispose
@pause_s.dispose
@cr_vport.dispose
for arrow in @arrows
arrow.dispose
end
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
@window.update
@cursor_rect.update
@viewport.update
@cr_vport.update
update_pause
update_visible
update_arrows
update_cursor
end
#--------------------------------------------------------------------------
# * Update Pause
#--------------------------------------------------------------------------
def update_pause
id = (Graphics.frame_count / 8) % 4
rect = Rect.new(160, 64, 16, 16)
src_bitmap = Bitmap.new(rect.width, rect.height)
px = rect.x + (id % 2) * rect.width
py = rect.y + (id.to_f / 2).floor * rect.height
src_bitmap.blt(0, 0, @skin, Rect.new(px, py, rect.width, rect.height))
@pause_s.bitmap = src_bitmap
@pause_s.update
end
#--------------------------------------------------------------------------
# * Update Visible
#--------------------------------------------------------------------------
def update_visible
@frame.visible = @visible
@bg.visible = @visible
@window.visible = @visible
@cursor_rect.visible = @visible
if @pause
@pause_s.visible = @visible
else
@pause_s.visible = false
end
end
#--------------------------------------------------------------------------
# * Set Pause Mode
#--------------------------------------------------------------------------
def pause=(pause)
@pause = pause
update_visible
end
#--------------------------------------------------------------------------
# * Update Arrows
#--------------------------------------------------------------------------
def update_arrows
if @window.bitmap == nil or @visible == false
for arrow in @arrows
arrow.visible = false
end
else
@arrows[0].visible = @oy > 0
@arrows[1].visible = @ox > 0
@arrows[2].visible = (@window.bitmap.width - @ox) > @viewport.rect.width
@arrows[3].visible = (@window.bitmap.height - @oy) > @viewport.rect.height
end
end
#--------------------------------------------------------------------------
# * Update Cursor
#--------------------------------------------------------------------------
def update_cursor
if self.active == true
if @cursor_fade
@cursor_rect.opacity -= 10
@cursor_fade = false if @cursor_rect.opacity <= 100
else
@cursor_rect.opacity += 10
@cursor_fade = true if @cursor_rect.opacity >= 255
end
else
@cursor_rect.opacity = 100
@cursor_fade = false
end
end
#--------------------------------------------------------------------------
# * Set Visible
#--------------------------------------------------------------------------
def visible=(visible)
@visible = visible
update_visible
update_arrows
end
#--------------------------------------------------------------------------
# * Set X
#--------------------------------------------------------------------------
def x=(x)
@x = x
@bg.x = x + 2
@frame.x = x
@viewport.rect.x = x + @margin
@cr_vport.rect.x = x
@pause_s.x = x + (@width / 2) - 8
set_arrows
end
#--------------------------------------------------------------------------
# * Set Y
#--------------------------------------------------------------------------
def y=(y)
@y = y
@bg.y = y + 2
@frame.y = y
@viewport.rect.y = y + @margin
@cr_vport.rect.y = y
@pause_s.y = y + @height - @margin
set_arrows
end
#--------------------------------------------------------------------------
# * Set Z
#--------------------------------------------------------------------------
def z=(z)
@z = z
@bg.z = z - 1
@frame.z = z
@cr_vport.z = z + 2
@viewport.z = z + 3
@pause_s.z = z + 4
end
#--------------------------------------------------------------------------
# * Set OX
#--------------------------------------------------------------------------
def ox=(ox)
return if @ox == ox
@ox = ox
@viewport.ox = ox
update_arrows
end
#--------------------------------------------------------------------------
# * Set OY
#--------------------------------------------------------------------------
def oy=(oy)
return if @oy == oy
@oy = oy
@viewport.oy = oy
update_arrows
end
#--------------------------------------------------------------------------
# * Set Width
#--------------------------------------------------------------------------
def width=(width)
@width = width
@viewport.rect.width = width - @margin * 2
@cr_vport.rect.width = width
draw_window if @width > 0 and @height > 0
self.x = @x
self.y = @y
end
#--------------------------------------------------------------------------
# * Set Height
#--------------------------------------------------------------------------
def height=(height)
@height = height
@viewport.rect.height = height - @margin * 2
@cr_vport.rect.height = height
draw_window if @height > 0 and @width > 0
self.x = @x
self.y = @y
end
#--------------------------------------------------------------------------
# * Set Opacity
#--------------------------------------------------------------------------
def opacity=(opacity)
value = [[opacity, 255].min, 0].max
@opacity = value
@contents_opacity = value
@back_opacity = value
@frame.opacity = value
@bg.opacity = value
@window.opacity = value
end
#--------------------------------------------------------------------------
# * Set Back Opacity
#--------------------------------------------------------------------------
def back_opacity=(opacity)
value = [[opacity, 255].min, 0].max
@back_opacity = value
@bg.opacity = value
end
#--------------------------------------------------------------------------
# * Set Contents Opacity
#--------------------------------------------------------------------------
def contents_opacity=(opacity)
value = [[opacity, 255].min, 0].max
@contents_opacity = value
@window.opacity = value
end
#--------------------------------------------------------------------------
# * Get Cursor Rect
#--------------------------------------------------------------------------
def cursor_rect
return @cursor_rect
end
#--------------------------------------------------------------------------
# * Set Cursor Rect
#--------------------------------------------------------------------------
def cursor_rect=(rect)
@cursor_rect.x = rect.x
@cursor_rect.y = rect.y
if @cursor_rect.width != rect.width or @cursor_rect.height != rect.height
@cursor_rect.set(@cursor_rect.x, @cursor_rect.y, rect.width, rect.height)
end
end
#--------------------------------------------------------------------------
# * Get Windowskin
#--------------------------------------------------------------------------
def windowskin
return @skin
end
#--------------------------------------------------------------------------
# * Set Windowskin
#--------------------------------------------------------------------------
def windowskin=(windowskin)
return if windowskin == nil
if @skin != windowskin
@skin = windowskin
@cursor_rect.skin = windowskin
draw_window
draw_arrows
end
end
#--------------------------------------------------------------------------
# * Set Margin
#--------------------------------------------------------------------------
def margin=(margin)
if @margin != margin
@margin = margin
self.x = @x
self.y = @y
temp = @height
self.height = 0
self.width = @width
self.height = temp
@cursor_rect.margin = margin
set_arrows
end
end
#--------------------------------------------------------------------------
# * Set Stretch
#--------------------------------------------------------------------------
def stretch=(stretch)
if @stretch != stretch
@stretch = stretch
draw_window
end
end
#--------------------------------------------------------------------------
# * Set Arrow Positions
#--------------------------------------------------------------------------
def set_arrows
@arrows[0].x = @width / 2 - 8
@arrows[0].y = 8
@arrows[1].x = 8
@arrows[1].y = @height / 2 - 8
@arrows[2].x = @width - 16
@arrows[2].y = @height / 2 - 8
@arrows[3].x = @width / 2 - 8
@arrows[3].y = @height - 16
end
#--------------------------------------------------------------------------
# * Draw Window Basics
#--------------------------------------------------------------------------
def draw_window
return if @skin == nil
return if @width == 0 or @height == 0
draw_back
draw_frame
end
#--------------------------------------------------------------------------
# * Draw Back
#--------------------------------------------------------------------------
def draw_back
@bg.bitmap = Bitmap.new(@width - 4, @height - 4)
src_bitmap = @skin.cut(0, 0, 128, 128)
sprite = Tiled_Sprite.new(src_bitmap, 0, @stretch)
@bg.bitmap.draw_tiled(sprite)
end
#--------------------------------------------------------------------------
# * Draw Frame
#--------------------------------------------------------------------------
def draw_frame
@frame.bitmap = Bitmap.new(@width, @height)
m = 16
src_bitmap = @skin.cut(128, 0, 64, 64)
src_rect = Rect.new(m, m, 64 - m * 2, 64 - m * 2)
src_bitmap.fill_rect(src_rect, Color.new(0, 0, 0, 0))
sprite = Tiled_Sprite.new(src_bitmap, m, false)
@frame.bitmap.draw_tiled(sprite)
end
#--------------------------------------------------------------------------
# * Draw Arrows
#--------------------------------------------------------------------------
def draw_arrows
return if @skin == nil
@arrows[0].bitmap = @skin.cut(152, 16, 16, 8)
@arrows[1].bitmap = @skin.cut(144, 24, 8, 16)
@arrows[2].bitmap = @skin.cut(168, 24, 8, 16)
@arrows[3].bitmap = @skin.cut(152, 40, 16, 8)
update_arrows
end
end
PART 5. Script adaptations
The Window script posted above defines in a single method the drawing of the sprites (used as a shortcut), this way it's easier to customize it taking into account both the border and the stretch mode.
That property is defined in Back, Frames, Cursor, and finally in Blind if you're using the Window Blind Add-On (see below).
It's also possible to change the cursor's windowskin independently, using cursor_rect.skin = name
Examples:
self.cursor_rect.skin = "001-Blue01"
@window.cursor_rect.skin = "Dark_Skin"
This dynamic cursor skin can be useful if you want to change it based on a condition (for example, when the current choice is disabled).
Therefore, we can make other basic changes, implemented as "AddOns" below this base script.
The method update_pause defines how the pause graphic is loaded. There you can change it easily so that graphic is loaded using an independent graphic instead, for example this one. This way it can be as big as you want, and have more frames.
Ruby:
#==============================================================================
# ** Window - Pause Frame Edit
#==============================================================================
class Window
def update_pause
#------------------------------------------------------------------------
# Number of frames per frame
frames = 8
# Graphic used
pause_bmp = RPG::Cache.picture("pause")
#------------------------------------------------------------------------
h = pause_bmp.height
i = pause_bmp.width / h
id = (Graphics.frame_count / frames) % i
rect = Rect.new(0, 0, h, h)
src_bitmap = Bitmap.new(rect.width, rect.height)
px = rect.x + id * rect.width
src_bitmap.blt(0, 0, pause_bmp, Rect.new(px, 0, rect.width, rect.height))
@pause_s.bitmap = src_bitmap
@pause_s.update
end
end
The method update_cursor defines the blinking of the cursor and its opacity when it's disabled. Disabling its blinking is very simple.
Ruby:
#==============================================================================
# ** Window - Cursor Fade Fix
#==============================================================================
class Window
def update_cursor
if self.active == true
@cursor_rect.opacity = 255
else
@cursor_rect.opacity = 100
end
end
end
You could also make a cursor with multiple frames as in RM2k/3, to do that you can use the previous script for pause as a reference. Similarly, on the method draw_arrows you can change how the scroll arrows are displayed, in case you want them bigger, or animated, etc.
Inside the methods that define X and Y, you can find these:
@pause_s.x = x + (@width / 2) - 8
@pause_s.y = y + @height - @margin
That controls the position of the pause, so you can easily change it as well, like this:
Ruby:
#==============================================================================
# ** Window - Pause position
#==============================================================================
class Window
alias pause_pos_x x= unless $@
alias pause_pos_y y= unless $@
def x=(x)
pause_pos_x(x)
# Set Pause X
@pause_s.x = x + @width - 24
end
def y=(y)
pause_pos_y(y)
# Set Pause Y
@pause_s.y = y + @height - 20
end
end
Now margin is a modifiable property too, but I recommend not changing that.
The method set_arrows defines the position of the scroll arrows, which I don't recommend changing either.

The method draw_back defines how the background is displayed.
It gets the graphic with the rect (0, 0, 128, 128) from the windowskin and then uses this
sprite = Tiled_Sprite.new(src_bitmap, 0, @stretch)
That 0 is the margin, which means changing it you can make things like this image.

Ruby:
#==============================================================================
# ** Window - Back margin
#==============================================================================
class Window
def draw_back
@bg.bitmap = Bitmap.new(@width - 4, @height - 4)
src_bitmap = @skin.cut(0, 0, 128, 128)
sprite = Tiled_Sprite.new(src_bitmap, 24, @stretch)
@bg.bitmap.draw_tiled(sprite)
end
end
Right after that, the Frame is defined in a very similar way inside the method draw_frame, where m = 16 is the margin.
sprite = Tiled_Sprite.new(src_bitmap, m, false)
Changing that to true allows the borders of the frames to stretch, which may be interesting in some cases. You can check it here.
Ruby:
#==============================================================================
# ** Window - Frame Stretch
#==============================================================================
class Window
def draw_frame
@frame.bitmap = Bitmap.new(@width, @height)
m = 16
src_bitmap = @skin.cut(128, 0, 64, 64)
src_rect = Rect.new(m, m, 64 - m * 2, 64 - m * 2)
src_bitmap.fill_rect(src_rect, Color.new(0, 0, 0, 0))
sprite = Tiled_Sprite.new(src_bitmap, m, true)
@frame.bitmap.draw_tiled(sprite)
end
end
Finally (this is getting long), the last interesting method is get_cursor_sprite, which defines the display of the cursor. The default 2px border is very limiting, so you can now change it to something more wide. You can also make it tile.
As before, all that is defined on this line:
@sprite = Tiled_Sprite.new(src_bitmap, 2, true)
Here's my version
Ruby:
#==============================================================================
# ** Window - Cursor Sprite
#==============================================================================
class Cursor_Rect < ::Sprite
def get_cursor_sprite
return if @skin == nil
src_bitmap = @skin.cut(128, 64, 32, 32)
@sprite = Tiled_Sprite.new(src_bitmap, 14, true)
end
end

More recent RPG maker versions have an extra part on the graphic with blinds, so you can define at once a tiling and a stretching part for the back of your windows. I've made a little AddOn for this script that allows doing that, but you'll need a Picture called blind.
Ruby:
#==============================================================================
# ** Window Blind Add-On
#------------------------------------------------------------------------------
# This script requires the Window - Hidden RGSS Class by Wecoc
#==============================================================================
class Window
alias blind_ini initialize unless $@
def initialize
@blind = Sprite.new
@blind.blend_type = 0
blind_ini
end
alias blind_dis dispose unless $@
def dispose
blind_dis
@blind.dispose
end
alias blind_visible update_visible unless $@
def update_visible
blind_visible
@blind.visible = @visible
end
alias blind_x x= unless $@
def x=(x)
blind_x(x)
@blind.x = x + 2
end
alias blind_y y= unless $@
def y=(y)
blind_y(y)
@blind.y = y + 2
end
def z=(z)
@z = z
@bg.z = z
@blind.z = z + 1
@frame.z = z + 2
@cr_vport.z = z + 3
@viewport.z = z + 4
@pause_s.z = z + 5
end
alias blind_opacity opacity= unless $@
def opacity=(opacity)
value = [[opacity, 255].min, 0].max
blind_opacity(value)
@blind.opacity = value
end
alias blind_back_opacity back_opacity= unless $@
def back_opacity=(opacity)
value = [[opacity, 255].min, 0].max
blind_back_opacity(value)
@blind.opacity = value
end
alias blind_draw_back draw_back
def draw_back
blind_draw_back
@blind.bitmap = Bitmap.new(@width - 4, @height - 4)
src_bitmap = RPG::Cache.picture("blind")
sprite = Tiled_Sprite.new(src_bitmap, 0, false)
@blind.bitmap.draw_tiled(sprite)
end
end
The windows of Chrono Trigger have two separated backs, similar to VX body and blind, but the other way around; the top part is the stretched one. You can see it here.
You could try to modify the stretch modes in the Blind Addon, but it wouldn't look exactly the same, so I made it a separate AddOn instead.
In this case it requires two extra images in the Pictures folder; chrono_lighen and chrono_lighten. I also made a skin in case you want to try it (don't use it on your game, it's just for testing purposes).
You could try to modify the stretch modes in the Blind Addon, but it wouldn't look exactly the same, so I made it a separate AddOn instead.
Ruby:
#==============================================================================
# ** Window Chrono Trigger
#------------------------------------------------------------------------------
# This script requires the Window - Hidden RGSS Class by Wecoc
#==============================================================================
class Window
alias chrono_ini initialize unless $@
def initialize
@chrono_lighten = Sprite.new
@chrono_darken = Sprite.new
@chrono_lighten.blend_type = 1
@chrono_darken.blend_type = 2
chrono_ini
self.stretch = false
end
alias chrono_dis dispose unless $@
def dispose
chrono_dis
@chrono_lighten.dispose
@chrono_darken.dispose
end
alias chrono_visible update_visible unless $@
def update_visible
chrono_visible
@chrono_lighten.visible = @visible
@chrono_darken.visible = @visible
end
def update_cursor
if self.active == true
@cursor_rect.opacity = 255
else
@cursor_rect.opacity = 100
end
end
alias chrono_x x= unless $@
def x=(x)
chrono_x(x)
@bg.x = x
@chrono_lighten.x = x
@chrono_darken.x = x
end
alias chrono_y y= unless $@
def y=(y)
chrono_y(y)
@bg.y = y
@chrono_lighten.y = y
@chrono_darken.y = y
end
def z=(z)
@z = z
@bg.z = z
@frame.z = z + 1
@chrono_lighten.z = z + 2
@chrono_darken.z = z + 2
@cr_vport.z = z + 3
@viewport.z = z + 4
@pause_s.z = z + 5
end
alias chrono_opacity opacity= unless $@
def opacity=(opacity)
value = [[opacity, 255].min, 0].max
chrono_opacity(value)
@chrono_lighten.opacity = value
@chrono_darken.opacity = value
end
def draw_back
@bg.bitmap = Bitmap.new(@width, @height)
src_bitmap = @skin.cut(0, 0, 128, 128)
sprite = Tiled_Sprite.new(src_bitmap, 16, @stretch)
@bg.bitmap.draw_tiled(sprite)
@chrono_lighten.bitmap = Bitmap.new(@width, @height)
src_bitmap = RPG::Cache.picture("chrono_lighten")
sprite = Tiled_Sprite.new(src_bitmap, 0, true)
@chrono_lighten.bitmap.draw_tiled(sprite)
@chrono_darken.bitmap = Bitmap.new(@width, @height)
src_bitmap = RPG::Cache.picture("chrono_darken")
sprite = Tiled_Sprite.new(src_bitmap, 0, true)
@chrono_darken.bitmap.draw_tiled(sprite)
end
end
In this case it requires two extra images in the Pictures folder; chrono_lighen and chrono_lighten. I also made a skin in case you want to try it (don't use it on your game, it's just for testing purposes).

Last edited: