Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.
Conectarse

Recuperar mi contraseña

Temas importantes
----------------------------------------
Páginas con recursos RPG Maker
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
Afiliados
Estadísticas
Tenemos 3808 miembros registrados.
El último usuario registrado es angel.ascanio.

Nuestros miembros han publicado un total de 86157 mensajes en 12277 argumentos.

[XP][Tutorial] Windowskins al detalle

Ver el tema anterior Ver el tema siguiente Ir abajo

[XP][Tutorial] Windowskins al detalle

Mensaje por Wecoc el 2017-04-30, 13:38

Me han dado la idea de hacer un tutorial sobre cómo funciona exactamente una Windowskin, así que allá voy.

La Windowskin es el gráfico que se utiliza para dibujar las ventanas del juego.
La distribución de ese gráfico varía según el RPG maker, así que aquí me centraré en la de RPG maker XP.



1. Partes de la Windowskin

En el siguiente template podéis ver los límites de cada parte de la windowksin.



A. La parte verde se llama back y corresponde al fondo de la ventana.
B. La parte gris con cantos amarillos se llama frame y corresponde al marco de la ventana.
C. La parte naranja son las flechas que salen en las listas del maker para indicar que no estás al inicio/final de la lista.
D. La parte roja es el cursor.
E. Los cuadros azules son cada uno de los 4 frames del iconcito que aparece en los cuadros de mensaje. A ese icono se le llama pause.
F. La parte lila es cada uno de los 2 frames de la flecha que se usa en batalla.



El dibujado de las partes se define dentro de la clase interna Window.
No se puede acceder a su código, pero se puede sobreescribir con RGSS para poder modificar alguna de sus propiedades.
La única parte que se controla en un script a parte son las flechas de batalla, que se definen en el script Arrow_Base. Eso es porque aunque estan en la Windowskin no son parte de la ventana en sí.

Algo que quiero destacar del template es que como puede verse el cursor en realidad tiene un pequeño borde alrededor que no queda estirado a diferencia de la parte central.
Ese efecto se puede apreciar bien aquí:



Por largo que sea el cursor en comparación con el gráfico de la windowskin, el borde mantiene su grosor.

2. Propiedades de Window

La ventana tiene varias variables relacionadas con cómo se muestran esas partes.
Algunas son modificables (por ejemplo al definir una ventana @window luego puedes hacer @window.opacity = 160 para cambiar su opacidad) mientras que otras son internas.

Modificables:

windowskinBitmapGráfico Windowskin usado para esa ventana.
contentsBitmapContenido de la ventana (texto, iconos...)
stretchBooleanModo en el que se muestra back. Estirado (true) o en modo Tile (false).
x, y, width, heightIntegerCoordenadas/tamaño de la ventana
zIntegerZ de la ventana
ox, oyIntegerPosición "scroll" de la ventana, por ejemplo dada una lista larga de items.
cursor_rectRectRect con coordenadas/tamaño del cursor
activeBooleanSi la ventana está activa o no, es decir si el cursor funciona o no.
visibleBooleanSi la ventana y su contenido se ven o no.
pauseBooleanSi el gráfico pause se muestra o no.
opacityIntegerOpacidad de back y frame, va de 0 a 255.
back_opacityIntegerOpacidad de back, va de 0 a 255.
contents_opacityIntegerOpacidad de contents y el cursor, va de 0 a 255.

No modificables:

marginIntegerMargen que queda entre el contenido de la ventana y el espacio real que ésta ocupa. Vale 16.
viewportViewportCapa en la que está anclada la ventana

3. Stretch y tileado

Algunas partes del gráfico de la windowskin quedan estiradas cuando la ventana es más grande que el gráfico, mientras que otras tilean hasta rellenar todo el espacio necesario.
Haciendo una modificación del template antes puesto se puede ver cuales quedan estiradas y cuales no.



Aquí podéis ver cómo queda:



Tal como se ve en el ejemplo, las partes en las que pinté las líneas verdes no quedan estiradas, mientras que las partes con líneas grises sí.
El único control que tenemos por defecto para eso es usar stretch tal como se indicó en el apartado anterior; si la variable stretch de la ventana vale false el fondo no queda estirado.

Para hacer que por defecto el fondo nunca quede estirado puede usarse éste pequeño script encima de main:

Código:
class Window
  alias stretch_mode_ini initialize unless $@
  def initialize(*args)
    stretch_mode_ini(*args)
    self.stretch = false
  end
end

Borde
Stretch
Back
0
@stretch
Frames
16
No
Cursor
2

4. Reescritura de Window en RGSS

