기타

프리 윈도우 스크립트 (상입오두막 출처)

by 백호 posted Feb 21, 2009
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄
출처는 상입 오두막입니다. (http://aea.to/hako/)
사용법은 댓글로

#===============================================================================
# ■ Free_Window (ver.3.01)
# ------------------------------------------------------------------------------
# 메세지 윈도우·커멘드 윈도우를 표시
# ------------------------------------------------------------------------------
# 2005/07/29 by 상입 오두막 http://aea.to/hako/
#===============================================================================
class Free_Window < Window_Selectable
  #-----------------------------------------------------------------------------
  # 정수(값은 자유롭게 설정할 수 있습니다)
  #-----------------------------------------------------------------------------
  # 행간(pixel)
  LINE_SPACE = 10
  # 윈도우의 불투명도(0..255)
  OPACITY = 255
  # 윈도우 배경의 불투명도(0..255)
  BACK_OPACITY = 160
  # 폰트(Font)
  FONT = Font.new("MS P고딕", 22) # 폰트명, 사이즈    (★폰트명이 고딕과 다른경우 고치도록.)
  FONT.bold = false                      # 볼드(굵은 글씨) 플래그
  FONT.italic = false                    # 이탤릭(이탤릭) 플래그
  # 선택사항의 결과(항목 번호)를 대입하는 변수 ID($game_variables)
  RESULT = 1
  # 그래픽 참조 폴더
  GRA_DIR = "Graphics/"
  #-----------------------------------------------------------------------------
  # ● 오브젝트 초기화
  #-----------------------------------------------------------------------------
  def initialize(text, wx = 80, wy = 304, ww = 480, wh = 160)
    @command = text.is_a?(Array) ? true : false # 커멘드 플래그
    @text = text.dup
    # 커멘드
    if @command
      # 말미 요소가 "!cancel" 였던 경우
      if @text[-1] == "!cancel"
        @text.pop    # 말미 요소를 없앤다
        @cancel = true  # 캔슬 유효 플래그
      else
        @cancel = false
      end
      # 렬수를 설정
      if @text[0].is_a?(Integer) and @text[0] > 0
        col = @text[0]
        @text.shift  # 선두 요소를 삭제
      else
        col = 1
      end
      # 렬수의 조정
      col = @text.size if col > @text.size
      @cw = ww
      super(wx, wy, @cw, wh)
      @column_max = col # 렬수
      @disable = Array.new(@text.size) # 선택 불가 플래그의 배열
      @text.each_index {|i| @disable[i] = @text[i].gsub!(/^\[xX]|\[xX]$/, "") != nil}
      refresh_command(wh)
      self.index = 0
      @pause_show = false  # 포즈 싸인 표시 플래그
      self.visible = true
      @contents_showing = true  # 메세지 표시중 플래그
    # 메세지
    else
      super(wx, wy, ww, wh)
      self.contents = Bitmap.new(ww - 32, wh - 32)
      # "<NP>"(이)가 있으면 포즈 싸인을 비표시
      @pause_show = @text.gsub!(/<NP>/) { "" } == nil
      # "<IN>"(이)가 있으면 메세지를 순간 표시·순간 소거
      @fade_speed = @text.gsub!(/<IN>/) { "" } != nil ? 255 : 48
      # "<+>"(이)가 있으면, 직후의 개행을 무시한다
      @text.gsub!(/<+>n/) { "" }
      # "\mini[캐릭터 라인 or 엑터 번호]"가 있으면, 미니 윈도우를 표시
      @text.gsub!(/\mini[(.+)]/) { "" }
      mini_c = $1
      if mini_c != nil
        if mini_c.to_i > 0
        mini_c = $game_actors[mini_c.to_i].name
        end
        mini_window(mini_c, wx, wy)
      end
      # "\gra[파일명, 파일 번호]"가 있으면 그래픽을 표시
      @text.gsub!(/\gra[(.+),s*(d+)]/) { "" }
      if $1 != nil and $2 != nil
        window_graphic(GRA_DIR + $1, $2.to_i, wx, wy)
      else
        @graphic = false # 그래픽 표시 플래그
        @gw = 0
      end
      self.index = -1
      self.visible = false
      @contents_showing = false
    end
    self.z = 1000
    self.opacity = OPACITY
    self.back_opacity = BACK_OPACITY
    @fade_in = false
    @fade_out = false
    @next_page = false  # 개페이지 플래그
    @ww = ww
    @wh = wh
    update
  end
  #-----------------------------------------------------------------------------
  # ● 해방
  #-----------------------------------------------------------------------------
  def dispose
    return if self.disposed?
    self.pause = false
    # 윈두우와 메세지를 페이드아웃
    while(not @command and self.opacity > 0)
      Graphics.update
      self.contents_opacity -= 64
      self.opacity -= @fade_speed
      if @mini_win
        @mini_txt.opacity -= 64
        @mini_win.opacity -= @fade_speed
      end
      if @graphic
        @gr.opacity -= @fade_speed
      end
      self.opacity
    end
    @fade_out = false
    @contents_showing = false
    @next_page = false
    super()
    if @mini_win
      @mini_win.dispose
      @mini_txt.dispose
    end
    if @graphic
      @gr.dispose
      @grahic = false
    end
    if @command
      @command = false
      @cancel = false
    end
    $game_temp.message_window_showing = false
  end
  #-----------------------------------------------------------------------------
  # ● 리프레쉬 : 메세지 묘화 처리
  #-----------------------------------------------------------------------------
  def refresh
    self.contents.clear
    if Font.exist?(FONT.name)
      self.contents.font = FONT
    end
    self.contents.font.color = normal_color
    @graphic ? x = @gw : x = 0
    y = 0
    @text.gsub!(/\[Cc][([0-9]+)]/) { "01[#{$1}]" } # "\C[n]" => "01"
    @text.gsub!(/\[Ff]n/) { "02" }  # "\Fn" => "02"
    @text.gsub!(/\[Ff]/) { "02" }    # "\F" => "02"
    @text.gsub!(/\[Vv][(d+)]/){ ($game_variables[$1.to_i]).to_s }
    while ((c = @text.slice!(/./m)) != nil)
      if c == "01"
        @text.sub!(/[([0-9]+)]/, "")
        color = $1.to_i
        if color >= 0 and color <= 7
          self.contents.font.color = text_color(color)
        end
        next
      end
      # n 의 경우 : 개행 처리
      if c == "n"
        @graphic ? x = @gw : x = 0
        y += FONT.size + LINE_SPACE
        next
      end
      w = self.contents.text_size(c).width
      h = self.contents.text_size(c).height
      # \F or 문장이 하단까지 왔을 경우 : 개페이지
      if c == "02" or y >= @wh - ( FONT.size + 32)
        x = y = 0
        text = c == "02" ? "" : c
        while ((c = @text.slice!(/./m)) != nil)
          text += c # 개페이지 후의 캐릭터 라인
        end
        @text = text
        @next_page = true # 개페이지 플래그
        break
      else
        self.contents.draw_text(4 + x, y , w, h, c)
      end
      x += w
      # 문장이 우단까지 오면(자) 강제적으로 개행
      if x >= @ww - (FONT.size + 28)
        y += FONT.size + LINE_SPACE
        x = @graphic ? @gw : 0
      end
    end    # while [END]
  end
  #-----------------------------------------------------------------------------
  # ● 프레임 갱신
  #-----------------------------------------------------------------------------
  def update
    loop do
      Graphics.update
      Input.update
      super
      # 용명
      if @fade_in
        self.contents_opacity += @fade_speed
        if @graphic
          @gr.opacity += @fade_speed
        end
        if @mini_win
          @mini_txt.opacity += @fade_speed
        end
        if self.contents_opacity == 255
          @fade_in = false
        end
        next
      end
      if @contents_showing    # 메세지 표시중의 경우
        if @pause_show == true
          self.pause = true    # 포즈 싸인을 표시
        end
        # B (캔슬)
        if Input.trigger?(Input::B)
          if @command    # 커멘드
            $game_system.se_play($data_system.cancel_se)
            if @cancel  # 캔슬의 경우 한층 더 분기
              $game_variables[RESULT] = @text.nitems  # 요소수+1을 대입
              break
            end
            next
          end
          break
        end
        # C (결정)
        if Input.trigger?(Input::C)
          if @command    # 커멘드
            # 선택 불가
            if @disable[self.index]
              $game_system.se_play($data_system.buzzer_se)
            else
              $game_system.se_play($data_system.decision_se)
              $game_variables[RESULT] = self.index  # 항목 번호를 대입[0~n]
              break
            end
          else
            break
          end
        end
        next
      end    # if @contents_showing [END]
      # 페이드아웃중이 아니고, 표시 대기 메세지가 있다
      if @fade_out == false and @text != nil and not @command
        @contents_showing = true    # 메세지 표시중
        $game_temp.message_window_showing = true
        refresh
        Graphics.frame_reset
        self.visible = true
        self.contents_opacity = 0
        @fade_in = true
        next
      end
      # 표시해야 할 메세지가 없고, 윈도우가 가시 상태의 경우
      if self.visible
        @fade_out = true
        self.opacity -= 48
        if self.opacity == 0
          self.visible = false
          @fade_out = false
          $game_temp.message_window_showing = false
        end
        next
      end
    end    # loop do [END]
    # 개페이지
    if @next_page
      # 메세지만 페이드아웃
      while(self.contents_opacity > 0)
        Graphics.update
        self.contents_opacity -= @fade_speed
      end
      @fade_out = false
      @contents_showing = false
      @next_page = false  # 개페이지
      update
    end
    if @command    # 커멘드의 경우는 선택 후, 해방
      dispose
    end
  end
  #--------------------------------------------------------------------------
  # ● 커멘드 리프레쉬
  #--------------------------------------------------------------------------
  def refresh_command(ch)
    @item_max = @text.size
    self.contents = Bitmap.new(width - 32, height - 32)
    if Font.exist?(FONT.name)
      self.contents.font = FONT
    end
    for i in 0...@item_max
      self.contents.font.color = @disable[i] ? disabled_color : normal_color
      c = @text[i].dup
      c.gsub!(/\[Vv][(d+)]/){ ($game_variables[$1.to_i]).to_s }
      w = @cw / @column_max
      @ch = self.contents.text_size(c).height
      x = (i % @column_max) * w
      y = (i / @column_max) * (@ch + LINE_SPACE) + LINE_SPACE / 2
      self.contents.draw_text(x + 4, y, w, @ch, c, 0)
    end
  end
  #--------------------------------------------------------------------------
  # ● 커서의 구형 갱신
  #--------------------------------------------------------------------------
  def update_cursor_rect
    # 커서 위치가 0 미만의 경우
    if @index < 0
      self.cursor_rect.empty
      return
    end
    # 현재의 행을 취득
    row = @index / @column_max
    # 현재의 행이, 표시되고 있는 선두의 행보다 전의 경우
    if row < self.top_row
      # 현재의 행이 선두가 되도록(되듯이) 스크롤
      self.top_row = row
    end
    # 현재의 행이, 표시되고 있는 최후미의 행부터 뒤의 경우
    if row > self.top_row + (self.page_row_max - 1)
      # 현재의 행이 최후미가 되도록(되듯이) 스크롤
      self.top_row = row - (self.page_row_max - 1)
    end
    h = FONT.size + LINE_SPACE
    # 커서의 폭을 계산
    w = self.width / @column_max - h
    # 커서의 좌표를 계산
    x = @index % @column_max * (w + h)
    y = @index / @column_max * h - self.oy
    # 커서의 구형을 갱신
    self.cursor_rect.set(x, y, w, h)
  end
  #--------------------------------------------------------------------------
  # ● 미니 윈도우
  #--------------------------------------------------------------------------
  def mini_window(text, wx, wy)
    @text_mn = text
    @mini_txt = Sprite.new
    @mini_txt.z = 5000
    @mini_txt.bitmap = Bitmap.new(640, 480)
    b = @mini_txt.bitmap
    if Font.exist?(FONT.name)
      b.font = FONT
    end
    @cw = b.text_size(@text_mn).width
    @ch = b.text_size(@text_mn).height
    @cx = wx + 12
    @cy = wy - (@ch + 24) + 12
    b.clear
    b.draw_text(@cx, @cy, @cw, @ch, @text_mn, 0)
    @mini_txt.opacity = 0
    @mini_win = Window_Base.new(wx, wy, @cw + 24, @ch + 24)
    @mini_win.x = wx
    @mini_win.y = wy - (@ch + 24)
    @mini_win.z = 2000
    @mini_win.opacity = OPACITY
    @mini_win.back_opacity = BACK_OPACITY
  end
  #--------------------------------------------------------------------------
  # ● 그래픽
  #--------------------------------------------------------------------------
  def window_graphic(filename, number, wx, wy)
    @gr = Sprite.new
    @gr.bitmap = Bitmap.new(filename)
    @gw = @gr.bitmap.width
    gh = @gr.bitmap.height
    @gr.ox = 0
    @gr.oy = 0
    if (gnum = number - 1) >= 0  # 그래픽 번호(0-16)
      gx = (@gw / 4) * (gnum % 4)
      gy = (gh / 4) * (gnum / 4)
      @gw = @gw / 4
      gh = gh / 4
      @gr.src_rect.set(gx, gy, @gw, gh)  # 파일을 16 분할(4*4)해 표시
    else
      @gr.src_rect.set(0, 0, @gw, gh)  # 파일을 그대로 표시
    end
    @gr.x = wx + 16
    @gr.y = wy + 16
    @gr.z = 3000
    @gr.opacity = 0
    @graphic = true # 그래픽 표시 플래그
  end
end


스크립트가 표시되면(자),[Ctrl]+A,[Ctrl]+C로 전체를 카피합니다.
트크르 XP의 스크립트 편집자를 열어, 「Window_Selectable」보다 아래에서 오른쪽 클릭 메뉴 「삽입」,
새롭게 할 수 있던 섹션에 본체를 붙여 주세요.


사용예
────────────────────────────────────────────────
실행은 이벤트 커멘드 「스크립트」로 실시합니다.
이벤트가 정상적으로 실행되도록, 「스크립트」의 전후에는 「웨이트」(1 프레임)을 두는 것을 추천합니다.


■ 메세지 윈도우를 표시
┌────────────────────────┐
│w = Free_Window.new("abcde...", 80, 50, 304, 100) │
│w.dispose                   │
└────────────────────────┘

인수는 왼쪽으로부터 표시하는 캐릭터 라인, 윈도우 위치 x, 윈도우 위치 y, 윈도우폭, 윈도우 높이입니다.


────────────────────────────────────────────────

■ 복수의 메세지 윈도우를 표시
┌─────────────────────┐
│s = "메세지n메세지"           │
│w1 = Free_Window.new(s, 80, 50, 304, 120)  │
│s =                     │
│"메세지                   │
│메세지"                   │
│w2 = Free_Window.new(s, 80, 250, 304, 120) │
│w1.dispose                 │
│w2.dispose                 │
└─────────────────────┘

이 예에서는 캐릭터 라인을 한 번 로컬 변수 s에 격납해, 그것을 참조시키고 있습니다.
n는 개행을 나타내기 때문에, 결과적으로 어느 쪽의 윈도우도 같은 내용이 표시됩니다.


────────────────────────────────────────────────

(이하, 오브젝트 생성 등 같은 기술은 생략 합니다)
■ 좌상에 작은 윈도우를 표시

┌───────────┐
│"\mini[아르시스]「?"│
└───────────┘

제어 문자 \mini[s]는 캐릭터 라인 s를 미니 윈도우에 표시합니다.

┌────────┐
│"\mini[1]「···."│
└────────┘

숫자로 지정하면(자) 그 번호의 엑터명을 표시합니다.



───────────────────────────────────────────────

■ 윈도우에 그래픽 표시
┌──────────────────┐
│"\gra[Battlers/001-Fighter01, 0]「!" │
└──────────────────┘

제어 문자 \gra[filename, number]는, 지정한 그래픽 파일(filename)을 표시합니다.
또, , (반각 칸마)그리고 단락지어 표시 방법을 번호로 지정할 수 있습니다.
0 때, 지정한 화상을 그대로 표시합니다.
1~16 때, 화상을 세로 4 분할, 옆 4 분할했을 때에 할당해지는 번호에 일치하는 그래픽을 표시합니다.



────────────────────────────────────────────────

■ 커멘드 윈도우를 표시
┌──────────────────┐
│s = ["선택 1", "선택 2", "선택 3"]    │
│Free_Window.new(s, 80, 50, 150, 200) │
└──────────────────┘

제일 인수를 배열로 하면(자), 커멘드 윈도우가 됩니다.
커멘드 윈도우는 dispose를 호출할 필요는 없습니다.
선택한 결과는 소스내에서 지정한 번호의 변수에 대입됩니다.
이 예에서는 「선택 1」 때 0, 「선택 2」 때 1, 「선택 3」 때 2가 변수에 대입됩니다.

┌──────────────────┐
│["선택 1", "선택 2", "선택 3", "!cancel"] │
└──────────────────┘

배열의 말미의 요소를"!cancel"로 하면(자), 캔슬 버튼을 눌렀을 때에, 지정한 변수에 요소의 수가 대입됩니다.(이 예에서는 변수에 3을 대입)

┌─────────────────┐
│[3, "A1", "A2", "A3", "B1", "B2", "B3"]  │
└─────────────────┘

배열의 최초의 요소를 정수로 하면(자), 열을 복수로 할 수 있습니다. 이 예의 경우, 다음과 같은 및 됩니다.

A1  A2  A3
B1  B2  B3

┌────────────────────────────────┐
│["\x아르시스", "그로리아 \x", "히르다"]  #=> 히르다만 선택 가능 │
└────────────────────────────────┘

항목이 되는 캐릭터 라인의 최초인가 마지막에 「\x」인가 「\X」를 넣으면(자), 그 항목은 선택 불가(회색 표시/버저 SE)가 됩니다. 다만, 모든 항목을 선택 불가로 하면(자) 게임이 진행되지 않게 될테니 주의해 주세요.
「\x」는 바트(×)이니까 선택할 수 없다, 라고 기억합시다.