| 赞 | 5 |
| VIP | |
| 好人卡 | |
| 积分 | 22 |
| 经验 | |
| 最后登录 | 2026-10-12 |
| 在线时间 | 60 小时 |
- 梦石
- 1
- 星屑
- 1219
- 在线时间
- 60 小时
- 注册时间
- 2023-9-8
- 回帖
- 20
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 Ruigi 于 2026-10-12 01:23 编辑
- #==============================================================================
- # ** 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, [url=home.php?mod=space&uid=8492]@blue[/url] = 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[i].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 [url=home.php?mod=space&uid=71174]@red[/url] = (@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
复制代码 |
|