Para poder modificar a nuestro antojo algunas de las propiedades de la ventana, se puede usar un script que reescriba los métodos de la ventana en RGSS. Eso hace que el cargado de las ventanas sea un poco más lento pero a cambio tendremos mucho más control de Window. Hay varios scripts que reescriben Window pero como soy más chulo que un ocho he hecho uno especialmente para éste tutorial, libre de uso.

Código:
#==============================================================================
# ** [XP] Window - Hidden RGSS Class
#------------------------------------------------------------------------------
# Autor: Wecoc (no requiere créditos)
#------------------------------------------------------------------------------
# Tomé el script Window de Selwyn como referencia.
#==============================================================================

#==============================================================================
# * 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
    @frame.z = z + 1
    @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

Recomiendo no modificar nada del script, sinó hacer reescrituras en otro script a parte para tenerlo más ordenado.

Hasta aquí ésta parte del tutorial, más adelante explicaré donde cambiar cada cosa en ese script, que supongo que será la parte más interesante, pero antes tenía que hacer ésta introducción.
avatar
Wecoc
Administrador
Administrador



Créditos 12099

Gracias : 522

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por xXIsrael0499Xx el 2017-04-30, 21:03

... u_u
Gracias de verdad por este tutorial de verdad me servirá de mucho, ya podre inventar mas cositas locas... 1 + para ti...

Tengo una duda y es sobre el Stretch, e visto algunos casos donde a la windoskin le ponen texturas al back , por ejemplo ponen una imagen pequeña como el back llena de circulitos y luego no se que hacen y esos circulitos salen en el back... eso es Stretch o mejor dicho se puede hacer con eso?....
avatar
xXIsrael0499Xx
Principiante
Principiante

0/3

Créditos 1132

Gracias : 57

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por Wecoc el 2017-04-30, 21:47

Me confunde lo de los "circulitos" pero supongo que sí te refieres al modo stretch (en ese caso desactivado para que tilee). Igualmente recomiendo hacer fondos de windowskin ténues para que se lea bien el texto. Pongo aquí dos ejemplos rápidos.



Spoiler:







La skin de VX/Ace/MV en ese sentido es un poco más avanzada porque back está separado en dos partes, una sin stretch (body) y otra con stretch que queda por encima (blind). Algunos scripts para XP pueden imitar ese efecto, como la reescritura de Window hecha por Poccil, pero en ese caso no implementé esa opción.

Si tienes dudas sobre el último script que puse, espérate a la segunda parte del tutorial, que irá de lo que se puede hacer partiendo de ese código. Muy pronto la pondré.


Última edición por Wecoc el 2017-04-30, 22:10, editado 1 vez
avatar
Wecoc
Administrador
Administrador



Créditos 12099

Gracias : 522

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por xXIsrael0499Xx el 2017-04-30, 22:08

Ah.. ok ya entiendo... para que se usa... pero no es lo que estoy preguntando... sera mas claro...
Por ejemplo tengo una windoskin:


Y ahora imagínate que nada mas tienes el back de esta (pero en blanco y negro) :

Y lo nombrare "imagen A"

Con una imagen A, cambian la textura de la window desde el maker... sin hacer otra windowskin..
Me entiendes?, claro ya me aclaraste la dudad del stretch, pero esos es lo que estaba tratando de preguntar.. pero no me explique bien XD...

Un ejemplo de esto es una demo que vi que se llama Ace Menu Engine (para XP) donde hacen lo que acabo de nombrar (Aparte de hacer que los charas se muevan en el menú, que estuve buscando la forma pero nunca la descubrí XD)....
avatar
xXIsrael0499Xx
Principiante
Principiante

0/3

Créditos 1132

Gracias : 57

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por Wecoc el 2017-05-01, 06:47

Ya veo, lo que hacen es recrear mediante otra imagen el efecto blind que comenté en el post anterior, presente por defecto a partir de VX. El Ace Menu Engine es un sistema complejo y no entraré en detalle pero en realidad no están cambiando nada de la clase Window ahí, definen un nuevo plane a parte que se dibuja a lo largo de toda la escena de menú y que queda justo entre el back de las ventanas y el contenido, por eso da el mismo efecto y además pueden hacerlo scrollear. No era mi intentención en éste tema pero bueno, he hecho un script para usar una imagen como blind (aunque en éste caso sin scroll).

Poned ésto debajo del script Window que he puesto antes.

Código:
#==============================================================================
# ** Window Blind Add-On
#------------------------------------------------------------------------------
#  Éste script requiere el Window - Hidden RGSS Class de 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

Necesitaréis una Picture llamada blind, puede tener cualquier tamaño aunque si es muy pequeña podría dar lag dibujarla a lo largo de la ventana. Yo hice ésta de ejemplo:

avatar
Wecoc
Administrador
Administrador



Créditos 12099

Gracias : 522

Volver arriba Ir abajo

