设为首页收藏本站同能贴吧 切换语言 繁体中文
开启辅助访问 切换到窄版
搜索附件  
同能RPG制作大师 › 附件中心 › 同能RM技术讨论区 › RPG Maker VA 讨论区 › 简单的"检视战场"脚本New: d1.jpg

简单的"检视战场"脚本New: d1.jpg

 

简单的"检视战场"脚本New:

最近用DS给自己的游戏加了一堆奇妙插件,难得有这么个简单易用的,分享一下。
操作方法:在ActorCommand阶段(显示[攻击][防御][技能][物品]的阶段),按下A键,弹出此场景。
按←→切换左右部分。
左半边记录了所有Message,一页显示不下,可以按↑↓滚动。
右半边列出了所有角色和敌人,可以按↑↓切换,底下会有敌人的简介(备注),及角色/敌人附有的状态名(备注,无备注则不显示状态,按优先等级排列)。
再按A或Esc退出场景。
自测可用,希望万机之神保佑你……
[Ruby] 纯文本查看 复制代码
#==============================================================================
# ■ 检视战场(独立场景版)
#------------------------------------------------------------------------------
# 【操作】
#   ActorCommand 阶段按 A / Shift 打开;A / Shift / Esc / X 关闭。
#   左半为战斗日志:↑↓ 滚动(可按住快速滚动),→ 切到右侧
#   右半为人物查看:↑↓ 切换成员(首尾循环),← 切回左侧
#   打开时默认滚到最新一条。
#
# 【滚动提示】
#   左侧有未显示内容时,底部显示黑框 + "按 ↑ 上翻" / "按 ↓ 下翻"
#
# 【记录来源】
#   Window_BattleLog#add_text / replace_text、$game_message.add
#
# 【转义符处理(记录时固定)】
#   \V[n] → 变量当前值;\name[XX] → "XX:";其他转义符去掉
#
# 【数据库备注】
#   敌人:<说明:XX>(\n 变换行,自动换行)
#   状态:<状态名:XX>(无此标签则不显示)
#
# 【加载位置】
#   Materials 下方、Main 上方,放在所有战斗脚本之后。
#==============================================================================

$battle_log_history = nil
$char_width_cache   = {}

#--------------------------------------------------------------------------
# ● 滚动参数
#--------------------------------------------------------------------------
HOLD_START_FRAMES = 15    # 按住多少帧后开始连续滚动
HOLD_INTERVAL     = 3     # 连续滚动间隔(帧)

#--------------------------------------------------------------------------
# ● 转义符处理
#--------------------------------------------------------------------------
module BattleLogSanitizer
  def self.sanitize(text)
    return text if text.nil?
    s = text.dup
    s.gsub!(/\\[Vv]\[(\d+)\]/) { $game_variables[$1.to_i].to_s }
    s.gsub!(/\\[Nn]ame\[([^\]]*)\]/) { "#{$1}:" }
    s.gsub!(/\\[A-Za-z_]+\[[^\]]*\]/, "")
    s.gsub!(/\\[A-Za-z_]+/, "")
    s.gsub!(/\\[.><|!^$]/, "")
    s
  end
end

#--------------------------------------------------------------------------
# ● Window_BattleLog — 记录
#--------------------------------------------------------------------------
class Window_BattleLog < Window_Selectable
  alias history_log_add_text add_text
  def add_text(text)
    if $battle_log_history
      s = BattleLogSanitizer.sanitize(text)
      $battle_log_history << s unless s.nil? || s.empty?
    end
    history_log_add_text(text)
  end

  alias history_log_replace_text replace_text
  def replace_text(text)
    if $battle_log_history
      s = BattleLogSanitizer.sanitize(text)
      $battle_log_history << s unless s.nil? || s.empty?
    end
    history_log_replace_text(text)
  end
end

#--------------------------------------------------------------------------
# ● Game_Message — 记录事件文字
#--------------------------------------------------------------------------
class Game_Message
  alias history_log_message_add add
  def add(text)
    if $battle_log_history && SceneManager.scene.is_a?(Scene_Battle)
      s = BattleLogSanitizer.sanitize(text)
      $battle_log_history << s unless s.nil? || s.empty?
    end
    history_log_message_add(text)
  end
end

