【脚本】书籍系统

预览

预览

范例工程
http://pan.baidu.com/s/1ntGl1FV

=begin
===============================================================================
  书籍系统 By喵呜喵5
===============================================================================

【说明】

  在屏幕上显示指定的图片,使用左右键可以切换不同的图片(下一张/上一张)

  说是书籍系统,这个系统更类似于一个相册

  所有显示的图片均放在 Graphics/M5Book 目录下


  在事件脚本中使用指令

    M5Book20151113.open(:书籍的名称)

  来打开对应的书籍

  书籍的具体设置请参考下方的说明以及脚本默认的范例


=end
$m5script ||= {};$m5script[:M5Book20151113] = 20151120
module M5Book20151113; CONFIG ={
=begin
#==============================================================================
#  设定部分
#==============================================================================

  下面的每一个设置对应一本书籍,设置的格式为

    :书籍的名称 => { 书籍的设置 },

    ※ 书籍名称开头的英文冒号以及书籍设置最后的英文逗号不能省略
    ※ 名为 :默认书籍 的设置为【所有】书籍的默认设置

  在两个大括号之间,可以设置书籍本身的属性,设置的格式为:

    需要设置的属性: 属性的值 ,

    ※ 冒号和属性的值之间请加上空格,不要忘记每条设置最后的逗号

  可以设置的属性如下:

  FOLD        书籍图片所在的目录,默认目录为“Graphics/M5Book”。
              例如,若这里设置为“Foo”,则书籍图片的目录将变成
              “Graphics/M5Book/Foo”目录,依此类推

  MAX         书籍的总页数,同时也指定了书籍要显示的图片。
              例如,设置为 4 时,
              显示的图片便为指定目录下文件名为 1、2、3、4 的这四张图片

  LIST        书籍的图片文件名列表,设置格式为 ['文件名1','文件名2','文件名n']
              ※ 文件名前后加上英文引号,中间用英文逗号分隔
              例如,设置为 ['1','2','4','5'] 时,
              显示的图片便为指定目录下名为 1、2、4、5 的这四张图片
              当设置了这个属性后,上方的 MAX 属性将失效

              当这里设置为 ['0',['1',100,100],['1',100,200],'2'] 时
              书籍的第二页显示名为 1 的图片,显示位置为(100,100)
              翻到第三页时,图片不会改变,而是将显示位置移动到(100,200)

  MOVE_SPEED  当图片设置了移动时(上面后半部分提到的设置方式),
              图片的移动速度

  BACK        界面的背景图片文件名,文件名前后需要加上英文引号
              背景图片文件的目录始终为“Graphics/M5Book”

  FORE        界面的遮罩图片文件名,文件名前后需要加上英文引号
              遮罩图片文件的目录始终为“Graphics/M5Book”

  HINT        界面的提示图片文件名,文件名前后需要加上英文引号
              提示图片文件的目录始终为“Graphics/M5Book”
              提示图片和遮罩图片类似,都是显示在界面最上方
              不过长时间没有按键时,提示图片会自动隐藏

  HIDE_TIME   设置多长时间没有操作时自动隐藏提示图片

  HIDE_SPEED  设置提示图片隐藏/显示的速度

  START_PAGE  书籍最开始的页数

  SCROLL      设置为 true 时,书籍翻到最后一页后继续翻页会回到第一页

  SPEED       书籍翻页的速度

  OPEN_SE     打开书籍界面时播放的音效文件名,前后需要加上英文引号

  CLOSE_SE    关闭书籍界面时播放的音效文件名,前后需要加上英文引号

  PAGE_SE     书籍翻页时播放的音效文件名,前后需要加上英文引号

  ERROR_SE    书籍无法翻页时播放的音效文件名,前后需要加上英文引号


  下面四个是书籍界面按钮的设置,设置格式为 [按钮1,按钮2,按钮n]

  各个按钮的格式为:

    :DOWN :LEFT :RIGHT :UP                  分别对应方向键中的下、左、右、上

    :A :B :C :X :Y :Z :L :R                 对应 F1 中各自的按键

    :SHIFT :CTRL :ALT :F5 :F6 :F7 :F8 :F9   直接对应键盘上面的相应按键

  按键设置为 [] 时对应功能失效


  PRE_BUTTON      书籍向前翻页的按钮
                  默认为 :LEFT 键(默认对应键盘的 左 键)

  NEXT_BUTTON     书籍向后翻页的按钮
                  默认为 :RIGHT 键(默认对应键盘的 右 键)

  CLOSE_BUTTON1   关闭书籍界面的按钮
                  默认为 :B 键(默认对应键盘的 X 键)