ARIGATO!!

Mensaje por xXIsrael0499Xx el 2017-05-01, 11:13

Perfecto, me servirá....
Eh probado el Script y no me da ningún error y esos es bueno XD
Con el efecto blind se puede hacer cosas bastante cool si se curra bien y me alegra que te ayas tomado la molestia de hacer ese script ya que es fácil de usar y de entender así que muchas gracias, a mi me servirá y pienso que es un muy buen aporte :3  1+

Estaré esperando el tutorial de como modificar el script (Para no hacer que me pete el Maker)
avatar
xXIsrael0499Xx
Principiante
Principiante

0/3

Créditos 1132

Gracias : 57

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por Wecoc el 2017-05-01, 11:22

Aquí tenéis la segunda parte del tutorial.

5. Adaptaciones del script (1)

El script Window (apartado 4) define un atajo al dibujado de los sprites para que sea más fácil hacerlo teniendo en cuenta el borde y el stretch.
Esa propiedad se define en Back, Frames y Cursor tal como se explicó al final del apartado 3, y finalmente a Blind en el script Window Blind Add-On que ya he puesto.

El funcionamiento de todo eso corresponde a la primera parte del script, en la que no hay nada modificable de interés por lo que me lo salto. Con ello saltamos directamente a la clase Cursor_Rect.

Hay un método margin para definir el margen del cursor, vale 16 por defecto al igual que el margen del contenido que ya expliqué anteriormente. Recomiendo no cambiar eso, solo lo menciono como apunte.

Luego está el método skin, eso significa que puedes cambiar el gráfico de windowskin del cursor sin cambiar el de la ventana.
Para hacerlo usad cursor_rect.skin = "nombre de la windowskin"

Ejemplos:
self.cursor_rect.skin = "001-Blue01"
@window.cursor_rect.skin = "Dark_Skin"


Ese cambio dinámico puede ser útil si se quiere una escena donde el cursor varíe según alguna condición (por ejemplo, si el índice actual está desactivado).
Como véis no hay que cambiar nada, es solo una nueva función que tenemos con éste script.

Pero eso es poco útil de momento... tiro mucho más abajo, ya dentro de la clase Window propiamente dicha, para rescatar lo interesante.

Dentro del método update_pause se define cómo se carga el gráfico pause.
Podemos modificarlo fácilmente para que cargue ese iconcito de un gráfico a parte.

Código:
#==============================================================================
# ** Window - Pause Frame Edit
#==============================================================================

class Window
  def update_pause
    #------------------------------------------------------------------------
    # Número de frames para cambiar gráfico
    frames = 8
    # Gráfico usado para el pause
    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

Ahora usa un gráfico Picture que puede tener los frames que se quiera y ser del tamaño que se quiera, teniendo en cuenta que los frames deben ser cuadrados.
Ejemplo:

Dentro de update_cursor se define el parpadeo del cursor y la opacidad cuando no está activado.
Impedir de parpadee es bien sencillo:

Código:
#==============================================================================
# ** 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

Si se quisiera usar un cursor con múltiples frames el frame actual también se definiría dentro de update_cursor, se puede usar el script anterior (para pause) como referencia.

Dentro de los métodos que definen X e Y se puede encontrar ésto:
@pause_s.x = x + (@width / 2) - 8
@pause_s.y = y + @height - @margin

Eso controla la posición del gráfico pause, así que se puede cambiar fácilmente.
Por ejemplo si queremos que se muestre en una esquina de la ventana de mensaje en vez de centrado:

Código:
#==============================================================================
# ** Window - Pause position
#==============================================================================

class Window
  alias pause_pos_x x= unless $@
  alias pause_pos_y y= unless $@
  def x=(x)
    pause_pos_x(x)
    # Definir X de pause
    @pause_s.x = x + @width - 24
  end
  def y=(y)
    pause_pos_y(y)
    # Definir Y de pause
    @pause_s.y = y + @height - 20
  end
end

Antes no se podía cambiar margin de la ventana y ahora sí, por lo que se puede hacer que el contenido de la ventana quede mucho más ajustado a los márgenes de ésta usando margin = valor

Ejemplo: self.margin = 8
Aún así recomiendo no cambiar eso xD

Dentro de set_arrows se define la posición a la que se muestran las flechas de scroll de la ventana. Centradas tal como está por defecto suele ser la mejor opción pero quizá queráis algo más personalizado.

Y ahora vienen seguramente los tres métodos más importantes, lo mejor para el final :D

6. Adaptaciones del script (2)

Dentro del método draw_back se define cómo se muestra el fondo de la ventana.
Obtiene el gráfico de la propia windowskin, recuadro (0, 0, 128, 128) y justo luego hace:

