设为首页收藏本站同能贴吧 切换语言 繁体中文
开启辅助访问 切换到窄版
搜索附件  
同能RPG制作大师 › 附件中心 › 同能RM技术讨论区 › RPG Maker VA 讨论区 › 仿半条命/反恐精英喷绘系统New: 6acbd9c2a7d3f.png

仿半条命/反恐精英喷绘系统New: 6acbd9c2a7d3f.png

 

仿半条命/反恐精英喷绘系统New:
[Ruby] 纯文本查看 复制代码
#==============================================================================
# ** HL1 喷绘系统
#------------------------------------------------------------------------------
#  半条命风格喷绘系统,支持菜单选择图案、颜色调整和快速喷绘
#  作者:Ruigi
#  - 喷绘图片放在 Graphics/Sprays/ 文件夹(PNG 格式)
#  - 按 A 键快速喷绘
#  - 按住 Shift 同时喷绘,喷绘出现在玩家前方一格(墙上喷绘)
#  - 主菜单 -> 喷绘 进入设置界面
#  - 可配置喷绘混合模式(BLEND_TYPE)
#==============================================================================

module HL1_Spray
  #--------------------------------------------------------------------------
  # * 配置
  #--------------------------------------------------------------------------
  FOLDER_PATH = "Graphics/Sprays/"   # 喷绘图片文件夹
  SE_NAME     = "Spray"              # 喷绘音效文件名(不含扩展名)
  SE_VOLUME   = 80                   # 音量 (0-100)
  SE_PITCH    = 100                  # 音调 (50-150)
  MAX_SPRAYS  = 10                   # 地图上最多保留喷绘数量(超出移除最旧)
  SPRAY_OFFSET_X = 0