  CLOSE_BUTTON2   书籍翻到最后一页时关闭书籍界面的按钮
                  默认为 :C 键(默认对应键盘的 Z 键)


=end

  :默认书籍 => {

    PAGE_SE: "Book2",

    ERROR_SE: "Book1",

  },

  # 这个设置中设置的属性将应用到所有书籍中,这里为所有书籍的翻页增加了音效

  :书籍1 => {

    FOLD: "书籍1",

    MAX: 9,

  },

  # 名为 书籍1 的书籍显示 M5Book/书籍1 目录下 1.jpg ~ 9.jpg 这9张图片

  :书籍2 => {

    LIST: ['cg2','pic1','pic4','cg0'],

    SCROLL: true,

  },

  # 名为 书籍2 的书籍显示 M5Book 目录下指定图片同时循环翻页

  :书籍3 => {

    LIST: ['cg2','cg0'],

    BACK: "back",

    FORE: "fore",

    HINT: "hint",

    SPEED: 5,

  },

  # 名为 书籍3 的书籍拥有前景、背景和提示,翻页速度特慢

  :书籍4 => {

    FOLD: '书籍4',

    MAX: 6,

    PRE_BUTTON: [:UP, :B],

    NEXT_BUTTON: [:DOWN, :C],

    CLOSE_BUTTON1: [],

  },

  # 名为 书籍4 的书籍使用上下和确定取消键翻页,只能在最后一页按确定键退出

  :书籍5 => {

    FOLD: '书籍5',

    MAX: 9,

    START_PAGE: 2,

    OPEN_SE: "Cat",

    CLOSE_SE: "Cat",

    ERROR_SE: "Dog",

  },

  # 名为 书籍5 的书籍最开始显示第二张图片,同时打开、关闭时有音效,
  # 并覆盖了默认翻页错误音效

  :书籍6 => {

    LIST: ['cg', ['cg',-140,0], ['cg',-280,0]],

    MOVE_SPEED: 5,

  },

