如何优雅的研究 RGSS3 (六) 技能与物品画面剖析

来源:互联网 发布:外国人用什么软件 编辑:程序博客网 时间:2024/05/17 03:15
物品与技能画面剖析


物品画面和技能画面有共同的父类 Scene_ItemBase,而 Scene_ItemBase 继承自 Scene_MenuBase。


Scene_ItemBase 在开始时用 create_actor_window 生成了显示角色的窗口备用。
Scene_ItemBase 中定义了若干方法作为处理画面的工具。
其中 show_sub_window、hide_sub_window 可以显示、隐藏一个窗口。
item、user用于获取选中的物品与使用者。
on_actor_ok、on_actor_cancel 确定或取消选择角色。
以及一整套判断与处理物品的方法。
#encoding:utf-8#==============================================================================# ■ Scene_ItemBase#------------------------------------------------------------------------------#  物品画面和技能画面的共同父类#==============================================================================class Scene_ItemBase < Scene_MenuBase  #--------------------------------------------------------------------------  # ● 开始处理  #--------------------------------------------------------------------------  def start    super    create_actor_window  end  #--------------------------------------------------------------------------  # ● 生成角色窗口  #--------------------------------------------------------------------------  def create_actor_window    @actor_window = Window_MenuActor.new    @actor_window.set_handler(:ok,     method(:on_actor_ok))    @actor_window.set_handler(:cancel, method(:on_actor_cancel))  end  #--------------------------------------------------------------------------  # ● 获取当前选中的物品  #--------------------------------------------------------------------------  def item    @item_window.item  end  #--------------------------------------------------------------------------  # ● 获取物品的使用者  #--------------------------------------------------------------------------  def user    $game_party.movable_members.max_by {|member| member.pha }  end  #--------------------------------------------------------------------------  # ● 判定光标是否在左列  #--------------------------------------------------------------------------  def cursor_left?    @item_window.index % 2 == 0  end  #--------------------------------------------------------------------------  # ● 显示子窗口  #--------------------------------------------------------------------------  def show_sub_window(window)    width_remain = Graphics.width - window.width    window.x = cursor_left? ? width_remain : 0    @viewport.rect.x = @viewport.ox = cursor_left? ? 0 : window.width    @viewport.rect.width = width_remain    window.show.activate  end  #--------------------------------------------------------------------------  # ● 隐藏子窗口  #--------------------------------------------------------------------------  def hide_sub_window(window)    @viewport.rect.x = @viewport.ox = 0    @viewport.rect.width = Graphics.width    window.hide.deactivate    activate_item_window  end  #--------------------------------------------------------------------------  # ● 角色“确定”  #--------------------------------------------------------------------------  def on_actor_ok    if item_usable?      use_item    else      Sound.play_buzzer    end  end  #--------------------------------------------------------------------------  # ● 角色“取消”  #--------------------------------------------------------------------------  def on_actor_cancel    hide_sub_window(@actor_window)  end  #--------------------------------------------------------------------------  # ● 确定物品  #--------------------------------------------------------------------------  def determine_item    if item.for_friend?      show_sub_window(@actor_window)      @actor_window.select_for_item(item)    else      use_item      activate_item_window    end  end  #--------------------------------------------------------------------------  # ● 启用物品窗口  #--------------------------------------------------------------------------  def activate_item_window    @item_window.refresh    @item_window.activate  end  #--------------------------------------------------------------------------  # ● 获取物品的使用目标数组  #--------------------------------------------------------------------------  def item_target_actors    if !item.for_friend?      []    elsif item.for_all?      $game_party.members    else      [$game_party.members[@actor_window.index]]    end  end  #--------------------------------------------------------------------------  # ● 判定物品是否可以使用  #--------------------------------------------------------------------------  def item_usable?    user.usable?(item) && item_effects_valid?  end  #--------------------------------------------------------------------------  # ● 判定物品的效果是否有效  #--------------------------------------------------------------------------  def item_effects_valid?    item_target_actors.any? do |target|      target.item_test(user, item)    end  end  #--------------------------------------------------------------------------  # ● 对角色使用物品  #--------------------------------------------------------------------------  def use_item_to_actors    item_target_actors.each do |target|      item.repeats.times { target.item_apply(user, item) }    end  end  #--------------------------------------------------------------------------  # ● 使用物品  #--------------------------------------------------------------------------  def use_item    play_se_for_item    user.use_item(item)    use_item_to_actors    check_common_event    check_gameover    @actor_window.refresh  end  #--------------------------------------------------------------------------  # ● 公共事件预定判定  #    如果预约了事件的调用,则切换到地图画面。  #--------------------------------------------------------------------------  def check_common_event    SceneManager.goto(Scene_Map) if $game_temp.common_event_reserved?  endend



