Project1

标题: 【囧】就当小白笔记吧——自己动手修改菜单 [打印本页]

作者: 北极七月熊    时间: 2013-4-9 20:51
标题: 【囧】就当小白笔记吧——自己动手修改菜单
本帖最后由 北极七月熊 于 2013-4-9 22:02 编辑

首先先弱弱地说下,我自己也是一个小白,从来没想过要用VA做游戏(本来是蹦着彩虹来的),不知道怎么莫名其妙就研究起VA脚本了……
回想当初自己看着XP的脚本就像在看天书一样,智商各种不够用。
由于某段日子误入歧途悟性终于增加了不少,于是就有了这帖子,写给也是VA的小白吧。

先从大家可能最感兴趣的菜单开始说起~

1.菜单的类是Scene_Menu,并且继承了Scene_MenuBase,而Scene_MenuBase又继承了Scene_Base。

class Scene_Menu < Scene_MenuBase

★ class 表示定义类,如class 类名。

★ < 表示类的继承。
Scene_Menu继承Scene_MenuBase,大概相当于Scene_Menu就有了Scene_MenuBase的所有函数,除非Scene_Menu类里再自己定义同名函数覆盖。

def start
    super
    create_command_window
    create_gold_window
    create_status_window
end

  
★ def 表示定义函数。如def 函数名。
这里的start为函数名。不过这里的函数名start不方便修改,因为在Scene_Base里的main函数定义了start的方法,
如果改了就会出错,建议别自找麻烦了……



★ super表示继承父类的同名函数。
说白了这里的super就相当于父类Scene_MenuBase中的
    super
    create_background
   
@actor = $game_party.menu_actor
而Scene_MenuBase中的super又相当于Scene_Base的
     create_main_viewport
话又说回去,如果你前面改变了函数名start,那么自然就无法继承出错了。


我整理一下代码,如果觉得看了更难理解就无视吧:        
# ● 开始处理
def start
    super-Scene_MenuBase
        (
                    super-Scene_Base
                        (
                                create_main_viewport
                        )
                        create_background
                        @actor = $game_party.menu_actor
        )
    create_command_window
    create_gold_window
    create_status_window
end


2.接下来我们看一下设置指令的这段代码:

# ● 生成指令窗口
def create_command_window
    @command_window = Window_MenuCommand.new
    @command_window.set_handler(:item,      method(:command_item))
    @command_window.set_handler(:skill,     method(:command_personal))
    @command_window.set_handler(:equip,     method(:command_personal))
    @command_window.set_handler(:status,    method(:command_personal))
    @command_window.set_handler(:formation, method(:command_formation))
    @command_window.set_handler(:save,      method(:command_save))
    @command_window.set_handler(:game_end,  method(:command_game_end))
    @command_window.set_handler(:cancel,    method(:return_scene))
end


印象中好像和XP的天差地别,囧。

★ 不过如果你注意上面函数的start中有一句create_command_window,那是在说明start函数里要调用create_command_window这段函数。
    所以
         def create_command_window
         end
    这是在为create_command_window要做什么样的操作进行定义。
        
★ @command_window = Window_MenuCommand.new
    这句话是表示生成一个Window_MenuCommand类的新对象command_window。
    @对象名 = 类名.new

★ @command_window.set_handler(:item, method(:command_item))
    这句话是表示对象command_window在调用set_handler的函数,而set_handler的定义在哪?自然在Window_MenuCommand类或者其父类里。
    这些其实就表示了如果一个类要调用到另一类的函数,基本上有两种方法:
    1.作为它的子类,就是继承。
    2.生成要调用类的对象,然后用对象.函数(参数),就可以调用了。

        
3.接下来我们先看一下Window_MenuCommand类的代码:  


Window_MenuCommand
# ● 初始化对象
def initialize
    super(0, 0)
        (
                clear_command_list
                make_command_list
                super(x, y, window_width, window_height)
                refresh
                select(0)
                activate
        )
    select_last
end


★ Window类都有initialize初始化这个函数。窗口的X,Y坐标,以及宽度高度就是在这里定义的。
   这里有个super(0, 0)就表示Window_MenuCommand继承父类Window_Command的initialize函数时,还传递了参数(0,0),
   看一下Window_Command类的  
   def initialize(x, y)
                ……
   super(x, y, window_width, window_height)
                ……
   end
   前后看一下代码,应该能明白这里的传递的参数(0,0)是表示x,y坐标吧?如果不明白把上面的再看一遍吧亲。

  