#--------------------------------------------------------------------------
# ● Window_BattleHistoryLog — 全屏双面板窗口
#--------------------------------------------------------------------------
class Window_BattleHistoryLog < Window_Base
  FONT_SIZE       = 20
  STATE_FONT_SIZE = 18
  HINT_FONT_SIZE  = 18
  LINE_HEIGHT     = 24
  MAX_MEMBERS     = 9
  STATE_ICON_W    = 24

  def initialize
    super(0, 0, Graphics.width, Graphics.height)
    contents.font.size = FONT_SIZE
    @active          = false
    @close_requested = false
    @side            = :left
    @left_oy         = 0
    @member_index    = 0
    @data            = []
    @battler_list    = []
    @history_lines   = []
    @prev_press      = {}
    @hold            = {}
    self.z = 1000
    self.openness = 0
  end

  def close_requested?; @close_requested; end

  #--------------------------------------------------------------------------
  # ● 激活:快照当前所有按键状态
  #--------------------------------------------------------------------------
  def activate
    @active = true
    @prev_press = {}
    @hold = {}
    [:UP, :DOWN, :LEFT, :RIGHT, :A, :B, :X].each do |k|
      @prev_press[k] = Input.press?(k)
      @hold[k] = nil
    end
  end

  def deactivate; @active = false; end
  def active?;    @active;         end

  def left_width;   (contents.width * 0.5).to_i - 8; end
  def right_x;      left_width + 16;                 end
  def right_width;  contents.width - right_x - 4;    end
  def right_top_height
    [MAX_MEMBERS * LINE_HEIGHT + 4, contents.height - 80].min
  end
  def right_bottom_y; right_top_height + 6; end

  #--------------------------------------------------------------------------
  # ● 字符宽度缓存
  #--------------------------------------------------------------------------
  def char_width(ch)
    key = [contents.font.size, ch]
    $char_width_cache[key] ||= contents.text_size(ch).width
  end

  #--------------------------------------------------------------------------
  # ● 设置数据
  #--------------------------------------------------------------------------
  def set_data(history, battlers)
    @data            = (history || []).dup
    @battler_list    = (battlers || []).first(MAX_MEMBERS)
    @member_index    = 0
    @side            = :left
    @close_requested = false
    rebuild
    @left_oy = left_max_oy
    refresh
  end

  def rebuild
    contents.font.size = FONT_SIZE
    @history_lines = []
    @data.each { |text| @history_lines.concat(wrap_text(text, left_width)) }
  end

  #--------------------------------------------------------------------------
  # ● 自动换行(逐字增量测量)
  #--------------------------------------------------------------------------
  def wrap_text(text, max_width)
    return [""] if text.empty?
    return [""] if text.nil?
    lines = []
    current = ""
    current_w = 0
    text.each_char do |c|
      if c == "\n"
        lines << current
        current = ""
        current_w = 0
        next
      end
      w = char_width(c)
      if current_w + w > max_width
        lines << current
        current = c
        current_w = w
      else
        current << c
        current_w += w
      end
    end
    lines << current unless current.empty?
    lines
  end

  def left_max_oy
    [@history_lines.size * LINE_HEIGHT - contents.height, 0].max
  end

  #--------------------------------------------------------------------------
  # ● 绘制
  #--------------------------------------------------------------------------
  def refresh
    contents.clear
    draw_left_panel
    draw_left_hints
    draw_separator
    draw_right_panel
    draw_focus_frame
  end

  def draw_left_panel
    w = left_width
    y = -@left_oy
    @history_lines.each do |line|
      if y + LINE_HEIGHT > 0 && y < contents.height
        contents.draw_text(0, y, w, LINE_HEIGHT, line)
      end
      y += LINE_HEIGHT
      break if y > contents.height
    end
  end

  #--------------------------------------------------------------------------
  # ● 左侧滚动提示:↑ 在顶部,↓ 在底部
  #--------------------------------------------------------------------------
  def draw_left_hints
    has_prev = @left_oy > 0
    has_next = @left_oy < left_max_oy

    lh = LINE_HEIGHT
    old_color = contents.font.color.clone
    old_size  = contents.font.size
    contents.font.color = Color.new(255, 220, 100)
    contents.font.size  = HINT_FONT_SIZE

    # 顶部:"↑ 上翻"
    if has_prev
      top_rect = Rect.new(0, 0, left_width, lh)
      contents.fill_rect(top_rect, Color.new(0, 0, 0, 200))
      contents.draw_text(top_rect, "↑ 上翻", 1)
    end

    # 底部:"↓ 下翻"
    if has_next
      bottom_rect = Rect.new(0, contents.height - lh, left_width, lh)
      contents.fill_rect(bottom_rect, Color.new(0, 0, 0, 200))
      contents.draw_text(bottom_rect, "↓ 下翻", 1)
    end

    contents.font.color = old_color
    contents.font.size  = old_size
  end

  def draw_separator
    x = left_width + 4
    contents.fill_rect(x, 0, 2, contents.height, Color.new(255, 255, 255, 60))
  end

  def draw_right_panel
    x = right_x
    w = right_width

    @battler_list.each_with_index do |b, i|
      y = i * LINE_HEIGHT
      if i == @member_index && @side == :right
        contents.fill_rect(x - 4, y - 1, w, LINE_HEIGHT + 2,
                           Color.new(255, 200, 50, 80))
        draw_border(x - 4, y - 1, w, LINE_HEIGHT + 2)
      end
      contents.draw_text(x, y, w, LINE_HEIGHT, b.name)
    end

    contents.fill_rect(x, right_top_height, w, 2, Color.new(255, 255, 255, 80))
    draw_member_detail(x, right_bottom_y, w, contents.height - right_bottom_y)
  end

  def draw_member_detail(x, y, w, h)
    return if @battler_list.empty?
    b = @battler_list[@member_index]
    return unless b

    contents.draw_text(x, y, w, LINE_HEIGHT, b.name)
    y += LINE_HEIGHT

    desc = get_description(b)
    if desc && !desc.empty?
      wrap_text(desc, w).each do |line|
        break if y + LINE_HEIGHT > contents.height
        contents.draw_text(x, y, w, LINE_HEIGHT, line)
        y += LINE_HEIGHT
      end
    end

    y += 6
    draw_states_two_columns(b, x, y, w, contents.height - y)
  end

  #--------------------------------------------------------------------------
  # ● 两列显示状态
  #--------------------------------------------------------------------------
  def draw_states_two_columns(battler, x, y, w, h)
    return if h <= 0
    old_size = contents.font.size
    contents.font.size = STATE_FONT_SIZE
    begin
      states = battler.states
                      .sort_by { |s| [-s.priority, s.id] }
                      .select  { |s| state_display_name(s) }
      return if states.empty?

      col_w    = w / 2
      text_max = col_w - STATE_ICON_W - 8

      first_col = []
      cur_y = 0
      remaining = []
      states.each do |s|
        if cur_y + LINE_HEIGHT > h
          remaining << s
          next
        end
        name = state_display_name(s)
        too_long = contents.text_size(name).width > text_max
        first_col << [s, too_long, cur_y]
        cur_y += LINE_HEIGHT
      end

      first_col.each do |s, too_long, offset_y|
        name = state_display_name(s)
        row_y = y + offset_y
        draw_icon(s.icon_index, x, row_y)
        if too_long
          contents.draw_text(x + STATE_ICON_W, row_y,
                             w - STATE_ICON_W, LINE_HEIGHT, name)
        else
          contents.draw_text(x + STATE_ICON_W, row_y,
                             col_w - STATE_ICON_W, LINE_HEIGHT, name)
        end
      end

      second_x = x + col_w
      cur_y = 0
      remaining.each do |s|
        while cur_y + LINE_HEIGHT <= h
          row_index = cur_y / LINE_HEIGHT
          if row_index < first_col.size && first_col[row_index][1]
            cur_y += LINE_HEIGHT
          else
            break
          end
        end
        break if cur_y + LINE_HEIGHT > h
        name = state_display_name(s)
        row_y = y + cur_y
        draw_icon(s.icon_index, second_x, row_y)
        contents.draw_text(second_x + STATE_ICON_W, row_y,
                           col_w - STATE_ICON_W, LINE_HEIGHT, name)
        cur_y += LINE_HEIGHT
      end
    ensure
      contents.font.size = old_size
    end
  end

  def get_description(battler)
    return nil unless battler.is_a?(Game_Enemy)
    note = battler.enemy.note
    return nil if note.nil? || note.empty?
    if note =~ /<说明[::]\s*([^>]+)>/m
      return $1.gsub("\\n", "\n").strip
    end
    nil
  end

  def state_display_name(state)
    return nil if state.note.nil?
    if state.note =~ /<状态名[::]\s*([^>]+)>/
      return $1.strip
    end
    nil
  end

  def draw_focus_frame
    draw_border(0, 0, left_width, contents.height) if @side == :left
  end

  def draw_border(x, y, w, h)
    c = Color.new(255, 200, 50)
    contents.fill_rect(x,     y,     w, 2, c)
    contents.fill_rect(x,     y+h-2, w, 2, c)
    contents.fill_rect(x,     y,     2, h, c)
    contents.fill_rect(x+w-2, y,     2, h, c)
  end

  #--------------------------------------------------------------------------
  # ● 输入状态更新(每帧一次)
  #--------------------------------------------------------------------------
  def update_input_state
    [:UP, :DOWN, :LEFT, :RIGHT, :A, :B, :X].each do |k|
      now = Input.press?(k)
      was = @prev_press[k] || false
      just = now && !was
      @prev_press[k] = now

      if just
        @hold[k] = 0
      elsif now
        @hold[k] = (@hold[k] || 0) + 1
      else
        @hold[k] = nil
      end
    end
  end

  # 首次按下(严格上升沿)
  def just_pressed?(key)
    @hold[key] == 0
  end

  # 首次按下 OR 按住后连续触发
  def triggered?(key)
    c = @hold[key]
    return false if c.nil?
    return true if c == 0
    c >= HOLD_START_FRAMES && (c - HOLD_START_FRAMES) % HOLD_INTERVAL == 0
  end

  #--------------------------------------------------------------------------
  # ● 更新
  #--------------------------------------------------------------------------
  def update
    super
    update_input_state
    return unless @active && openness > 0

    # 关闭
    if just_pressed?(:A) || just_pressed?(:B) || just_pressed?(:X)
      @close_requested = true
      deactivate
      close
      return
    end

    if @side == :left
      if just_pressed?(:RIGHT)
        @side = :right
        refresh
      elsif triggered?(:UP)
        @left_oy = [@left_oy - LINE_HEIGHT, 0].max
        refresh
      elsif triggered?(:DOWN)
        @left_oy = [@left_oy + LINE_HEIGHT, left_max_oy].min
        refresh
      end
    else
      if just_pressed?(:LEFT)
        @side = :left
        refresh
      elsif triggered?(:UP)
        move_cursor(-1)
      elsif triggered?(:DOWN)
        move_cursor(1)
      end
    end
  end

  def move_cursor(delta)
    return if @battler_list.empty?
    @member_index = (@member_index + delta) % @battler_list.size
    refresh
  end