其使用物品的子类 Scene_Item 中在 start 中生成了自己独立的帮助窗口分类窗口与物品窗口。

在生成物品窗口的最后,将生成的物品窗口实例传递给了分类窗口。

#encoding:utf-8#==============================================================================# ■ Scene_Item#------------------------------------------------------------------------------#  物品画面#==============================================================================class Scene_Item < Scene_ItemBase  #--------------------------------------------------------------------------  # ● 开始处理  #--------------------------------------------------------------------------  def start    super    create_help_window    create_category_window    create_item_window  end  #--------------------------------------------------------------------------  # ● 生成分类窗口  #--------------------------------------------------------------------------  def create_category_window    @category_window = Window_ItemCategory.new    @category_window.viewport = @viewport    @category_window.help_window = @help_window    @category_window.y = @help_window.height    @category_window.set_handler(:ok,     method(:on_category_ok))    @category_window.set_handler(:cancel, method(:return_scene))  end  #--------------------------------------------------------------------------  # ● 生成物品窗口  #--------------------------------------------------------------------------  def create_item_window    wy = @category_window.y + @category_window.height    wh = Graphics.height - wy    @item_window = Window_ItemList.new(0, wy, Graphics.width, wh)    @item_window.viewport = @viewport    @item_window.help_window = @help_window    @item_window.set_handler(:ok,     method(:on_item_ok))    @item_window.set_handler(:cancel, method(:on_item_cancel))    @category_window.item_window = @item_window  end  #--------------------------------------------------------------------------  # ● 分类“确定”  #--------------------------------------------------------------------------  def on_category_ok    @item_window.activate    @item_window.select_last  end  #--------------------------------------------------------------------------  # ● 物品“确定”  #--------------------------------------------------------------------------  def on_item_ok    $game_party.last_item.object = item    determine_item  end  #--------------------------------------------------------------------------  # ● 物品“取消”  #--------------------------------------------------------------------------  def on_item_cancel    @item_window.unselect    @category_window.activate  end  #--------------------------------------------------------------------------  # ● 播放使用物品声效  #--------------------------------------------------------------------------  def play_se_for_item    Sound.play_use_item  end  #--------------------------------------------------------------------------  # ● 使用物品  #--------------------------------------------------------------------------  def use_item    super    @item_window.redraw_current_item  endend


使用技能的子类 Scene_Skill 中多了指令窗口与状态窗口。物品窗口与 Scene_Item 中的是不同的。
#encoding:utf-8#==============================================================================# ■ Scene_Skill#------------------------------------------------------------------------------#  技能画面#   为了方便共通化处理,这里把技能也称为“物品”。#==============================================================================class Scene_Skill < Scene_ItemBase  #--------------------------------------------------------------------------  # ● 开始处理  #--------------------------------------------------------------------------  def start    super    create_help_window    create_command_window    create_status_window    create_item_window  end  #--------------------------------------------------------------------------  # ● 生成指令窗口  #--------------------------------------------------------------------------  def create_command_window    wy = @help_window.height    @command_window = Window_SkillCommand.new(0, wy)    @command_window.viewport = @viewport    @command_window.help_window = @help_window    @command_window.actor = @actor    @command_window.set_handler(:skill,    method(:command_skill))    @command_window.set_handler(:cancel,   method(:return_scene))    @command_window.set_handler(:pagedown, method(:next_actor))    @command_window.set_handler(:pageup,   method(:prev_actor))  end  #--------------------------------------------------------------------------  # ● 生成状态窗口  #--------------------------------------------------------------------------  def create_status_window    y = @help_window.height    @status_window = Window_SkillStatus.new(@command_window.width, y)    @status_window.viewport = @viewport    @status_window.actor = @actor  end  #--------------------------------------------------------------------------  # ● 生成物品窗口  #--------------------------------------------------------------------------  def create_item_window    wx = 0    wy = @status_window.y + @status_window.height    ww = Graphics.width    wh = Graphics.height - wy    @item_window = Window_SkillList.new(wx, wy, ww, wh)    @item_window.actor = @actor    @item_window.viewport = @viewport    @item_window.help_window = @help_window    @item_window.set_handler(:ok,     method(:on_item_ok))    @item_window.set_handler(:cancel, method(:on_item_cancel))    @command_window.skill_window = @item_window  end  #--------------------------------------------------------------------------  # ● 获取技能的使用者  #--------------------------------------------------------------------------  def user    @actor  end  #--------------------------------------------------------------------------  # ● 指令“技能”  #--------------------------------------------------------------------------  def command_skill    @item_window.activate    @item_window.select_last  end  #--------------------------------------------------------------------------  # ● 物品“确定”  #--------------------------------------------------------------------------  def on_item_ok    @actor.last_skill.object = item    determine_item  end  #--------------------------------------------------------------------------  # ● 物品“取消”  #--------------------------------------------------------------------------  def on_item_cancel    @item_window.unselect    @command_window.activate  end  #--------------------------------------------------------------------------  # ● 播放物品使用声效  #--------------------------------------------------------------------------  def play_se_for_item    Sound.play_use_skill  end  #--------------------------------------------------------------------------  # ● 使用物品  #--------------------------------------------------------------------------  def use_item    super    @status_window.refresh    @item_window.refresh  end  #--------------------------------------------------------------------------  # ● 切换角色  #--------------------------------------------------------------------------  def on_actor_change    @command_window.actor = @actor    @status_window.actor = @actor    @item_window.actor = @actor    @command_window.activate  endend



