Project1

标题: ISA——支持子选项的选择窗口(理论支持无限层) [打印本页]

作者: 沙漠点灰    时间: 2011-4-3 10:04
标题: ISA——支持子选项的选择窗口(理论支持无限层)
本帖最后由 沙漠点灰 于 2011-4-3 10:16 编辑

先上效果图(?):



比较鸡肋...
关于这个脚本的用法,稍后会发放范例(http://rpg.blue/thread-174282-1-1.html)

这张截图里面用的格式是:

    commands = ["dust",["a","b",["c","c1",["c1_1","c1_2","c1_3"]],"d","f"],"p"]
    @folder_window = Window_Folder.new(50,96,480,32*8,commands)

有点晕...?数组类(含子选项要求超过1个)会判定为"文件夹",该数组第2,3一直到最后1个会判定为
"子选项",当然,这些"子选项"还可以是"文件夹",以次类推

50,96,480,32*8 分别是x,y,宽,高

这个版本不是很完美,期待下个版本吧(不过极有可能TJ掉)

最后,上脚本(技术有限,比较臃肿...):
  1. #==============================================================================
  2. # ■ Window_Folder   ISA
  3. #------------------------------------------------------------------------------
  4. #  拥有光标的移动以及滚动功能、子项目的窗口类。
  5. #                          ISA
  6. #   制作       : 沙漠.灰
  7. #   本脚本版本 : v0.9     P.S : 制作中遇到了一个Bug,找了3个小时,不惜动用rescue
  8. #        最后发现是 if @folder_window.index = [0,2] .....写成了 = 号了...
  9. #
  10. #   本脚本很无敌(指的是Bug方面).欢迎各位朋友进行优化及DeBug
  11. #==============================================================================

  12. class Window_Folder < Window_Base
  13.   #--------------------------------------------------------------------------
  14.   # ● 定义实例变量
  15.   #--------------------------------------------------------------------------
  16.   attr_reader   :index                    # 光标位置
  17.   attr_reader   :c                        # C 键允许
  18.   #--------------------------------------------------------------------------
  19.   # ● 初始画对像
  20.   #     x      : 窗口的 X 坐标
  21.   #     y      : 窗口的 Y 坐标
  22.   #     width  : 窗口的宽
  23.   #     height : 窗口的高
  24.   #--------------------------------------------------------------------------
  25.   def initialize(x,y,width, height, commands)
  26.     super(x, y, width, height)
  27.     # 初始化数据
  28.     @move_to        = 0
  29.     @to_refresh     = false
  30.     @commands_size  = 0
  31.     @c              = false
  32.     @index          = [0]
  33.     @spread_command = []
  34.     @disable_item   = []
  35.     commands.size.times{@spread_command.push(1)}
  36.     @true_commands  = commands
  37.     # 初始化所有项目
  38.     ini_command @true_commands
  39.     # 生成位图
  40.     self.contents = Bitmap.new(width - 32, @commands_size * 32)
  41.     v = Viewport.new(16+self.x, 16+self.y, width-32, height-32) ; v.z = 999
  42.     @new_bitmap = Sprite.new(v)
  43.     @new_bitmap.bitmap = Bitmap.new(width - 32, @commands_size * 32)
  44.     index = 0 # 描绘顶层项目
  45.     # 描绘父项目
  46.     for unit in @true_commands
  47.       # 描写项目
  48.       draw_command [index]
  49.       # index 前进1
  50.       index += 1
  51.     end
  52.   end
  53.   #--------------------------------------------------------------------------
  54.   # ● 初始化所有项目 array : 父项目
  55.   #--------------------------------------------------------------------------
  56.   def ini_command(array)
  57.     for unit in array
  58.       if unit.is_a?(Array)
  59.         unit.size > 1 ? ini_command(unit): @commands_size += 1
  60.       else
  61.         @commands_size += 1
  62.       end
  63.     end
  64.   end
  65.   #--------------------------------------------------------------------------
  66.   # ● 项目无效化
  67.   #     index : 项目编号
  68.   #--------------------------------------------------------------------------
  69.   def disable_item(index)
  70.     @disable_item.push(index)
  71.   end
  72.   #--------------------------------------------------------------------------
  73.   # ● 指定项目是否为父项目 index 所在位置
  74.   #--------------------------------------------------------------------------
  75.   def is_folder?(commands,index)
  76.     # 若指定项目为数组且子单元数目大于1就判定为父项目
  77.     if index.size == 1 and commands[index[0]].is_a?(Array)
  78.       return true if commands[index[0]].size > 1
  79.     elsif index.size > 1
  80.       return is_folder?(commands[index[0]],index[1...index.size])
  81.     end
  82.     # 否则就判定为非父项目
  83.     return false
  84.   end
  85.   #--------------------------------------------------------------------------
  86.   # ● 描绘项目名称 index 所在位置  branch 是否分支
  87.   #--------------------------------------------------------------------------
  88.   def draw_command(index,branch=false)
  89.     # 查看当前index所在坐标
  90.     x, y = check_index_xy(index)
  91.     rect = Rect.new(x+32,y,self.width-32,32)
  92.     self.contents.font.color = disabled_color if @disable_item.include?(index)
  93.     name = get_command(@true_commands,index)
  94.     self.contents.draw_text(rect, name)
  95.     # 为父项目时,描绘指引
  96.     if is_folder?(@true_commands,index)
  97.       draw_flag(index,branch)
  98.     end
  99.     self.contents.font.color = normal_color
  100.   end
  101.   #--------------------------------------------------------------------------
  102.   # ● 取得项目名称 index 所在位置
  103.   #--------------------------------------------------------------------------
  104.   def get_command(name_array,index)
  105.     # 当index到底时(只有一个单元时)
  106.     return get_command_name(name_array[index[0]]) if index.size == 1
  107.     # 没到底,删除首单元,继续调用自己
  108.     # 删除首单元?为嘛不用shift?   因为shift删除首单元,并返回它...
  109.     return get_command name_array[index[0]],index[1...index.size]
  110.   end
  111.   #--------------------------------------------------------------------------
  112.   # ● 再次 取得项目名称 index 所在位置
  113.   #--------------------------------------------------------------------------
  114.   def get_command_name(name_array)
  115.     if name_array.is_a?(String)
  116.       # 目前已经为字符串时,直接返回
  117.       return name_array
  118.     else
  119.       # 目前为数组且数组第X个还是数组时,调用并返回自己
  120.       if name_array[0].is_a?(Array)
  121.         return get_command_name(name_array[0])
  122.       else
  123.         # 第X个为字符串,直接返回
  124.         return name_array[0]
  125.       end
  126.     end
  127.   end
  128.   #--------------------------------------------------------------------------
  129.   # ● 描绘项目标记 index 所在位置
  130.   #--------------------------------------------------------------------------
  131.   def draw_flag(index,branch=false)
  132.     # 查看当前index所在坐标
  133.     x, y = check_index_xy index
  134.     src_rect  = Rect.new(x+16,y+10,16,16)
  135.     # 清除原来标记
  136.     self.contents.fill_rect(src_rect, Color.new(0,0,0,0))
  137.     dest_rect = branch ? Rect.new(152, 40, 16, 16): Rect.new(168, 24, 16, 16)
  138.     src_bitmap= RPG::Cache.windowskin($game_system.windowskin_name)
  139.     # 图上现在标记
  140.     self.contents.stretch_blt(src_rect, src_bitmap, dest_rect)
  141.   end
  142.   #--------------------------------------------------------------------------
  143.   # ● 检查 index 所在坐标
  144.   #--------------------------------------------------------------------------
  145.   def check_index_xy(index)
  146.     y = 0
  147.     # 检查项目     多1项,y+32
  148.     for i in 0...@spread_command.size
  149.       # 检查缩进项目,为数组时,进一步检查
  150.       if @spread_command[i].is_a?(Array)
  151.         # 在这个项目活动....
  152.         if index.size > 1  
  153.           y += check_spread(@spread_command[i], index[1...index.size])
  154.         else
  155.           # 否则,加1行
  156.           y += 32
  157.         end
  158.       else
  159.         # 上次的没关闭,则自相加
  160.         #if @spread_command[i-1].is_a?(Array)
  161.           #y += @spread_command[i-1].self_all_plus * 32 - 32
  162.         #end
  163.         # 这个版本不支持↑,这里直接加32
  164.         y += 32#@spread_command[i] * 32
  165.       end
  166.       break if index[0] <= i
  167.     end
  168.     # 检查本index所有上面的展开数
  169.     #size = size(index)*32
  170.     # 多1层,x+32
  171.     return index.new_to_s.size/3*32-32, y-32
  172.   end
  173.   #--------------------------------------------------------------------------
  174.   # ● 检查展开项目,返回项目数
  175.   #--------------------------------------------------------------------------
  176.   def check_spread(spread_array,index)
  177.     y = 0
  178.     # 检查项目     多1项,y+32
  179.     for i in 0...spread_array.size
  180.       # 检查缩进项目,为数组时,进一步检查
  181.       if spread_array[i].is_a?(Array)
  182.         # 在这个项目活动....
  183.         if index.size > 1
  184.           y += check_spread(spread_array[i],index[1...index.size])
  185.         else
  186.           # 否则,加1行
  187.           y += 32
  188.         end
  189.       else
  190.         # 上次的没关闭,则自相加
  191.         #if @spread_command[i-1].is_a?(Array)
  192.           #y += @spread_command[i-1].self_all_plus * 32 - 32
  193.         #end
  194.         # 这个版本不支持↑,这里直接加32
  195.         y += 32#@spread_command[i] * 32
  196.       end
  197.       break if index[0] <= i
  198.     end
  199.     return y
  200.   end
  201.   #--------------------------------------------------------------------------
  202.   # ● 释放
  203.   #--------------------------------------------------------------------------
  204.   def dispose
  205.     # 释放新的位图 精灵
  206.     @new_bitmap.bitmap.dispose
  207.     @new_bitmap.dispose
  208.     super
  209.   end
  210.   #--------------------------------------------------------------------------
  211.   # ● 设置光标的位置
  212.   #     index : 新的光标位置
  213.   #--------------------------------------------------------------------------
  214.   def index=(index)
  215.     @index = index
  216.     # 刷新光标矩形
  217.     update_cursor_rect
  218.   end
  219.   #--------------------------------------------------------------------------
  220.   # ● 检查指定项目大小 index :
  221.   #--------------------------------------------------------------------------
  222.   def check_command_size(index,commands=@true_commands)
  223.     # 在次选项下,返回次commands的单元数
  224.     return commands.size  if index.size == 1
  225.     # 删首调自
  226.     return check_command_size(index[1...index.size],commands[index[0]])
  227.   end
  228.   #--------------------------------------------------------------------------
  229.   # ● 关闭\展开父选项
  230.   #--------------------------------------------------------------------------
  231.   def folder(index,close=true)
  232.     if close
  233.       # 关闭时
  234.       # 如果当前为父选项,关闭它,若已经关闭,关闭此层(顶层除外)
  235.       # 把需关闭的子项目清空,10帧淡入淡出
  236.       if closed?(index)
  237.         # 顶层...?
  238.         return if index.size == 1
  239.         # 关闭上层
  240.         folder(index[0...index-1],close)
  241.         return
  242.       end
  243.       x1, y1 = check_index_xy(index)
  244.       new_height = check_command_size(index+[1]) * 32
  245.       Graphics.freeze
  246.       eval("@spread_command#{@index.new_to_s} = 1 ")
  247.       src_rect      = Rect.new(0,0,self.width,self.contents.height)
  248.       dest_rect     = Rect.new(0,y1+new_height,self.width,self.contents.height)
  249.       @new_bitmap.bitmap.stretch_blt(src_rect, self.contents, dest_rect)
  250.       # 把当前信息"剪切"到新位图上,使之移动
  251.       src_rect  = Rect.new(0,y1,self.width,self.contents.height)
  252.       self.contents.fill_rect(src_rect, Color.new(0,0,0,0))
  253.       @new_bitmap.y= y1 + new_height
  254.       @move_to     = -new_height + 32
  255.       @to_refresh  = -1
  256.       draw_command(@index,false)
  257.       Graphics.transition(10)
  258.     else
  259.       # 展开时
  260.       # 如果当前为父选项,展开它,若已经展开,什么也不做
  261.       # 把需展开的子项目写入位图,10帧淡入淡出
  262.       return if !is_folder?(@true_commands,index)
  263.       if !closed?(index)
  264.         @index.push(1)
  265.         return
  266.       end
  267.       new_height = check_command_size(index+[0]) * 32 - 32
  268.       x1, y1 = check_index_xy(index+[0])
  269.       @new_bitmap.bitmap.clear
  270.       @new_bitmap.y = y1 + 32
  271.       src_rect      = Rect.new(0 ,0    ,self.width,self.contents.height)
  272.       dest_rect     = Rect.new(0,y1+32,self.width,self.contents.height)
  273.       @new_bitmap.bitmap.stretch_blt(src_rect, self.contents, dest_rect)
  274.       # 把当前信息"剪切"到新位图上,使之移动
  275.       src_rect  = Rect.new(0,y1,self.width,self.contents.height)
  276.       self.contents.fill_rect(src_rect, Color.new(0,0,0,0))
  277.       @move_to     = new_height
  278.       @to_refresh  = 1
  279.       draw_command(@index,true)
  280.       size = "1," * check_command_size(@index+[0])
  281.       eval("@spread_command#{@index.new_to_s} = [#{size}] ")
  282.     end
  283.   end
  284.   #--------------------------------------------------------------------------
  285.   # ● 移动项目
  286.   #--------------------------------------------------------------------------
  287.   def move_command
  288.     if @move_to == 0 and @to_refresh != 0
  289.       if @to_refresh == 1
  290.         @to_refresh = 0
  291.         for i in 1...check_command_size(@index+[0])
  292.           draw_command(@index+[i])
  293.         end
  294.         Graphics.freeze
  295.         # "剪切"回来
  296.         src_rect  = Rect.new(@new_bitmap.x,@new_bitmap.y,self.width,self.contents.height)
  297.         dest_rect = Rect.new(0,0,self.width,self.contents.height)
  298.         self.contents.stretch_blt(src_rect, @new_bitmap.bitmap, dest_rect)
  299.         @new_bitmap.bitmap.clear
  300.         Graphics.transition(10)
  301.         @index.push(1)
  302.       else
  303.         @to_refresh = 0
  304.         # "剪切"回来
  305.         src_rect  = Rect.new(@new_bitmap.x,@new_bitmap.y,self.width,self.contents.height)
  306.         dest_rect = Rect.new(0,0,self.width,self.contents.height)
  307.         self.contents.stretch_blt(src_rect, @new_bitmap.bitmap, dest_rect)
  308.         @new_bitmap.bitmap.clear
  309.       end
  310.     end
  311.     return if @move_to == 0
  312.     step = @move_to/@move_to.abs * 4
  313.     @move_to -= step
  314.     @new_bitmap.y += step
  315.   end
  316.   #--------------------------------------------------------------------------
  317.   # ● 父选项已关闭?
  318.   #--------------------------------------------------------------------------
  319.   def closed?(index,commands=@spread_command)
  320.     # @spread_command 记录着展开的信息:若为数组,则展开;否则,关闭
  321.     return true if !commands[index[0]].is_a?(Array)
  322.     return closed?(index[1...index.size],commands[index[0]]) if index.size > 1
  323.     return false
  324.   end
  325.   #--------------------------------------------------------------------------
  326.   # ● 刷新画面
  327.   #--------------------------------------------------------------------------
  328.   def update
  329.     super
  330.     move_command
  331.     return if @to_refresh != 0
  332.     # 可以移动光标的情况下
  333.     if self.active
  334.       # 方向键下被按下的情况下
  335.       if Input.repeat?(Input::DOWN)
  336.         $game_system.se_play($data_system.cursor_se)
  337.         # 跳跃到下一个同层选项
  338.         @index[-1] = (@index[-1]+1)%check_command_size(@index)
  339.         @index[-1] += 1 if @index.size > 1 and @index[-1] == 0
  340.       end
  341.       # 方向键上被按下的情况下
  342.       if Input.repeat?(Input::UP)
  343.         # 跳跃到上一个同层选项
  344.         $game_system.se_play($data_system.cursor_se)
  345.         # 跳跃到下一个同层选项
  346.         @index[-1] -= 1 if @index.size > 1 and @index[-1] == 1
  347.         @index[-1] = (@index[-1]-1)%check_command_size(@index)
  348.       end
  349.       # A键被按下的情况下
  350.       if Input.trigger?(Input::A)
  351.         # 展开\关闭 当前选项,展开优先
  352.         # 这个功能暂时被和谐掉...
  353.         #p @new_bitmap.x, @new_bitmap.y
  354.       end  
  355.       # B键被按下的情况下
  356.       if Input.trigger?(Input::B)
  357.         # 退到上一层,若允许关闭,则关闭
  358.         if @index.size == 1
  359.           $game_system.se_play($data_system.buzzer_se)
  360.         else
  361.           @index.pop
  362.           $game_system.se_play($data_system.cancel_se)
  363.           # 允许关闭的情况下
  364.           folder(@index) # if $game_party.closed_by_b
  365.         end
  366.       end
  367.       # C键被按下的情况下
  368.       if Input.trigger?(Input::C)
  369.         @c = !is_folder?(@true_commands,@index)
  370.         # 展开当前选项,不能展开时,打开允许C键键入开关(否则关掉)
  371.         # 等待场景捕捉动作
  372.         if is_folder?(@true_commands,@index)
  373.           $game_system.se_play($data_system.decision_se)
  374.           folder(@index,false)
  375.         end
  376.       end
  377.     end
  378.     # 刷新光标矩形
  379.     update_cursor_rect
  380.   end
  381.   #--------------------------------------------------------------------------
  382.   # ● 更新光标矩形
  383.   #--------------------------------------------------------------------------
  384.   def update_cursor_rect
  385.     x, y = check_index_xy(@index)
  386.     # 超出范围,更新self.oy
  387.     if y - self.oy >= self.height - 32
  388.       self.oy        += 32
  389.       @new_bitmap.oy += 32
  390.     elsif y - self.oy < 0
  391.       self.oy        -= 32
  392.       @new_bitmap.oy -= 32
  393.     end
  394.     # 更新光标矩形
  395.     self.cursor_rect.set(x, y-self.oy, [email protected]_to_s.size/3*32, 32)
  396.   end
  397. end
  398. #==============================================================================
  399. # ■ Array
  400. #------------------------------------------------------------------------------
  401. #  数组类  又拿数组开刀...
  402. #==============================================================================

  403. class Array
  404.   #--------------------------------------------------------------------------
  405.   # ● 转换 新 字符串
  406.   #--------------------------------------------------------------------------
  407.   def new_to_s
  408.     string = ""
  409.     for unit in self
  410.       string += "[#{unit}]"
  411.     end
  412.     return string
  413.   end
  414. =begin
  415.   #--------------------------------------------------------------------------
  416.   # ● 自相加
  417.   #--------------------------------------------------------------------------
  418.   def self_all_plus(array=self)
  419.     plus = 0
  420.     for unit in self
  421.       if unit.is_a?(Array)
  422.         plus += self_all_plus(unit)
  423.       else
  424.         plus += unit.to_i
  425.       end
  426.     end
  427.     return plus
  428.   end
  429. =end
  430. end
复制代码

作者: SVM伟    时间: 2011-4-3 12:47
432行,的确蛮臃肿的,估计可以大幅度缩水
作者: kuerlulu    时间: 2013-8-13 17:15
坟= =
LZ签名碉堡!如果是用RM做的我也要做一个




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1