# 原地喷绘相对于玩家屏幕坐标的 X 偏移
  SPRAY_OFFSET_Y = 0               # 原地喷绘 Y 偏移(负值向上,通常放在脚底)
  SPRAY_Z     = 99                  # Z 坐标(高于角色,低于天气)
  SPRAY_KEY   = 0x48                 # 虚拟键码 0x48 = H 键
  FALLBACK_KEY = Input::X            # Win32API 不可用时的备用键(X 键)
  COLOR_EDIT_KEY = Input::Y          # 切换颜色编辑的按键(Y 键)
  COLOR_EDIT_KEY_NAME = "Y"          # 颜色编辑键的显示名称
  #--------------------------------------------------------------------------
  # * 混合模式
  #  0 = 正常混合
  #  1 = 加法混合(变亮)
  #  2 = 减法混合(变暗,近似正片叠底)
  #--------------------------------------------------------------------------
  BLEND_TYPE = 0                     # 设置为 2 实现正片叠底效果
  #--------------------------------------------------------------------------
  # * 墙上喷绘偏移(前方一格喷绘时的微调)
  #--------------------------------------------------------------------------
  WALL_SPRAY_OFFSET_X = 0            # 前方一格喷绘的 X 偏移(像素)
  WALL_SPRAY_OFFSET_Y = 0            # 前方一格喷绘的 Y 偏移(像素)
  #--------------------------------------------------------------------------
  # * 内部变量
  #--------------------------------------------------------------------------
  @spray_list = []                   # 喷绘文件名列表(不含路径和扩展名)
  @current_index = 0                 # 当前选中的喷绘索引
  @spray_color = Color.new(255,255,255,255)  # 当前喷绘颜色 (RGBA)
  @initialized = false               # 是否已加载列表
  @h_was_down = false                # 喷绘键上一帧状态(用于触发检测)

  # 尝试加载 Win32API(用于检测 H 键)
  begin
    require 'Win32API'
    GET_ASYNC_KEY_STATE = Win32API.new('user32', 'GetAsyncKeyState', 'i', 'i')
    USE_WIN32API = true
  rescue LoadError
    GET_ASYNC_KEY_STATE = nil
    USE_WIN32API = false
  end

  class << self
    #------------------------------------------------------------------------
    # * 加载喷绘文件列表
    #------------------------------------------------------------------------
    def load_sprays
      @spray_list.clear
      Dir.glob(FOLDER_PATH + "*.png").sort.each do |path|
        @spray_list << File.basename(path, ".png")
      end
      @initialized = true
      p "[喷绘系统] 已加载 #{@spray_list.size} 个喷绘图片。" if $TEST
    end

    #------------------------------------------------------------------------
    # * 获取喷绘名称列表
    #------------------------------------------------------------------------
    def spray_list
      load_sprays unless @initialized
      @spray_list
    end

    #------------------------------------------------------------------------
    # * 获取/设置当前喷绘索引
    #------------------------------------------------------------------------
    def current_index
      load_sprays unless @initialized
      @current_index
    end

    def current_index=(index)
      load_sprays unless @initialized
      @current_index = index.clamp(0, [spray_list.size - 1, 0].max)
    end

    #------------------------------------------------------------------------
    # * 获取/设置当前喷绘颜色
    #------------------------------------------------------------------------
    def spray_color
      @spray_color
    end

    def spray_color=(color)
      @spray_color = color
    end

    #------------------------------------------------------------------------
    # * 获取当前喷绘位图(失败返回 nil)
    #------------------------------------------------------------------------
    def current_bitmap
      return nil if spray_list.empty?
      name = spray_list[current_index]
      return nil unless name
      path = FOLDER_PATH + name + ".png"
      begin
        bitmap = Bitmap.new(path)
        p "[喷绘系统] 成功加载图片: #{path}" if $TEST
        return bitmap
      rescue => e
        p "[喷绘系统] 加载图片失败: #{path} - #{e.message}" if $TEST
        return nil
      end
    end

    #------------------------------------------------------------------------
    # * 设置当前喷绘(兼容旧接口)
    #------------------------------------------------------------------------
    def set_spray(index)
      self.current_index = index
    end

    #------------------------------------------------------------------------
    # * 打开喷绘选择场景(脚本调用兼容)
    #------------------------------------------------------------------------
    def choose_spray
      SceneManager.call(Scene_SpraySelect)
    end

    #------------------------------------------------------------------------
    # * 检测喷绘键是否刚按下(触发)
    #------------------------------------------------------------------------
    def h_trigger?
      if USE_WIN32API
        down = (GET_ASYNC_KEY_STATE.call(SPRAY_KEY) & 0x8000) != 0
        trigger = down && !@h_was_down
        @h_was_down = down
        p "[喷绘系统] 喷绘键按下: #{trigger}" if $TEST && trigger
        trigger
      else
        Input.trigger?(FALLBACK_KEY)
      end
    end

    #------------------------------------------------------------------------
    # * 执行喷绘
    #------------------------------------------------------------------------
    def spray
      return unless SceneManager.scene_is?(Scene_Map)
      p "[喷绘系统] 尝试喷绘..." if $TEST
      bitmap = current_bitmap
      if bitmap.nil?
        RPG::SE.new("Buzzer1", 80, 100).play
        p "[喷绘系统] 没有可用的喷绘图片!" if $TEST
        return
      end

      # 根据 Shift 键状态决定喷绘位置
      if Input.press?(Input::SHIFT)
        # 前方一格喷绘(墙上喷绘)
        tx = $game_player.x
        ty = $game_player.y
        case $game_player.direction
        when 2 then ty += 1   # 下
        when 4 then tx -= 1   # 左
        when 6 then tx += 1   # 右
        when 8 then ty -= 1   # 上
        end
        map_x = tx * 32 + 16 + HL1_Spray::WALL_SPRAY_OFFSET_X
        map_y = ty * 32 + 16 + HL1_Spray::WALL_SPRAY_OFFSET_Y
        p "[喷绘系统] 前方一格喷绘,格子(#{tx}, #{ty})" if $TEST
      else
        # 原地喷绘
        screen_x = $game_player.screen_x + HL1_Spray::SPRAY_OFFSET_X
        screen_y = $game_player.screen_y + HL1_Spray::SPRAY_OFFSET_Y
        map_x = screen_x + $game_map.display_x * 32
        map_y = screen_y + $game_map.display_y * 32
        p "[喷绘系统] 原地喷绘" if $TEST
      end

      spriteset = SceneManager.scene.instance_variable_get(:@spriteset)
      if spriteset
        spriteset.add_spray(map_x, map_y, bitmap, spray_color)
        RPG::SE.new(SE_NAME, SE_VOLUME, SE_PITCH).play
        p "[喷绘系统] 喷绘已添加,坐标: (#{map_x}, #{map_y})" if $TEST
      else
        p "[喷绘系统] 找不到 Spriteset!" if $TEST
        bitmap.dispose
      end
    end
  end