可见各种各样的窗口占了代码的大部分。


Window_Help 是显示说明的小窗口。

它在初始化时默认为占用两行。

它用 set_item(item) 将内容设置为指定物品或技能的描述。

#encoding:utf-8#==============================================================================# ■ Window_Help#------------------------------------------------------------------------------#  显示特技和物品等的说明、以及角色状态的窗口#==============================================================================class Window_Help < Window_Base  #--------------------------------------------------------------------------  # ● 初始化对象  #--------------------------------------------------------------------------  def initialize(line_number = 2)    super(0, 0, Graphics.width, fitting_height(line_number))  end  #--------------------------------------------------------------------------  # ● 设置内容  #--------------------------------------------------------------------------  def set_text(text)    if text != @text      @text = text      refresh    end  end  #--------------------------------------------------------------------------  # ● 清除  #--------------------------------------------------------------------------  def clear    set_text("")  end  #--------------------------------------------------------------------------  # ● 设置物品  #     item : 技能、物品等  #--------------------------------------------------------------------------  def set_item(item)    set_text(item ? item.description : "")  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    contents.clear    draw_text_ex(4, 0, @text)  endend




Window_ItemCategory 是将物品分类的窗口。

我们的物品被分为4类:物品、武器、防具、关键道具。

在分类窗口更新画面的过程中,不停的将物品窗口的分类设为当前选中的分类。

当分类被选中时 Scene_Item 中的 on_category_ok 被执行,激活了物品窗口。

#encoding:utf-8#==============================================================================# ■ Window_ItemCategory#------------------------------------------------------------------------------#  物品画面和商店画面中,显示装备、所持物品等项目列表的窗口。#==============================================================================class Window_ItemCategory < Window_HorzCommand  #--------------------------------------------------------------------------  # ● 定义实例变量  #--------------------------------------------------------------------------  attr_reader   :item_window  #--------------------------------------------------------------------------  # ● 初始化对象  #--------------------------------------------------------------------------  def initialize    super(0, 0)  end  #--------------------------------------------------------------------------  # ● 获取窗口的宽度  #--------------------------------------------------------------------------  def window_width    Graphics.width  end  #--------------------------------------------------------------------------  # ● 获取列数  #--------------------------------------------------------------------------  def col_max    return 4  end  #--------------------------------------------------------------------------  # ● 更新画面  #--------------------------------------------------------------------------  def update    super    @item_window.category = current_symbol if @item_window  end  #--------------------------------------------------------------------------  # ● 生成指令列表  #--------------------------------------------------------------------------  def make_command_list    add_command(Vocab::item,     :item)    add_command(Vocab::weapon,   :weapon)    add_command(Vocab::armor,    :armor)    add_command(Vocab::key_item, :key_item)  end  #--------------------------------------------------------------------------  # ● 设置物品窗口  #--------------------------------------------------------------------------  def item_window=(item_window)    @item_window = item_window    update  endend



Window_ItemList 显示持有的物品。

设置分类的方法 category 被用于在分类窗口中设置类别。

这个窗口在调用刷新 refresh 时,首先用 make_item_list 遍历物品栏中的所有物品,如果属于目前的分类就将其加入物品列表。