3.VA里的选项指令的设置比较麻烦了,所以我们再看一下Window_MenuCommand的这句代码:


★ add_command(Vocab::item,   :item,   main_commands_enabled)
    看英语的意思应该也能菜单这是在设置菜单的物品这个选项吧。
    而add_command(参数)这是一句函数。


★ Vocab::item表示module Vocab的item。

按Shift+Ctrl+F就能全局查找,我们查找add_command,就能在Window_Command找到这段代码:
        
# ● 向指令列表添加主要的指令
#--------------------------------------------------------------------------
# ● 添加指令
#     name    : 指令名称
#     symbol  : 对应的符号
#     enabled : 有效状态的标志
#     ext     : 任意的扩展数据
#--------------------------------------------------------------------------
  def add_command(name, symbol, enabled = true, ext = nil)
    @list.push({:name=>name, :symbol=>symbol, :enabled=>enabled, :ext=>ext})
  end

  
这里就定义了add_command函数,至于@list.push这大致就是用一个数组把这些指令保存起来,然后再用其它函数进行绘制,这里先不讲了。
所以如果想要在VA里要为菜单添加新的选项就需要在Window_MenuCommand类用add_command进行设置的。

例如我在def add_main_commands里加上一句:add_command("测试",:test)
这时菜单已经绘制出这个选项了,但是按下后没有反应。


4.下面我们就返回到Scene_Menu接着看代码:

@command_window.set_handler(:item,      method(:command_item))
        
我们再次去查找set_handler,在Window_Selectable里有:


  #--------------------------------------------------------------------------
  # ● 设置动作对应的处理方法
  #     method : 设置的处理方法 (Method 实例)
  #--------------------------------------------------------------------------
  def set_handler(symbol, method)
    @handler[symbol] = method
  end

  
这里大概就是说设置动作对应的处理方法(好吧,我复制了……),这里的symbol应该是和add_command里的相对应的,所以我们可以
参照系统默认的写法加上一句:
@command_window.set_handler(:test,      method(:command_test))

这时我们需要再为method(:command_test)写上一个函数定义:
def command_test
    ……
end


这时候菜单的测试按钮就生效了,主要是用到add_command和set_handler这两个函数。


如果有人注意到这句代码:
@command_window.set_handler(:cancel,    method(:return_scene))
并发现Window_MenuCommand并没有相对应的add_command,好吧其实在VA里,VA设置了一些比较常用的动作控制,
所以在菜单中如果可以的话我们就可以不需自己再去处理光标的移动,换页,确定,取消这样的按钮,直接调用就可以了。
如果想深究的话,可以在Window_Selectable类找到:


  #--------------------------------------------------------------------------
  # ● “确定”和“取消”的处理
  #--------------------------------------------------------------------------
  def process_handling
    ……
    return process_cancel   if cancel_enabled?    && Input.trigger?(:B)
……
  end
  #--------------------------------------------------------------------------
  # ● 按下取消键时的处理
  #--------------------------------------------------------------------------
  def process_cancel
    Sound.play_cancel
    Input.update
    deactivate
    call_cancel_handler
  end
  #--------------------------------------------------------------------------
  # ● 调用“取消”的处理方法
  #--------------------------------------------------------------------------
  def call_cancel_handler
    call_handler(:cancel)
  end
  #--------------------------------------------------------------------------
  # ● 调用处理方法
  #--------------------------------------------------------------------------
  def call_handler(symbol)
    @handler[symbol].call if handle?(symbol)
  end

其实看到这里也差不多了,大致就是当Esc键按下的时候,就进行取消的处理,对于这个菜单来说就是:return_scene:

  #--------------------------------------------------------------------------
  # ● 返回前一个场景
  #--------------------------------------------------------------------------
  def return_scene
    SceneManager.return
  end


@status_window.select_last

  #--------------------------------------------------------------------------
  # ● 返回最后一个选项的位置
  #--------------------------------------------------------------------------
  def select_last
    select_symbol(@@last_command_symbol)
  end
  #--------------------------------------------------------------------------
  # ● 按下确定键时的处理
  #--------------------------------------------------------------------------
  def process_ok
    @@last_command_symbol = current_symbol
    super
  end
  #--------------------------------------------------------------------------
  # ● 将光标移动到指定的标志符对应的选项
  #--------------------------------------------------------------------------
  def select_symbol(symbol)
    @list.each_index {|i| select(i) if @list
[:symbol] == symbol }
  end
  