end

#==============================================================================
# ** 喷绘列表窗口(继承自 Window_Selectable,但屏蔽内置输入处理)
#==============================================================================

class Window_SprayList < Window_Selectable
  #--------------------------------------------------------------------------
  # * 初始化
  #--------------------------------------------------------------------------
  def initialize(x, y, width, height)
    super
    @data = HL1_Spray.spray_list
    self.contents = Bitmap.new(width - 32, [height - 32, 1].max)
    refresh
    self.index = HL1_Spray.current_index
    activate
  end

  #--------------------------------------------------------------------------
  # * 获取项目数
  #--------------------------------------------------------------------------
  def item_max
    @data ? @data.size : 0
  end

  #--------------------------------------------------------------------------
  # * 绘制项目
  #--------------------------------------------------------------------------
  def draw_item(index)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    name = @data[index]
    self.contents.draw_text(rect, name, 1)
  end

  #--------------------------------------------------------------------------
  # * 刷新
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    draw_all_items
  end

  #--------------------------------------------------------------------------
  # * 重写 update,阻止内置方向键等处理
  #--------------------------------------------------------------------------
  def update
    # 留空,不调用 super,完全由场景手动控制
  end
end

#==============================================================================
# ** 喷绘预览窗口
#==============================================================================

class Window_SprayPreview < Window_Base
  #--------------------------------------------------------------------------
  # * 初始化
  #--------------------------------------------------------------------------
  def initialize(x, y, width, height)
    super
    @sprite = Sprite.new
    @sprite.bitmap = nil
    @sprite.x = x + 16
    @sprite.y = y + 16
    @sprite.z = 200
    @sprite.blend_type = HL1_Spray::BLEND_TYPE  # 应用混合模式
    refresh
  end

  #--------------------------------------------------------------------------
  # * 刷新预览
  #--------------------------------------------------------------------------
  def refresh
    bitmap = HL1_Spray.current_bitmap
    if bitmap.nil?
      @sprite.bitmap = nil
      self.contents.clear
      self.contents.font.color = crisis_color
      self.contents.draw_text(0, 0, contents_width, 24, "未找到图片", 1)
      return
    end
    @sprite.bitmap = bitmap
    @sprite.color = HL1_Spray.spray_color
    self.contents.clear
  end

  #--------------------------------------------------------------------------
  # * 更新预览(外部调用)
  #--------------------------------------------------------------------------
  def update_preview
    refresh
  end

  #--------------------------------------------------------------------------
  # * 释放资源
  #--------------------------------------------------------------------------
  def dispose
    @sprite.bitmap.dispose if @sprite.bitmap
    @sprite.dispose
    super
  end
end

#==============================================================================
# ** 颜色调整窗口
#==============================================================================