最后将一个空物品加入了列表。然后调用 create_contents 生成窗口内容。

draw_all_items 绘制所有项目。后面两个方法都是在父类中定义的。

在绘制每个项目时,draw_item 会将物品的名字与数量绘制到画面上。

#encoding:utf-8#==============================================================================# ■ Window_ItemList#------------------------------------------------------------------------------#  物品画面中,显示持有物品的窗口。#==============================================================================class Window_ItemList < Window_Selectable  #--------------------------------------------------------------------------  # ● 初始化对象  #--------------------------------------------------------------------------  def initialize(x, y, width, height)    super    @category = :none    @data = []  end  #--------------------------------------------------------------------------  # ● 设置分类  #--------------------------------------------------------------------------  def category=(category)    return if @category == category    @category = category    refresh    self.oy = 0  end  #--------------------------------------------------------------------------  # ● 获取列数  #--------------------------------------------------------------------------  def col_max    return 2  end  #--------------------------------------------------------------------------  # ● 获取项目数  #--------------------------------------------------------------------------  def item_max    @data ? @data.size : 1  end  #--------------------------------------------------------------------------  # ● 获取物品  #--------------------------------------------------------------------------  def item    @data && index >= 0 ? @data[index] : nil  end  #--------------------------------------------------------------------------  # ● 获取选择项目的有效状态  #--------------------------------------------------------------------------  def current_item_enabled?    enable?(@data[index])  end  #--------------------------------------------------------------------------  # ● 查询列表中是否含有此物品  #--------------------------------------------------------------------------  def include?(item)    case @category    when :item      item.is_a?(RPG::Item) && !item.key_item?    when :weapon      item.is_a?(RPG::Weapon)    when :armor      item.is_a?(RPG::Armor)    when :key_item      item.is_a?(RPG::Item) && item.key_item?    else      false    end  end  #--------------------------------------------------------------------------  # ● 查询此物品是否可用  #--------------------------------------------------------------------------  def enable?(item)    $game_party.usable?(item)  end  #--------------------------------------------------------------------------  # ● 生成物品列表  #--------------------------------------------------------------------------  def make_item_list    @data = $game_party.all_items.select {|item| include?(item) }    @data.push(nil) if include?(nil)  end  #--------------------------------------------------------------------------  # ● 返回上一个选择的位置  #--------------------------------------------------------------------------  def select_last    select(@data.index($game_party.last_item.object) || 0)  end  #--------------------------------------------------------------------------  # ● 绘制项目  #--------------------------------------------------------------------------  def draw_item(index)    item = @data[index]    if item      rect = item_rect(index)      rect.width -= 4      draw_item_name(item, rect.x, rect.y, enable?(item))      draw_item_number(rect, item)    end  end  #--------------------------------------------------------------------------  # ● 绘制物品个数  #--------------------------------------------------------------------------  def draw_item_number(rect, item)    draw_text(rect, sprintf(":%2d", $game_party.item_number(item)), 2)  end  #--------------------------------------------------------------------------  # ● 更新帮助内容  #--------------------------------------------------------------------------  def update_help    @help_window.set_item(item)  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    make_item_list    create_contents    draw_all_items  endend

显示技能的窗口 Window_SkillList 与它很类似。

在刷新 refresh 时,调用 make_item_list 遍历角色的所有技能。

而其中的角色 @actor 是在 Scene_Skill 类用切换角色的方法 on_actor_change 指定的。

技能中的项目在绘制时会把技能的消耗绘制到屏幕。