  # 名为 书籍6 的书籍演示了如何制作书籍图片移动的效果

#==============================================================================
#  设定结束
#==============================================================================
}
class Scene < Scene_MenuBase
  def bitmap(filename)
    @cache ||= {}
    path = "Graphics/M5Book/"
    path += "#{@config[:FOLD]}/" if @config[:FOLD]
    path += filename
    return @cache[path] if @cache[path]
    @cache[path] = filename.empty? ? Bitmap.new(32,32) : Bitmap.new(path)
  end
  def input?(list)
    list.each do |i|
      if Input.trigger?(i)
        @hint_state[0] = :showing
        return true
      end
    end
    false
  end
  def prepare(config)
    @config = config.clone
    if [email protected][:LIST]
      @config[:LIST] = []
      @config[:MAX].times {|i| @config[:LIST] << (i + 1).to_s }
    end
    start = @config[:START_PAGE] || 1
    start -= 1
    start = [[start,0].max, @config[:LIST].size - 1].min
    @config[:START_PAGE] = start
    @config[:SCROLL] ||= false
    @config[:CLOSE_BUTTON1] ||= [:B]
    @config[:CLOSE_BUTTON2] ||= [:C]
    @config[:NEXT_BUTTON] ||= [:RIGHT, :C]
    @config[:PRE_BUTTON] ||= [:LEFT]
    @config[:SPEED] ||= 20
    @config[:MOVE_SPEED] ||= 10
    @config[:HIDE_TIME] ||= 60
    @config[:HIDE_SPEED] ||= 20
  end
  def start
    super
    create_page
    create_foreground
    create_hint
    Audio.se_play "Audio/SE/#{@config[:OPEN_SE]}" if @config[:OPEN_SE]
  end
  def create_background
    @background_bitmap = nil
    return super unless @config[:BACK]
    @background_sprite = Sprite.new
    @background_bitmap = Bitmap.new "Graphics/M5Book/#{@config[:BACK]}"
    @background_sprite.bitmap = @background_bitmap
  end
  def create_page
    @page_index = @config[:START_PAGE]
    @page_change = false
    @now_sprite = Sprite.new
    @next_sprite = Sprite.new
    page = @config[:LIST][@page_index]
    page = [page, 0, 0] unless page.is_a? Array
    @next_sprite.bitmap = bitmap(page[0])
    @next_sprite.x, @next_sprite.y = page[1], page[2]
    @now_sprite.opacity = 0
    @next_sprite.z = 100
  end
  def create_foreground
    @foreground = Sprite.new
    @foreground.z = 150
    if @config[:FORE]
      @foreground.bitmap = Bitmap.new "Graphics/M5Book/#{@config[:FORE]}"
    end
  end
  def create_hint
    @hint = Sprite.new
    @hint.z = 200
    if @config[:HINT]
      @hint.bitmap = Bitmap.new "Graphics/M5Book/#{@config[:HINT]}"
    end
    @hint_state = [:show, @config[:HIDE_TIME]]
  end
  def update
    super
    update_hint_image
    return update_page if @page_change
    @now_sprite.opacity -= @config[:SPEED] unless @now_sprite.opacity == 0
    update_input
  end
  def update_hint_image
    return unless @hint.bitmap
    case @hint_state[0]
    when :showing
      @hint.opacity += @config[:HIDE_SPEED]
      @hint_state = [:show, @config[:HIDE_TIME]] if @hint.opacity == 255
    when :show
      return if @page_change
      time = @hint_state[1]
      time -= 1
      @hint_state[0] = :hiding if time < 0
      @hint_state[1] = time
    when :hiding
      @hint.opacity -= @config[:HIDE_SPEED] unless @hint.opacity == 0
    end
  end

  def update_page
    case @page_change_type[0]
    when :image then update_image_change
    when :move then update_image_move(@page_change_type[1])
    end
  end
  def update_image_change
    @next_sprite.opacity += @config[:SPEED]
    @page_change = false if @next_sprite.opacity == 255
  end
  def update_image_move(data)
    s = @next_sprite
    proc = ->(target, direction, orign) do
      next orign if target == orign
      speed = @config[:MOVE_SPEED]
      speed *= -1 unless direction
      result = orign + speed
      direction ? [result, target].min : [result, target].max
    end
    s.x = proc.call(data[:TX], data[:X], s.x)
    s.y = proc.call(data[:TY], data[:Y], s.y)
    s.x == data[:TX] && s.y == data[:TY] && @page_change = false
  end
  def update_input
    change_page(-1) if input?(@config[:PRE_BUTTON])
    change_page(1) if input?(@config[:NEXT_BUTTON])
    return_scene if input?(@config[:CLOSE_BUTTON1])
    return unless @page_index == @config[:LIST].size - 1
    return_scene if input?(@config[:CLOSE_BUTTON2])
  end
  def change_page(amount)
    old_page = @page_index
    @page_index += amount
    last_page = @config[:LIST].size
    if @page_index < 0 || @page_index > last_page - 1
      @page_index = @config[:SCROLL] ?
        @page_index % last_page : [[@page_index, 0].max, last_page - 1].min
    end
    if old_page != @page_index
      Audio.se_play "Audio/SE/#{@config[:PAGE_SE]}" if @config[:PAGE_SE]
      @page_change = true
      set_page(old_page, @page_index)
      Input.update
    else
      Audio.se_play "Audio/SE/#{@config[:ERROR_SE]}" if @config[:ERROR_SE]
    end
  end
  def set_page(old_page, new_page)
    old_data = @config[:LIST][old_page]
    new_data = @config[:LIST][new_page]
    old_data = [old_data, 0, 0] unless old_data.is_a? Array
    new_data = [new_data, 0, 0] unless new_data.is_a? Array
    return set_move(*new_data) if new_data[0] == old_data[0]
    set_bitmap(*new_data)
  end
  def set_bitmap(filename, x, y)
    @now_sprite, @next_sprite = @next_sprite, @now_sprite
    @now_sprite.z, @next_sprite.z = 50, 100
    @now_sprite.opacity, @next_sprite.opacity = 255, 0
    @next_sprite.bitmap = bitmap(filename)
    @next_sprite.x, @next_sprite.y = x, y
    @page_change_type = [:image]
  end
  def set_move(_, tx, ty)
    move_data = {
      TX: tx, TY: ty,
      X:  tx - @next_sprite.x > 0,
      Y:  ty - @next_sprite.y > 0
    }
    @page_change_type = [:move, move_data]
  end
  def terminate
    Audio.se_play "Audio/SE/#{@config[:CLOSE_SE]}" if @config[:CLOSE_SE]
    super
    @now_sprite.dispose
    @next_sprite.dispose
    @foreground.bitmap.dispose if @foreground.bitmap
    @foreground.dispose
    @hint.bitmap.dispose if @hint.bitmap
    @hint.dispose
    @cache.each_value(&:dispose)
    @background_bitmap.dispose if @background_bitmap
  end
end

  def self.open(name)
    config = CONFIG[:默认书籍] || {}
    config = config.merge (CONFIG[name] || {})
    raise '未设置书籍内容' unless config[:LIST] || config[:MAX]
    SceneManager.call(Scene)
    SceneManager.scene.prepare(config)
  end

end # M5Book20151113

发表评论

电子邮件地址不会被公开。 必填项已用*标注