class Window_SprayColor < Window_Base
  attr_reader :red, :green, :blue
  attr_accessor :index   # 0=红, 1=绿, 2=蓝

  def initialize(x, y, width, height)
    super
    @red, @green, @blue = HL1_Spray.spray_color.red, HL1_Spray.spray_color.green, HL1_Spray.spray_color.blue
    @index = 0
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end

  def refresh
    self.contents.clear
    labels = ["红:", "绿:", "蓝:"]
    values = [@red, @green, @blue]
    labels.each_with_index do |label, i|
      y = i * 28
      if i == @index
        self.contents.font.color = crisis_color
        self.contents.fill_rect(0, y, contents_width, 24, Color.new(255,255,255,80))
      else
        self.contents.font.color = system_color
      end
      self.contents.draw_text(0, y, 60, 24, label)
      self.contents.font.color = normal_color
      self.contents.draw_text(70, y, 60, 24, values.to_s, 2)
      bar_color = case i
                  when 0 then Color.new(@red, 0, 0)
                  when 1 then Color.new(0, @green, 0)
                  when 2 then Color.new(0, 0, @blue)
                  end
      self.contents.fill_rect(140, y + 4, 100, 16, bar_color)
    end
  end

  def change_color(delta)
    case @index
    when 0 then @red = (@red + delta).clamp(0, 255)
    when 1 then @green = (@green + delta).clamp(0, 255)
    when 2 then @blue = (@blue + delta).clamp(0, 255)
    end
    HL1_Spray.spray_color = Color.new(@red, @green, @blue, 255)
    refresh
  end
end

#==============================================================================
# ** 喷绘设置场景
#==============================================================================

class Scene_SpraySelect < Scene_MenuBase
  def start
    super
    create_background
    create_list_window
    create_preview_window
    create_color_window
    create_help_window
    @list_window.index = HL1_Spray.current_index
    @color_mode = false
    update_preview
    p "[喷绘系统] 设置场景已启动。列表项: #{HL1_Spray.spray_list.size}" if $TEST
  end

  def create_list_window
    @list_window = Window_SprayList.new(0, 48, 240, Graphics.height - 48 - 120)
    @list_window.activate
  end

  def create_preview_window
    @preview_window = Window_SprayPreview.new(240, 48, Graphics.width - 240, 200)
  end

  def create_color_window
    @color_window = Window_SprayColor.new(240, 248, Graphics.width - 240, 120)
  end

  def create_help_window
    @help_window = Window_Help.new(1)
    @help_window.set_text("选择喷绘图案。按 #{HL1_Spray::COLOR_EDIT_KEY_NAME} 或 Enter 编辑颜色。")
  end

  def update_preview
    @preview_window.update_preview
  end

  def update
    super
    @preview_window.update
    @color_window.update
    @help_window.update
    # 注意:不调用 @list_window.update,因为其 update 已被重写为空

    if !@color_mode
      # 列表编辑模式
      if Input.trigger?(Input::UP) || Input.trigger?(Input::DOWN)
        if Input.trigger?(Input::UP)
          @list_window.index = (@list_window.index - 1) % @list_window.item_max
        else
          @list_window.index = (@list_window.index + 1) % @list_window.item_max
        end
        # 同步全局当前索引
        HL1_Spray.current_index = @list_window.index
        @list_window.refresh
        update_preview
        Sound.play_cursor
      end

      if Input.trigger?(Input::C) || Input.trigger?(HL1_Spray::COLOR_EDIT_KEY)
        @color_mode = true
        @list_window.deactivate
        @help_window.set_text("调整颜色:上下键选择分量,左右键调整数值。Enter 保存,Esc 返回。")
      end

      if Input.trigger?(Input::B)
        return_scene
      end
    else
      # 颜色编辑模式
      if Input.trigger?(Input::B)
        @color_mode = false
        @list_window.activate
        @help_window.set_text("选择喷绘图案。按 #{HL1_Spray::COLOR_EDIT_KEY_NAME} 或 Enter 编辑颜色。")
      end

      if Input.trigger?(Input::C)
        HL1_Spray.current_index = @list_window.index  # 保存最终选择
        return_scene
      end

      if Input.trigger?(Input::UP) || Input.trigger?(Input::DOWN)
        if Input.trigger?(Input::UP)
          @color_window.index = (@color_window.index - 1) % 3
        else
          @color_window.index = (@color_window.index + 1) % 3
        end
        @color_window.refresh
        Sound.play_cursor
      end

      if Input.repeat?(Input::RIGHT)
        @color_window.change_color(5)
        update_preview
      elsif Input.repeat?(Input::LEFT)
        @color_window.change_color(-5)
        update_preview
      end
    end
  end

  def terminate
    super
    @list_window.dispose
    @preview_window.dispose
    @color_window.dispose
    @help_window.dispose
  end