#encoding:utf-8#==============================================================================# ■ Window_SkillList#------------------------------------------------------------------------------#  技能画面中,显示技能的窗口。#==============================================================================class Window_SkillList < Window_Selectable  #--------------------------------------------------------------------------  # ● 初始化对象  #--------------------------------------------------------------------------  def initialize(x, y, width, height)    super    @actor = nil    @stype_id = 0    @data = []  end  #--------------------------------------------------------------------------  # ● 设置角色  #--------------------------------------------------------------------------  def actor=(actor)    return if @actor == actor    @actor = actor    refresh    self.oy = 0  end  #--------------------------------------------------------------------------  # ● 设置技能类型 ID   #--------------------------------------------------------------------------  def stype_id=(stype_id)    return if @stype_id == stype_id    @stype_id = stype_id    refresh    self.oy = 0  end  #--------------------------------------------------------------------------  # ● 获取列数  #--------------------------------------------------------------------------  def col_max    return 2  end  #--------------------------------------------------------------------------  # ● 获取项目数  #--------------------------------------------------------------------------  def item_max    @data ? @data.size : 1  end  #--------------------------------------------------------------------------  # ● 获取技能  #--------------------------------------------------------------------------  def item    @data && index >= 0 ? @data[index] : nil  end  #--------------------------------------------------------------------------  # ● 获取选择项目的有效状态  #--------------------------------------------------------------------------  def current_item_enabled?    enable?(@data[index])  end  #--------------------------------------------------------------------------  # ● 查询列表中是否含有此技能  #--------------------------------------------------------------------------  def include?(item)    item && item.stype_id == @stype_id  end  #--------------------------------------------------------------------------  # ● 查询此技能是否可用  #--------------------------------------------------------------------------  def enable?(item)    @actor && @actor.usable?(item)  end  #--------------------------------------------------------------------------  # ● 生成技能列表  #--------------------------------------------------------------------------  def make_item_list    @data = @actor ? @actor.skills.select {|skill| include?(skill) } : []  end  #--------------------------------------------------------------------------  # ● 返回上一个选择的位置  #--------------------------------------------------------------------------  def select_last    select(@data.index(@actor.last_skill.object) || 0)  end  #--------------------------------------------------------------------------  # ● 绘制项目  #--------------------------------------------------------------------------  def draw_item(index)    skill = @data[index]    if skill      rect = item_rect(index)      rect.width -= 4      draw_item_name(skill, rect.x, rect.y, enable?(skill))      draw_skill_cost(rect, skill)    end  end  #--------------------------------------------------------------------------  # ● 绘制技能的使用消耗  #--------------------------------------------------------------------------  def draw_skill_cost(rect, skill)    if @actor.skill_tp_cost(skill) > 0      change_color(tp_cost_color, enable?(skill))      draw_text(rect, @actor.skill_tp_cost(skill), 2)    elsif @actor.skill_mp_cost(skill) > 0      change_color(mp_cost_color, enable?(skill))      draw_text(rect, @actor.skill_mp_cost(skill), 2)    end  end  #--------------------------------------------------------------------------  # ● 更新帮助内容  #--------------------------------------------------------------------------  def update_help    @help_window.set_item(item)  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    make_item_list    create_contents    draw_all_items  endend

技能画面中有一个指令窗口 Window_SkillCommand,用来选取特技还是魔法。

它有自动生成的指令列表,遍历角色的所有技能,然后将技能种类生成指令。

在更新画面时,它不停的将技能窗口的技能类型设为当前选中的种类。

#encoding:utf-8#==============================================================================# ■ Window_SkillCommand#------------------------------------------------------------------------------#  技能画面中,选择指令(特技/魔法等)的窗口。#==============================================================================class Window_SkillCommand < Window_Command  #--------------------------------------------------------------------------  # ● 定义实例变量  #--------------------------------------------------------------------------  attr_reader   :skill_window  #--------------------------------------------------------------------------  # ● 初始化对象  #--------------------------------------------------------------------------  def initialize(x, y)    super(x, y)    @actor = nil  end  #--------------------------------------------------------------------------  # ● 获取窗口的宽度  #--------------------------------------------------------------------------  def window_width    return 160  end  #--------------------------------------------------------------------------  # ● 设置角色  #--------------------------------------------------------------------------  def actor=(actor)    return if @actor == actor    @actor = actor    refresh    select_last  end  #--------------------------------------------------------------------------  # ● 获取显示行数  #--------------------------------------------------------------------------  def visible_line_number    return 4  end  #--------------------------------------------------------------------------  # ● 生成指令列表  #--------------------------------------------------------------------------  def make_command_list    return unless @actor    @actor.added_skill_types.sort.each do |stype_id|      name = $data_system.skill_types[stype_id]      add_command(name, :skill, true, stype_id)    end  end  #--------------------------------------------------------------------------  # ● 更新画面  #--------------------------------------------------------------------------  def update    super    @skill_window.stype_id = current_ext if @skill_window  end  #--------------------------------------------------------------------------  # ● 设置技能窗口  #--------------------------------------------------------------------------  def skill_window=(skill_window)    @skill_window = skill_window    update  end  #--------------------------------------------------------------------------  # ● 返回上一个选择的位置  #--------------------------------------------------------------------------  def select_last    skill = @actor.last_skill.object    if skill      select_ext(skill.stype_id)    else      select(0)    end  endend




技能与物品画面的工作原理大致就是如此了。
0 0