sprite = Tiled_Sprite.new(src_bitmap, 0, @stretch)

Ese 0 significa el margen (ver tabla del apartado 3), lo que significa que ampliándolo ahora puedes hacer windowskins con fondo que tenga márgenes definidos.

Aquí un ejemplo con un margen de 24.

Código:
#==============================================================================
# ** 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

Da un efecto bisel algo curioso, probadlo con la skin por defecto para ver a lo que me refiero.
También se puede usar para hacer un efecto popup. Aquí os muestro a lo que me refiero.



Justo después, dentro del método draw_frame se define, de modo similar, el dibujado de los frames.
En la línea m = 16 se define el margen de éstos, y luego se usa éste en una línea casi idéntica a la de antes.

sprite = Tiled_Sprite.new(src_bitmap, m, false)

Cambiando ese false por true ahora podemos hacer que los bordes de los frames queden estirados en vez de tilear.
En la mayoría de windowskins no se verá la diferencia, pero en otras puede ser interesante esa opción.

Pongo aquí ese ejemplo para que lo probéis:

Código:
#==============================================================================
# ** 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

En el método draw_arrows se define donde se obtiene el gráfico de las flechas de scroll, no creo que sea necesario cambiar eso, pero si en el caso anterior habéis puesto un margen más pequeño para los bordes luego se puede usar más espacio, para poder hacer flechas más grandes. Otra opción es cargarlas de un gráfico a parte.

El último método llamativo me lo salté antes a propósito y es el get_cursor_sprite. Ahí se define el dibujado del gráfico del cursor. En muchas windowskins el cursor queda mal estirado, puesto que el margen por defecto de solo 2 píxeles es muy limitante. Además por defecto queda estirado y puede interesarnos que tilee.

Todo eso viene definido de modo muy parecido a como se vió en back y frame, en ésta línea:

@sprite = Tiled_Sprite.new(src_bitmap, 2, true)

Pongo aquí mi versión, el cursor se suele ver mejor si usáis éste arreglo.

Código:
#==============================================================================
# ** 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

Aquí un ejemplo del "antes" y "después" de usar ese script:



Y ésto sería todo pero (en parte gracias al bueno de Israel) hay un edit extra que quiero comentar.

7. Windowskin estilo Chrono Trigger

No sé si sois fans de Chrono Trigger, seguramente muchos sí. Las windowskins de Chrono Trigger tienen el back separado en dos, muy similar al VX con body y blind, pero al revés, body tilea mientras que blind es un degradado tal como puede verse aquí: Chrono Trigger Skin Sheet

Blind lo definí de modo similar a Back, Frame y Cursor de modo que se puede hacer que no tilee y ya está, pero no acabaría de quedar igual.
¡Así que aquí tenéis un edit del script Window Blind Add-On para hacer ventanas exactamente como las de Chrono Trigger!

Código:
#==============================================================================
# ** Window Chrono Trigger
#------------------------------------------------------------------------------
#  Éste script requiere el Window - Hidden RGSS Class de 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

Podéis tomarlo de ejemplo para otros edits similares también, se cambian muchas cosas de las que se han comentado en apartados anteriores.
En ese caso requiere dos imágenes a parte en la carpeta pictures, una llamada chrono_lighten y otra chrono_darken.

Hice éstas de ejemplo:
chrono_lighten.png
chrono_darken.png
chrono_skin01.png

Spoiler:

Y ahora sí, eso es todo. Ojalá os haya sido de ayuda todo éste tocho-topic ;D
avatar
Wecoc
Administrador
Administrador



Créditos 12099

Gracias : 522

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por orochii el 2017-05-02, 01:24

Pos está bastante útil, la información e incluso como repositorio de ideas xd. No sé, digo, a veces se deja una skin tal cual sin pensar en que quiza hayan más opciones que un color plano, o una cosa asdf como la de siempre. O quiza en casos no sea necesario usar puros fondos de ventanas por imagen xd.

No sé, expandir los usos de las windowskins es guay :^V.
avatar
orochii
Reportero

0/3

Créditos 7458

Gracias : 368

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por xXIsrael0499Xx el 2017-05-02, 10:41

Hay muchas cosas interesantes que hacer, y como dijo orochii expandir los usos de las windowskins es guay, así que ya con esto no hay escusa para no ponerse a inventar resultados bonitos....
Madre mía Wecoc me nombro asadasdaedasd (?)


Gracias por tomarte tu tiempo haciendo esto....

PD: ahora es cuando me entra la envidia por no hacer scripts igual de útiles (?)
avatar
xXIsrael0499Xx
Principiante
Principiante

0/3

Créditos 1132

Gracias : 57

Volver arriba Ir abajo

Re: [XP][Tutorial] Windowskins al detalle

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.