end

#==============================================================================
# ** 主菜单场景
#==============================================================================

class Scene_Menu < Scene_MenuBase
  alias hl1_spray_create_command_window create_command_window
  def create_command_window
    hl1_spray_create_command_window
    @command_window.set_handler(:spray, method(:command_spray))
  end

  def command_spray
    SceneManager.call(Scene_SpraySelect)
  end
end

#==============================================================================
# ** 菜单命令窗口
#==============================================================================

class Window_MenuCommand < Window_Command
  alias hl1_spray_make_command_list make_command_list
  def make_command_list
    hl1_spray_make_command_list
    add_command("喷绘", :spray)
  end
end

#==============================================================================
# ** 地图精灵集合
#==============================================================================

class Spriteset_Map
  alias hl1_spray_initialize initialize
  alias hl1_spray_update update
  alias hl1_spray_dispose dispose

  def initialize
    @spray_sprites = []
    hl1_spray_initialize
  end

  def update
    hl1_spray_update
    update_spray_sprites
  end

  def update_spray_sprites
    @spray_sprites.each do |entry|
      sprite, map_x, map_y = entry
      screen_x = map_x - $game_map.display_x * 32
      screen_y = map_y - $game_map.display_y * 32
      sprite.x = screen_x + HL1_Spray::SPRAY_OFFSET_X
      sprite.y = screen_y + HL1_Spray::SPRAY_OFFSET_Y
    end
  end

  def add_spray(map_x, map_y, bitmap, color = Color.new(255,255,255,255))
    sprite = Sprite.new(@viewport1)
    sprite.bitmap = bitmap
    sprite.ox = bitmap.width / 2
    sprite.oy = bitmap.height / 2
    sprite.z = HL1_Spray::SPRAY_Z
    sprite.color = color
    sprite.blend_type = HL1_Spray::BLEND_TYPE  # 应用混合模式
    screen_x = map_x - $game_map.display_x * 32
    screen_y = map_y - $game_map.display_y * 32
    sprite.x = screen_x + HL1_Spray::SPRAY_OFFSET_X
    sprite.y = screen_y + HL1_Spray::SPRAY_OFFSET_Y
    @spray_sprites << [sprite, map_x, map_y]
    while @spray_sprites.size > HL1_Spray::MAX_SPRAYS
      old_entry = @spray_sprites.shift
      old_entry[0].bitmap.dispose
      old_entry[0].dispose
    end
  end

  def dispose
    @spray_sprites.each do |entry|
      entry[0].bitmap.dispose
      entry[0].dispose
    end
    @spray_sprites.clear
    hl1_spray_dispose
  end
end

#==============================================================================
# ** 地图场景
#==============================================================================

class Scene_Map
  alias hl1_spray_update update

  def update
    hl1_spray_update
    if HL1_Spray.h_trigger?
      HL1_Spray.spray
    end
  end
end







仿半条命/反恐精英喷绘系统New: 6acbd9c2a7d3f.png
         同一主题附件:
    6acbd9ba909d4.png
    6acbd9c2a7d3f.png
    6acbd9ca1309c.png
    012111rgsf5g5rkn3u8mie.png
    012112mhtcfbithrcyhb2m.png
    012258nwc2camccmcma6mc.png
简体中文
繁體中文
English(英语)
日本語(日语)
Deutsch(德语)
Русский язык(俄语)
بالعربية(阿拉伯语)
Türkçe(土耳其语)
Português(葡萄牙语)
ภาษาไทย(泰国语)
한어(朝鲜语/韩语)
Français(法语)
关闭

幸运抽奖

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

立即查看

Loading...

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

GMT+8, 2026-10-24 21:13 , Processed in 0.049503 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

返回顶部