end

#--------------------------------------------------------------------------
# ● Scene_BattleHistory — 独立场景
#--------------------------------------------------------------------------
class Scene_BattleHistory < Scene_Base
  def start
    super
    create_background
    create_window
  end

  def create_background
    @bg_sprite = Sprite.new
    @bg_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
    @bg_sprite.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height,
                                 Color.new(0, 0, 0, 200))
    @bg_sprite.z = 500
  end

  def create_window
    battlers = $game_party.members + $game_troop.members
    @window = Window_BattleHistoryLog.new
    @window.set_data($battle_log_history, battlers)
    @window.openness = 255
    @window.activate
  end

  def perform_transition
    Graphics.transition(4)
  end

  def update
    super
    @window.update
    if @window.close_requested? && @window.openness == 0
      return_scene
    end
  end

  def terminate
    @window.dispose
    @bg_sprite.dispose
    super
  end
end

#--------------------------------------------------------------------------
# ● Scene_Battle — 集成
#--------------------------------------------------------------------------
class Scene_Battle < Scene_Base
  alias history_log_battle_start battle_start
  def battle_start
    $battle_log_history = []
    history_log_battle_start
  end

  alias history_log_turn_end turn_end
  def turn_end
    history_log_turn_end
    if $battle_log_history && !$battle_log_history.empty? && $battle_log_history.last != ""
      $battle_log_history << ""
    end
  end

  alias history_log_update update
  def update
    history_log_update
    update_battle_history_log
  end

  def update_battle_history_log
    @history_cooldown ||= 0
    @history_cooldown -= 1 if @history_cooldown > 0
    return if @history_cooldown > 0

    return unless @actor_command_window
    return unless @actor_command_window.active
    return unless Input.trigger?(:A) || Input.trigger?(:X)
    open_battle_history_log
  end

  def open_battle_history_log
    saved_index = @actor_command_window ? @actor_command_window.index : 0
    saved_oy    = @actor_command_window ? @actor_command_window.oy : 0

    @actor_command_window.deactivate if @actor_command_window

    SceneManager.call(Scene_BattleHistory)
    SceneManager.scene.main
    if SceneManager.respond_to?(:force_recall)
      SceneManager.force_recall(self)
    else
      SceneManager.instance_variable_set(:@scene, self)
    end

    if @actor_command_window && !@actor_command_window.disposed?
      @actor_command_window.refresh
      @actor_command_window.activate
      @actor_command_window.select(saved_index)
      @actor_command_window.oy = saved_oy
    end
    refresh_status

    # 关键:解冻画面(子场景退出时执行了 Graphics.freeze)
    perform_transition

    @history_cooldown = 3
  end
end




            本帖来自P1论坛作者JasperCrazy,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg. blue/forum.php?mod=viewthread&tid=499333  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
简单的"检视战场"脚本New: d1.jpg
简体中文
繁體中文
English(英语)
日本語(日语)
Deutsch(德语)
Русский язык(俄语)
بالعربية(阿拉伯语)
Türkçe(土耳其语)
Português(葡萄牙语)
ภาษาไทย(泰国语)
한어(朝鲜语/韩语)
Français(法语)
关闭

幸运抽奖

社区每日抽奖来袭,快来试试你是欧皇还是非酋~

立即查看

Loading...

QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

GMT+8, 2026-10-24 22:05 , Processed in 0.065298 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

返回顶部