但按下技能装备状态时,就会激活Window_MenuStatus进行选择,.select_last就是返回最后一个选项的位置。
不过当重新打开菜单界面时清空变量last_command_symbol。

class Scene_Map
  #--------------------------------------------------------------------------
  # ● 打开菜单画面
  #--------------------------------------------------------------------------
  def call_menu
    Sound.play_ok
    SceneManager.call(Scene_Menu)
    Window_MenuCommand::init_command_position
  end  
  
  #--------------------------------------------------------------------------
  # ● 初始化指令选择位置(类方法)
  #--------------------------------------------------------------------------
  def self.init_command_position
    @@last_command_symbol = nil
  end
  
  
@status_window.activate
  #--------------------------------------------------------------------------
  # ● 启用窗口
  #--------------------------------------------------------------------------
  def activate
    self.active = true
    self
  end
  
选项的光标从@command_window移至@status_window。

@status_window.set_handler(:ok,     method(:on_personal_ok))
@status_window.set_handler(:cancel, method(:on_personal_cancel))

  #--------------------------------------------------------------------------
  # ● 按下确定键时的处理
  #--------------------------------------------------------------------------
  def process_ok
    super

  if current_item_enabled?
   Sound.play_ok
   Input.update
   deactivate
   call_ok_handler
  else
   Sound.play_buzzer
    end

    $game_party.menu_actor = $game_party.members[index]
  end

这里的当确定键按下时,还传递了一个全局变量。
$game_party.menu_actor = $game_party.members[index]

  #--------------------------------------------------------------------------
  # ● 个人指令“确定”
  #--------------------------------------------------------------------------
  def on_personal_ok
    case @command_window.current_symbol
    when :skill
      SceneManager.call(Scene_Skill)
    when :equip
      SceneManager.call(Scene_Equip)
    when :status
      SceneManager.call(Scene_Status)
    end
  end
  
  这里的current_symbol可参照Window_MenuCommand的代码:
  #--------------------------------------------------------------------------
  # ● 按下确定键时的处理
  #--------------------------------------------------------------------------
  def process_ok
    @@last_command_symbol = current_symbol
    super
  end
  
  #--------------------------------------------------------------------------
  # ● 获取选项的符号
  #--------------------------------------------------------------------------
  def current_symbol
    current_data ? current_data[:symbol] : nil
  end  
  @command_window.current_symbol
  
  class Scene_Status < Scene_MenuBase.
  就是按下技能装备状态时,@command_window.current_symbol已经被记录下来了。
  这里是对应指令的symbol,所以if对其进行判断。

  
这里先用最简单的class Scene_Status说明一下。
  #--------------------------------------------------------------------------
  # ● 开始处理
  #--------------------------------------------------------------------------
  def start
    super

  super
  create_background
  @actor = $game_party.menu_actor

    @status_window = Window_Status.new(@actor)
    @status_window.set_handler(:cancel,   method(:return_scene))
    @status_window.set_handler(:pagedown, method(:next_actor))
    @status_window.set_handler(:pageup,   method(:prev_actor))
  end

我先把super的内容补上了,因为这里的@actor = $game_party.menu_actor,就是把选择的角色用变量传递过来,然后用
@status_window = Window_Status.new(@actor)进行绘制。

大致的顺序是这样的:
Scene_Menu
1.@command_window 来选择“物品”“技能”“装备”“状态”这些,但确定键按下时,同时记录了变量@command_window.current_symbol。
2.如果是按下“技能”“装备”“状态”这些选项,激活@status_window进行选择。
3.当选择完角色时,记录全局变量$game_party.menu_actor = $game_party.members[index]。(省略select_last)
4.如果是“状态”的话,又有@actor = $game_party.menu_actor,最后用@status_window = Window_Status.new(@actor),传递@actor绘制相应角色的窗口。
        

打得好累,果然我是没什么毅力的人。
虽然觉得打了好多字但似乎什么都没讲到啊……
又补充了一部分,物品技能装备估计下次再继续讲吧。
目前对菜单的修改也没什么想法,如果谁想定制菜单可以找我,我顺便做个实例……
最好不要有鼠标的,目前还没搞明白鼠标,泪奔……
-2013.4.9






作者: wx1y    时间: 2013-5-5 14:06
先留个名,好像VA改菜单选项好麻烦
作者: 圆寂丨不羁的风    时间: 2013-6-13 19:56
谢谢撸主,贫道总算学到点菜单修改了。之前那些太专业,看得贫道一头雾水




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