赞 | 342 |
VIP | 10 |
好人卡 | 8 |
积分 | 262 |
经验 | 235776 |
最后登录 | 2024-9-23 |
在线时间 | 2387 小时 |
Lv5.捕梦者 (版主) 遠航の猫咪
- 梦石
- 3
- 星屑
- 23186
- 在线时间
- 2387 小时
- 注册时间
- 2005-10-15
- 帖子
- 1166
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 SailCat 于 2017-11-6 01:24 编辑
好像看到有人写过,但是为了给地图截个图自写一个Tilemap,是不是有点太小题大做了……想过渲染Tilemap有多麻烦吗?
于是写了下面这个。Tilemap是什么能吃吗……
500X500的地图亲测可用。
单框脚本,俺就不发测试工程了,免得积分清零了导致各位下载不能。
更新:
v1.3
再加速PNG处理(加速约6倍,果然优化无上限)
支持M(纯地图)、U(ULDS)、T(攻略)、A(航拍)四种截图模式
全脚本加注释(详细程度可比默认系统,700行脚本有1/3是注释……)
v1.2
优化缓存,现支持RM理论上限(500X500)的导出;优化进度显示功能
v1.1
加速PNG处理
执行效率(在M模式下):
90X90以下的地图秒过,250X250大约需要6秒,500X500大约需要25秒(Surface Book i7-6600M CPU测试数据)
我的204张地图的大坑,M模式下47秒全部输出完,其他模式1分多一点点。
#============================================================================== # ■ Map_Snapshot 1.3 (Build 171106) #------------------------------------------------------------------------------ # 地图截图工具 by SailCat @ Project1 # 该程序能将地图转换为PNG图片格式,包括三层图块和用图块ID绘制的事件,遮挡正确。 # 使用方法: # 1. 插入本脚本到Game_Temp(不是Main)之前。 # 2. 在插入脚本的下方,输入代码: # ms = Map_Snapshot.new # ms.set_scale(8) # 将地图缩小8倍,可以设定的值有1、2、4、8,默认为1 # ms.set_mode("U") # 设置输出模式为 ULDS分层模式 # 支持的模式有"M"普通地图、"U"ULDS分层模式、"T"攻略模式、"A"航拍模式 # M模式:默认的模式、渲染F5、F6、F7层的全部和F8层的地图元件事件 # U模式:内容同M模式,但将一张地图渲染成主角上层和主角下层的两张截图 # T模式:在M模式的基础上,再加上不移动的事件,事件取第1页、初始位置 # A模式:在M模式的基础上,再加上所有的非空事件,事件取第1页、初始位置 # 注:使用U模式会将地图放大率强制设为1:1 # ms.snap(6) # 转换Map006到图片 # ms.snaps(1..19) # 转换Map001到Map019到图片 # ms.snaps([1, 3, 7, 15]) # 转换Map001, Map003, Map007, Map015到图片 # ms.snap_all # 转换工程中所有地图到图片 # exit # 转换工程后退出 # 3. 注释掉700行以下的内容可以屏蔽此工具,正常测试游戏。 # 4. 该工具不修改工程内含文件,故执行完后不需要退出重新打开工程。 #============================================================================== #============================================================================== # ■ Scene_Reporter #------------------------------------------------------------------------------ # 通用工具处理进度显示模块。 #============================================================================== module Scene_Reporter @sprite = nil @message = "" @value = "" #-------------------------------------------------------------------------- # ● 更新显示 # message: 主要信息(滚屏) # value: 次要信息(不滚屏) #-------------------------------------------------------------------------- def self.update(message = "", value = "") # 初期化精灵 if @sprite == nil @sprite = Sprite.new @sprite.bitmap = Bitmap.new(640, 480) @sprite.bitmap.font.name = "楷体" @sprite.bitmap.font.size = 20 @start = Time.now @elapse = -1 end # 信息和所显信息完全相同的情况下,直接返回 return if (message == "" or @message == message) and @value == value # 主信息不相同的情况下,滚屏 if message != "" and @message != message @sprite.bitmap.blt(0, 0, @sprite.bitmap, Rect.new(0, 32, 640, 448)) @message = message @elapse = 0 end # 显示已用时间 elapse = Integer(Time.now - @start) if @elapse < elapse @elapse = elapse min = @elapse / 60 sec = @elapse % 60 @sprite.bitmap.fill_rect(580, 0, 60, 32, Color.new(0, 0, 0)) @sprite.bitmap.draw_text(580, 0, 60, 32, sprintf("%2d:%02d", min, sec)) end # 显示信息 @sprite.bitmap.fill_rect(0, 448, 640, 32, Color.new(0, 0, 0)) @sprite.bitmap.draw_text(0, 448, 640, 32, @message + value) @value = value # 更新画面 Graphics.update end #-------------------------------------------------------------------------- # ● 结束处理 # message: 最后的信息 #-------------------------------------------------------------------------- def self.close(message) # 更新最后的信息 Scene_Reporter.update(message) # 等待按键结束 loop do Graphics.update Input.update # 按下 C 键或 B 键的情况下 if Input.trigger?(Input::C) or Input.trigger?(Input::B) break end end # 释放精灵 if @sprite != nil @sprite.bitmap.dispose @sprite.dispose end end end #============================================================================== # ■ PNG #------------------------------------------------------------------------------ # PNG文件输出模块 by SailCat # 鸣谢:SixRC(取内存地址相关代码) # 用法:bitmap.output_png(filename) # filename: 输出的文件名,可含路径 #============================================================================== module PNG #-------------------------------------------------------------------------- # ● API 声明 #-------------------------------------------------------------------------- CopyMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i') CopyMemory_ii = Win32API.new('kernel32', 'RtlMoveMemory', 'iii', 'i') CopyMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i') CallWindowProc_p = Win32API.new('user32.dll','CallWindowProc','pppii','i') CallWindowProc_i = Win32API.new('user32.dll','CallWindowProc','ppiii','i') #-------------------------------------------------------------------------- # ● API 调用代码 #-------------------------------------------------------------------------- RGBAConvert = [ 0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x33, 0xC9, 0xEB, 0x0D, 0x8B, 0x10, 0x0F, 0xCA, 0xC1, 0xCA, 0x08, 0x89, 0x10, 0x41, 0x83, 0xC0, 0x04, 0x3B, 0x4D, 0x0C, 0x72, 0xEE, 0xC9, 0xC2, 0x10, 0x00].pack('C*') GetAddress = [ 0x8B, 0x74, 0x24, 0x08, 0x8B, 0x36, 0x8B, 0x76, 0x08, 0x8B, 0x76, 0x10, 0x8B, 0x7C, 0x24, 0x04, 0x89, 0x37, 0xC2, 0x10, 0x00].pack("C*") #-------------------------------------------------------------------------- # ● PNG 常量 #-------------------------------------------------------------------------- PNG_HEADER = "\211\120\116\107\015\012\032\012\000\000\000\015" PNG_IHDR_HEAD = "\111\110\104\122" PNG_IHDR_TAIL = "\010\006\000\000\000" PNG_IEND_CHUNK = "\000\000\000\000\111\105\116\104\256\102\140\202" #-------------------------------------------------------------------------- # ● 生成 PNG 文件情报头数据块(IHDR) #-------------------------------------------------------------------------- def make_png_ihdr data = PNG_IHDR_HEAD + [width, height].pack("N*") + PNG_IHDR_TAIL return data + [Zlib.crc32(data)].pack("N") end #-------------------------------------------------------------------------- # ● 保存 PNG 文件 # filename: 保存的文件名 #-------------------------------------------------------------------------- def output_png(filename) # 检查并建立路径 dir = filename.split("/") for i in 0...dir.size - 1 unless dir == "." add_dir = dir[0..i].join("/") Dir.mkdir(add_dir) rescue nil end end # 依次写入 PNG 文件内容 file = File.open(filename,"wb") file.write(PNG_HEADER) file.write(make_png_ihdr) file.write(make_png_idat) file.write(PNG_IEND_CHUNK) file.close Scene_Reporter.update("", "完成") end #-------------------------------------------------------------------------- # ● 使用临时文件生成 PNG 图像数据(IDAT) #-------------------------------------------------------------------------- def make_png_idat # 数据头 header = "IDAT" # 输出图像信息为临时文件并获得校验码 adler = [make_data_file].pack("N") # 读取临时文件 data = "\170\332" fsize = File.size("temp.gz") File.open("temp.gz", "rb") do |f| f.pos = 10 data.concat(f.read(fsize - 18)) data.concat(adler) end # 删除临时文件 File.delete("temp.gz") # 附加校验码 crc = [Zlib.crc32(header + data)].pack("N") size = [data.length].pack("N") # 返回数据 return size + header + data + crc end #-------------------------------------------------------------------------- # ● 将内存数据转储为文件,并返回adler32校验值 #-------------------------------------------------------------------------- def make_data_file # 建立缓存 cache = "\000" * 1 # 保存缓存原有结构信息 cache_info = [cache.size].pack("L")+ [cache].pack("p") cache_len = cache.id * 2 + 8; cache_addr = cache_len + 4 # 将缓存的指针覆盖使之指向 Bitmap 的图像数据 byte_size = 4 * width * height bitmap_info = [byte_size].pack("L") + [address].pack("L") CopyMemory_ip.call(cache_len, bitmap_info, 8) # 进度汇报线程 t = Thread.new do loop do; sleep(0.5); Scene_Reporter.update("", "转换格式..."); end end # BGRA 转 RGBA CallWindowProc_p.call(RGBAConvert, cache, width * height, 0, 0) # 结束进度汇报 Thread.kill(t) # 准备写入文件 x = 4 * width; y = [address + byte_size]; null = "\000" # adler32 校验码初期化 adler = Zlib.adler32 # 将缓存的大小改为单行位图 CopyMemory_ip.call(cache_len, [x].pack("L"), 4) # 打开临时文件 Zlib::GzipWriter.open("temp.gz", 8) do |gz| # 进度汇报线程 t = Thread.new do loop do sleep(0.5) Scene_Reporter.update("", sprintf("压缩图片...%d%%", (byte_size - y[0] + @address) * 100 / byte_size)) end end # 逐行上移 while y[0] > @address y[0] -= x # 更改缓存指针 CopyMemory_ip.call(cache_addr, y.pack("L"), 4) # 写入文件数据 gz.write(null) adler = Zlib.adler32(null, adler) gz.write(cache) adler = Zlib.adler32(cache, adler) end # 结束进度汇报 Thread.kill(t) # 关闭临时文件 gz.close end # 恢复指针原始结构信息以便释放 CopyMemory_ip.call(cache_len, cache_info, 8) # 返回校验码 return adler end #-------------------------------------------------------------------------- # ● 位图的数据内存地址 #-------------------------------------------------------------------------- def address if @address == nil buffer = "xxxx" CallWindowProc_i.call(GetAddress, buffer, object_id * 2 + 16, 0, 0) @address = buffer.unpack("L")[0] end return @address end end #============================================================================== # ■ Bitmap #------------------------------------------------------------------------------ # 内部位图类 #============================================================================== class Bitmap #-------------------------------------------------------------------------- # ● 导入 PNG 模块 #-------------------------------------------------------------------------- include PNG #-------------------------------------------------------------------------- # ● 合成 # rect: 合成的矩形 # src_bitmap: 合成的位图 # src_rect: 合成位图的传送元矩形 # opacity: 不透明度 # blend_type: 合成方式(1: 加法、2: 减法) #-------------------------------------------------------------------------- def blend_blt(rect, src_bitmap, src_rect, opacity, blend_type) # 纯透明的情况下 不合成 return if opacity == 0 # 建立临时位图 temp_bitmap = Bitmap.new(rect.width, rect.height) # 将源位图合成到临时位图,考虑缩放 if rect.width != src_rect.width or rect.height != src_rect.height temp_bitmap.stretch_blt(temp_bitmap.rect, src_bitmap, src_rect, opacity) else temp_bitmap.blt(0, 0, src_bitmap, src_rect, opacity) end # 逐点合成 for i in 0...rect.width for j in 0...rect.height # 取色 c1 = self.get_pixel(rect.x + i, rect.y + j) c2 = temp_bitmap.get_pixel(i, j) # 源位图此点无色的情况下,继续 next if c2.alpha == 0 # 加法 if blend_type == 1 c1.red += c2.red * c2.alpha / 255 * opacity / 255 c1.green += c2.green * c2.alpha / 255 * opacity / 255 c1.blue += c2.blue * c2.alpha / 255 * opacity / 255 # 减法 else c1.red = [0, c1.red - c2.red * c2.alpha / 255 * opacity / 255].max c1.green = [0, c1.green - c2.green * c2.alpha / 255 * opacity / 255].max c1.blue = [0, c1.blue - c2.blue * c2.alpha / 255 * opacity / 255].max end # 设色 self.set_pixel(rect.x + i, rect.y + j, c1) end end # 释放临时位图 temp_bitmap.dispose end end #============================================================================== # ■ Map_Snapshot #------------------------------------------------------------------------------ # 地图截图渲染引擎 #============================================================================== class Map_Snapshot #-------------------------------------------------------------------------- # ● 常量 #-------------------------------------------------------------------------- AUTOTILE_EXPAND = [ 555752218, 555752196, 555746586, 555746564, 186653466, 186653444, 186647834, 186647812, 554310426, 554310404, 554304794, 554304772, 185211674, 185211652, 185206042, 185206020, 522066200, 522061080, 186521880, 186516760, 353636110, 185863950, 352980750, 185208590, 589438236, 587865372, 589438212, 587865348, 757868326, 757868292, 757859622, 757859588, 589176088, 757862158, 319950092, 185732364, 387322128, 386535696, 791554344, 791554308, 724182308, 724174116, 387059980, 724176140, 791292196, 791548176, 791286028, 117833984 ] # 自动元件的展开方式 #-------------------------------------------------------------------------- # ● 初期化 #-------------------------------------------------------------------------- def initialize @tilesets = load_data("Data/Tilesets.rxdata") @mapnames = load_data("Data/MapInfos.rxdata") @mapnames.each {|k, v| @mapnames[k] = v.name.gsub(/[\\\/:*?|<>]/,"_")} @map_data = nil @output_bitmap = nil @tile_bitmap = nil @autotiles = [nil, nil, nil, nil, nil, nil, nil] @width = 0 @height = 0 @map_id = 0 @scale = 1 @mode = "M" end #-------------------------------------------------------------------------- # ● 设置缩放 # scale: 缩放比(1/1、1/2、1/4或1/8) #-------------------------------------------------------------------------- def set_scale(scale) @scale = scale if [1, 2, 4, 8].include?(scale) end #-------------------------------------------------------------------------- # ● 设置渲染模式 # mode: 渲染模式(M、U、A、T) #-------------------------------------------------------------------------- def set_mode(mode) @mode = mode if ["M", "U", "A", "T"].include?(mode) end #-------------------------------------------------------------------------- # ● 地图截图 # map_id: 地图ID #-------------------------------------------------------------------------- def snap(map_id) # 如果是ULDS模式,放大率强制为1 set_scale(1) if @mode == "U" # 加载地图数据 map_name = sprintf("Data/Map%03d.rxdata", map_id) if FileTest.exist?(map_name) @map_id = map_id @map_data = load_data(map_name) @width = @map_data.width @height = @map_data.height @tileset = @tilesets[@map_data.tileset_id] @tile_bitmap = RPG::Cache.tileset(@tileset.tileset_name) @tile_rect = Rect.new(0, 0, 32, 32) # 用于输出的位图 @output_bitmap = Bitmap.new(@width * 32 / @scale, @height * 32 / @scale) for i in 0..6 @autotiles[i] = RPG::Cache.autotile(@tileset.autotile_names[i]) end @auto_stretch = {} # 渲染 snapshot # 输出截图 filename = sprintf("MapSnapshots/%03d-%s.png", map_id, @mapnames[map_id]) @output_bitmap.output_png(filename) # 如果是ULDS模式,渲染第二张图 if @mode == "U" @output_bitmap.clear snapshot(true) f2 = sprintf("MapSnapshots/%03d-%s[U].png", map_id, @mapnames[map_id]) @output_bitmap.output_png(f2) end # 释放位图 @output_bitmap.dispose @auto_stretch.each_value {|v| v.dispose} for i in 0..6 @autotiles[i].dispose end @autotiles = [nil, nil, nil, nil, nil, nil, nil] @tile_bitmap.dispose @tile_bitmap = nil end end #-------------------------------------------------------------------------- # ● 渲染地图 # ulds: ULDS第二层渲染专用 #-------------------------------------------------------------------------- def snapshot(ulds = false) # 筛选需要渲染的事件集 @effect_events = @map_data.events.select do |k, v| # 事件的地图元件有效的情况下,总是渲染 effective = (v.pages[0].graphic.tile_id > 0) # 分层模式的情况下 if @mode == "U" # 事件还需要满足优先级条件才渲染 effective &= (v.pages[0].always_on_top == ulds) # 攻略模式的情况下 elsif @mode == "T" # 事件不移动且朝向固定也需渲染 effective |= (v.pages[0].graphic.character_name != "" and v.pages[0].move_type == 0) # 航拍模式的情况下 elsif @mode == "A" # 所有非空事件一律渲染 effective |= (v.pages[0].graphic.character_name != "") end # 筛选 effective end # 纯地图模式的情况下,直接按格快速渲染 return direct_paint if @mode == "M" # 分层渲染底图 unless ulds # 渲染没有优先级的图块 for k in 0...3 for j in 0...@height for i in 0...@width # 取得图块 tile_id = @map_data.data[i, j, k] # 优先级为0的情况下 if tile_id > 0 and @tileset.priorities[tile_id] == 0 paint(i, j, tile_id) end end end # 每层汇报进度 Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id), sprintf("渲染下层...%d%%", (k + 1) * 33)) end # 渲染不在最前显示的图块事件 @effect_events.each do |f| e = f[1]; g = e.pages[0].graphic if g.tile_id > 0 and not e.pages[0].always_on_top paint(e.x, e.y, g.tile_id, g.character_hue, g.opacity, g.blend_type) end end # 分层模式的情况下,渲染结束 return if @mode == "U" end # 分层渲染顶图 # 计算剩余所有图块的 Z 坐标 z_indexes = {} for k in 0...3 for j in 0...@height for i in 0...@width # 取得图块 tile_id = @map_data.data[i, j, k] # 优先级不为0的情况下 if tile_id > 0 and @tileset.priorities[tile_id] > 0 z = (@tileset.priorities[tile_id] + j) * 32 + 32 z_indexes[z] = (z_indexes[z] || []).push([i, j, tile_id]) end end end end # 计算所有需要渲染的事件的 Z 坐标 @effect_events.each do |f| e = f[1]; g = e.pages[0].graphic # 事件的 Z 坐标 z = e.pages[0].always_on_top ? 32768 : e.y * 32 + 32 # 是普通事件的情况下 if g.tile_id == 0 or e.pages[0].always_on_top z_indexes[z] = (z_indexes[z] || []).push([e.x, e.y, g]) end end # 按 Z 坐标开始绘制 l = n = z_indexes.keys.size z_indexes.keys.sort.each do |k| v = z_indexes[k] while not v.empty? tile = v.shift x = tile[0]; y = tile[1]; g = tile[2] # 如果此处是图块 if g.is_a?(Numeric) paint(x, y, g) # 如果此处是事件 elsif g.tile_id > 0 paint(x, y, g.tile_id, g.character_hue, g.opacity, g.blend_type) else paint_character(x, y, g) end end n -= 1 # 已绘制20层的情况下,汇报进度 if n % 20 == 0 Scene_Reporter.update("", sprintf("渲染上层...%d%%",(l - n) * 100 / l)) end end end #-------------------------------------------------------------------------- # ● 快速逐格渲染(M模式用) #-------------------------------------------------------------------------- def direct_paint # 变换有效事件列表 events = @effect_events.inject({}) do |s, f| e = f[1] s[[e.x, e.y]] = [e.pages[0].graphic, e.pages[0].always_on_top] s end # 逐格绘制 for j in 0...@height for i in 0...@width # 获得此处的三层图块 tiles = [@map_data.data[i, j, 0], @map_data.data[i, j, 1], @map_data.data[i, j, 2]] # 获得此处三层图块的 Z 坐标 z_indexes = [@tileset.priorities[tiles[0]] * 32, @tileset.priorities[tiles[1]] * 32 + 1, @tileset.priorities[tiles[2]] * 32 + 2] # 如果此处有事件,压入图块数据 if events.has_key?([i, j]) tiles.push(events[[i, j]][0].tile_id) z_indexes.push(events[[i, j]][1] ? 999 : 3) end # 从最小值 Z 坐标开始绘制 while tiles.size > 0 z_index = z_indexes.min index = z_indexes.index(z_index) tile_id = tiles[index] # 图块是事件的情况下,按事件图块的合成方式绘成 if z_index == 3 or z_index == 999 opacity = events[[i, j]][0].opacity hue = events[[i, j]][0].character_hue blend_type = events[[i, j]][0].blend_type else # 基本绘成 hue = blend_type = 0 opacity = 255 end paint(i, j, tile_id, hue, opacity, blend_type) if tile_id > 0 tiles.delete_at(index) z_indexes.delete_at(index) end end # 每绘制 20 行汇报一次进度 if j % 20 == 0 or j == @height - 1 Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id), sprintf("渲染地图...%d%%", (j + 1) * 100 / @height)) end end end #-------------------------------------------------------------------------- # ● 绘制格子 # x, y: 地图的坐标 # tile_id: 元件 ID # hue_change: 色相 # opacity: 不透明度 # blend_type: 合成方式 (0: 普通、1: 加法、2: 减法) #-------------------------------------------------------------------------- def paint(x, y, tile_id, hue_change = 0, opacity = 255, blend_type = 0) # 透明的图块不需要绘制 return if opacity == 0 # 绘制的原点 ox = x * 32 / @scale oy = y * 32 / @scale # 是普通元件的情况下 if tile_id >= 384 # 取得源位图 if hue_change != 0 (src = @tile_bitmap.clone).hue_change(hue) else src = @tile_bitmap end # 传送矩形 tile_id -= 384 src_rect = Rect.new((tile_id % 8) * 32, (tile_id / 8) * 32, 32, 32) # 绘制合成 if blend_type == 0 if @scale == 1 @output_bitmap.blt(ox, oy, src, src_rect, opacity) else @output_bitmap.stretch_blt(Rect.new(ox, oy, 32 / @scale, 32 / @scale), src, rect, opacity) end else @output_bitmap.blend_blt(Rect.new(ox, oy, 32 / @scale, 32 / @scale), src, rect, opacity, blend_type) end # 色相有差异的情况下要释放 src.dispose if hue_change != 0 # 不是普通元件的情况下(即自动元件) else # 获得自动元件的展开样式 autotile = @autotiles[tile_id / 48 - 1] tile_form = AUTOTILE_EXPAND[tile_id % 48] tile_lu = tile_form & 0xff tile_ru = (tile_form & 0xff00) >> 8 tile_ld = (tile_form & 0xff0000) >> 16 tile_rd = (tile_form & 0xff000000) >> 24 # 缩放比为1的情况下,直接拷贝原件 if @scale == 1 @output_bitmap.blt(ox, oy, autotile, auto_rect(tile_lu), 255) @output_bitmap.blt(ox + 16, oy, autotile, auto_rect(tile_ru), 255) @output_bitmap.blt(ox, oy + 16, autotile, auto_rect(tile_ld), 255) @output_bitmap.blt(ox + 16, oy + 16, autotile, auto_rect(tile_rd), 255) # 缩放比不为1的情况下 else s = 32 / @scale temp_bitmap = Bitmap.new(32, 32) temp_bitmap.blt(0, 0, autotile, auto_rect(tile_lu), 255) temp_bitmap.blt(16, 0, autotile, auto_rect(tile_ru), 255) temp_bitmap.blt(0, 16, autotile, auto_rect(tile_ld), 255) temp_bitmap.blt(16, 16, autotile, auto_rect(tile_rd), 255) @output_bitmap.stretch_blt(Rect.new(ox, oy, s, s), temp_bitmap, @tile_rect, 255) temp_bitmap.dispose end end end #-------------------------------------------------------------------------- # ● 绘制事件 # x, y: 地图的坐标 # g: 事件的图像(RPG::Event::Graphic) #-------------------------------------------------------------------------- def paint_character(x, y, g) # 透明的角色不需要绘制 return if g.opacity == 0 # 绘制的原点 bitmap = RPG::Cache.character(g.character_name, g.character_hue) rect = char_rect(bitmap.width, bitmap.height, g.direction, g.pattern) ox = (x * 32 - rect.width / 2 + 16) / @scale oy = (y * 32 - rect.height + 32) / @scale w = rect.width / @scale h = rect.height / @scale # 普通叠加的情况下,传送位图 if g.blend_type == 0 if @scale == 1 @output_bitmap.blt(ox, oy, bitmap, rect, g.opacity) else @output_bitmap.stretch_blt(Rect.new(ox, oy, w, h), bitmap, rect, g.opacity) end else @output_bitmap.blend_blt(Rect.new(ox, oy, w, h), bitmap, rect, g.opacity, g.blend_type) end end #-------------------------------------------------------------------------- # ● 事件的传送矩形 # width, height: 事件的位图宽高 # direction: 事件的朝向 # pattern: 事件的模式 #-------------------------------------------------------------------------- def char_rect(width, height, direction, pattern) Rect.new(pattern * width / 4, (direction - 2) * height / 8, width / 4, height / 4) end #-------------------------------------------------------------------------- # ● 自动元件的传送矩形 # region: 自动元件的展开方式(0-47) #-------------------------------------------------------------------------- def auto_rect(region) Rect.new((region % 6) * 16, (region / 6) * 16, 16, 16) end #-------------------------------------------------------------------------- # ● 连续截图 # range: 截图的地图ID列表 #-------------------------------------------------------------------------- def snaps(range) Scene_Reporter.update("准备就绪") if range.is_a?(Range) or range.is_a?(Array) range.each do |i| snap(i) end end Scene_Reporter.close("完成,按B或C键继续") end #-------------------------------------------------------------------------- # ● 全部截图 #-------------------------------------------------------------------------- def snap_all snaps(1..999) end end ms = Map_Snapshot.new ms.set_scale(1) ms.set_mode("T") ms.snap_all exit
#==============================================================================
# ■ Map_Snapshot 1.3 (Build 171106)
#------------------------------------------------------------------------------
# 地图截图工具 by SailCat @ Project1
# 该程序能将地图转换为PNG图片格式,包括三层图块和用图块ID绘制的事件,遮挡正确。
# 使用方法:
# 1. 插入本脚本到Game_Temp(不是Main)之前。
# 2. 在插入脚本的下方,输入代码:
# ms = Map_Snapshot.new
# ms.set_scale(8) # 将地图缩小8倍,可以设定的值有1、2、4、8,默认为1
# ms.set_mode("U") # 设置输出模式为 ULDS分层模式
# 支持的模式有"M"普通地图、"U"ULDS分层模式、"T"攻略模式、"A"航拍模式
# M模式:默认的模式、渲染F5、F6、F7层的全部和F8层的地图元件事件
# U模式:内容同M模式,但将一张地图渲染成主角上层和主角下层的两张截图
# T模式:在M模式的基础上,再加上不移动的事件,事件取第1页、初始位置
# A模式:在M模式的基础上,再加上所有的非空事件,事件取第1页、初始位置
# 注:使用U模式会将地图放大率强制设为1:1
# ms.snap(6) # 转换Map006到图片
# ms.snaps(1..19) # 转换Map001到Map019到图片
# ms.snaps([1, 3, 7, 15]) # 转换Map001, Map003, Map007, Map015到图片
# ms.snap_all # 转换工程中所有地图到图片
# exit # 转换工程后退出
# 3. 注释掉700行以下的内容可以屏蔽此工具,正常测试游戏。
# 4. 该工具不修改工程内含文件,故执行完后不需要退出重新打开工程。
#==============================================================================
#==============================================================================
# ■ Scene_Reporter
#------------------------------------------------------------------------------
# 通用工具处理进度显示模块。
#==============================================================================
module Scene_Reporter
@sprite = nil
@message = ""
@value = ""
#--------------------------------------------------------------------------
# ● 更新显示
# message: 主要信息(滚屏)
# value: 次要信息(不滚屏)
#--------------------------------------------------------------------------
def self.update(message = "", value = "")
# 初期化精灵
if @sprite == nil
@sprite = Sprite.new
@sprite.bitmap = Bitmap.new(640, 480)
@sprite.bitmap.font.name = "楷体"
@sprite.bitmap.font.size = 20
@start = Time.now
@elapse = -1
end
# 信息和所显信息完全相同的情况下,直接返回
return if (message == "" or @message == message) and @value == value
# 主信息不相同的情况下,滚屏
if message != "" and @message != message
@sprite.bitmap.blt(0, 0, @sprite.bitmap, Rect.new(0, 32, 640, 448))
@message = message
@elapse = 0
end
# 显示已用时间
elapse = Integer(Time.now - @start)
if @elapse < elapse
@elapse = elapse
min = @elapse / 60
sec = @elapse % 60
@sprite.bitmap.fill_rect(580, 0, 60, 32, Color.new(0, 0, 0))
@sprite.bitmap.draw_text(580, 0, 60, 32, sprintf("%2d:%02d", min, sec))
end
# 显示信息
@sprite.bitmap.fill_rect(0, 448, 640, 32, Color.new(0, 0, 0))
@sprite.bitmap.draw_text(0, 448, 640, 32, @message + value)
@value = value
# 更新画面
Graphics.update
end
#--------------------------------------------------------------------------
# ● 结束处理
# message: 最后的信息
#--------------------------------------------------------------------------
def self.close(message)
# 更新最后的信息
Scene_Reporter.update(message)
# 等待按键结束
loop do
Graphics.update
Input.update
# 按下 C 键或 B 键的情况下
if Input.trigger?(Input::C) or Input.trigger?(Input::B)
break
end
end
# 释放精灵
if @sprite != nil
@sprite.bitmap.dispose
@sprite.dispose
end
end
end
#==============================================================================
# ■ PNG
#------------------------------------------------------------------------------
# PNG文件输出模块 by SailCat
# 鸣谢:SixRC(取内存地址相关代码)
# 用法:bitmap.output_png(filename)
# filename: 输出的文件名,可含路径
#==============================================================================
module PNG
#--------------------------------------------------------------------------
# ● API 声明
#--------------------------------------------------------------------------
CopyMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
CopyMemory_ii = Win32API.new('kernel32', 'RtlMoveMemory', 'iii', 'i')
CopyMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
CallWindowProc_p = Win32API.new('user32.dll','CallWindowProc','pppii','i')
CallWindowProc_i = Win32API.new('user32.dll','CallWindowProc','ppiii','i')
#--------------------------------------------------------------------------
# ● API 调用代码
#--------------------------------------------------------------------------
RGBAConvert = [
0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x33, 0xC9,
0xEB, 0x0D, 0x8B, 0x10, 0x0F, 0xCA, 0xC1, 0xCA,
0x08, 0x89, 0x10, 0x41, 0x83, 0xC0, 0x04, 0x3B,
0x4D, 0x0C, 0x72, 0xEE, 0xC9, 0xC2, 0x10, 0x00].pack('C*')
GetAddress = [
0x8B, 0x74, 0x24, 0x08, 0x8B, 0x36, 0x8B, 0x76,
0x08, 0x8B, 0x76, 0x10, 0x8B, 0x7C, 0x24, 0x04,
0x89, 0x37, 0xC2, 0x10, 0x00].pack("C*")
#--------------------------------------------------------------------------
# ● PNG 常量
#--------------------------------------------------------------------------
PNG_HEADER = "\211\120\116\107\015\012\032\012\000\000\000\015"
PNG_IHDR_HEAD = "\111\110\104\122"
PNG_IHDR_TAIL = "\010\006\000\000\000"
PNG_IEND_CHUNK = "\000\000\000\000\111\105\116\104\256\102\140\202"
#--------------------------------------------------------------------------
# ● 生成 PNG 文件情报头数据块(IHDR)
#--------------------------------------------------------------------------
def make_png_ihdr
data = PNG_IHDR_HEAD + [width, height].pack("N*") + PNG_IHDR_TAIL
return data + [Zlib.crc32(data)].pack("N")
end
#--------------------------------------------------------------------------
# ● 保存 PNG 文件
# filename: 保存的文件名
#--------------------------------------------------------------------------
def output_png(filename)
# 检查并建立路径
dir = filename.split("/")
for i in 0...dir.size - 1
unless dir == "."
add_dir = dir[0..i].join("/")
Dir.mkdir(add_dir) rescue nil
end
end
# 依次写入 PNG 文件内容
file = File.open(filename,"wb")
file.write(PNG_HEADER)
file.write(make_png_ihdr)
file.write(make_png_idat)
file.write(PNG_IEND_CHUNK)
file.close
Scene_Reporter.update("", "完成")
end
#--------------------------------------------------------------------------
# ● 使用临时文件生成 PNG 图像数据(IDAT)
#--------------------------------------------------------------------------
def make_png_idat
# 数据头
header = "IDAT"
# 输出图像信息为临时文件并获得校验码
adler = [make_data_file].pack("N")
# 读取临时文件
data = "\170\332"
fsize = File.size("temp.gz")
File.open("temp.gz", "rb") do |f|
f.pos = 10
data.concat(f.read(fsize - 18))
data.concat(adler)
end
# 删除临时文件
File.delete("temp.gz")
# 附加校验码
crc = [Zlib.crc32(header + data)].pack("N")
size = [data.length].pack("N")
# 返回数据
return size + header + data + crc
end
#--------------------------------------------------------------------------
# ● 将内存数据转储为文件,并返回adler32校验值
#--------------------------------------------------------------------------
def make_data_file
# 建立缓存
cache = "\000" * 1
# 保存缓存原有结构信息
cache_info = [cache.size].pack("L")+ [cache].pack("p")
cache_len = cache.id * 2 + 8; cache_addr = cache_len + 4
# 将缓存的指针覆盖使之指向 Bitmap 的图像数据
byte_size = 4 * width * height
bitmap_info = [byte_size].pack("L") + [address].pack("L")
CopyMemory_ip.call(cache_len, bitmap_info, 8)
# 进度汇报线程
t = Thread.new do
loop do; sleep(0.5); Scene_Reporter.update("", "转换格式..."); end
end
# BGRA 转 RGBA
CallWindowProc_p.call(RGBAConvert, cache, width * height, 0, 0)
# 结束进度汇报
Thread.kill(t)
# 准备写入文件
x = 4 * width; y = [address + byte_size]; null = "\000"
# adler32 校验码初期化
adler = Zlib.adler32
# 将缓存的大小改为单行位图
CopyMemory_ip.call(cache_len, [x].pack("L"), 4)
# 打开临时文件
Zlib::GzipWriter.open("temp.gz", 8) do |gz|
# 进度汇报线程
t = Thread.new do
loop do
sleep(0.5)
Scene_Reporter.update("", sprintf("压缩图片...%d%%",
(byte_size - y[0] + @address) * 100 / byte_size))
end
end
# 逐行上移
while y[0] > @address
y[0] -= x
# 更改缓存指针
CopyMemory_ip.call(cache_addr, y.pack("L"), 4)
# 写入文件数据
gz.write(null)
adler = Zlib.adler32(null, adler)
gz.write(cache)
adler = Zlib.adler32(cache, adler)
end
# 结束进度汇报
Thread.kill(t)
# 关闭临时文件
gz.close
end
# 恢复指针原始结构信息以便释放
CopyMemory_ip.call(cache_len, cache_info, 8)
# 返回校验码
return adler
end
#--------------------------------------------------------------------------
# ● 位图的数据内存地址
#--------------------------------------------------------------------------
def address
if @address == nil
buffer = "xxxx"
CallWindowProc_i.call(GetAddress, buffer, object_id * 2 + 16, 0, 0)
@address = buffer.unpack("L")[0]
end
return @address
end
end
#==============================================================================
# ■ Bitmap
#------------------------------------------------------------------------------
# 内部位图类
#==============================================================================
class Bitmap
#--------------------------------------------------------------------------
# ● 导入 PNG 模块
#--------------------------------------------------------------------------
include PNG
#--------------------------------------------------------------------------
# ● 合成
# rect: 合成的矩形
# src_bitmap: 合成的位图
# src_rect: 合成位图的传送元矩形
# opacity: 不透明度
# blend_type: 合成方式(1: 加法、2: 减法)
#--------------------------------------------------------------------------
def blend_blt(rect, src_bitmap, src_rect, opacity, blend_type)
# 纯透明的情况下 不合成
return if opacity == 0
# 建立临时位图
temp_bitmap = Bitmap.new(rect.width, rect.height)
# 将源位图合成到临时位图,考虑缩放
if rect.width != src_rect.width or rect.height != src_rect.height
temp_bitmap.stretch_blt(temp_bitmap.rect, src_bitmap, src_rect, opacity)
else
temp_bitmap.blt(0, 0, src_bitmap, src_rect, opacity)
end
# 逐点合成
for i in 0...rect.width
for j in 0...rect.height
# 取色
c1 = self.get_pixel(rect.x + i, rect.y + j)
c2 = temp_bitmap.get_pixel(i, j)
# 源位图此点无色的情况下,继续
next if c2.alpha == 0
# 加法
if blend_type == 1
c1.red += c2.red * c2.alpha / 255 * opacity / 255
c1.green += c2.green * c2.alpha / 255 * opacity / 255
c1.blue += c2.blue * c2.alpha / 255 * opacity / 255
# 减法
else
c1.red = [0, c1.red - c2.red * c2.alpha / 255 * opacity / 255].max
c1.green = [0, c1.green - c2.green * c2.alpha / 255 * opacity / 255].max
c1.blue = [0, c1.blue - c2.blue * c2.alpha / 255 * opacity / 255].max
end
# 设色
self.set_pixel(rect.x + i, rect.y + j, c1)
end
end
# 释放临时位图
temp_bitmap.dispose
end
end
#==============================================================================
# ■ Map_Snapshot
#------------------------------------------------------------------------------
# 地图截图渲染引擎
#==============================================================================
class Map_Snapshot
#--------------------------------------------------------------------------
# ● 常量
#--------------------------------------------------------------------------
AUTOTILE_EXPAND = [
555752218, 555752196, 555746586, 555746564, 186653466, 186653444,
186647834, 186647812, 554310426, 554310404, 554304794, 554304772,
185211674, 185211652, 185206042, 185206020, 522066200, 522061080,
186521880, 186516760, 353636110, 185863950, 352980750, 185208590,
589438236, 587865372, 589438212, 587865348, 757868326, 757868292,
757859622, 757859588, 589176088, 757862158, 319950092, 185732364,
387322128, 386535696, 791554344, 791554308, 724182308, 724174116,
387059980, 724176140, 791292196, 791548176, 791286028, 117833984
] # 自动元件的展开方式
#--------------------------------------------------------------------------
# ● 初期化
#--------------------------------------------------------------------------
def initialize
@tilesets = load_data("Data/Tilesets.rxdata")
@mapnames = load_data("Data/MapInfos.rxdata")
@mapnames.each {|k, v| @mapnames[k] = v.name.gsub(/[\\\/:*?|<>]/,"_")}
@map_data = nil
@output_bitmap = nil
@tile_bitmap = nil
@autotiles = [nil, nil, nil, nil, nil, nil, nil]
@width = 0
@height = 0
@map_id = 0
@scale = 1
@mode = "M"
end
#--------------------------------------------------------------------------
# ● 设置缩放
# scale: 缩放比(1/1、1/2、1/4或1/8)
#--------------------------------------------------------------------------
def set_scale(scale)
@scale = scale if [1, 2, 4, 8].include?(scale)
end
#--------------------------------------------------------------------------
# ● 设置渲染模式
# mode: 渲染模式(M、U、A、T)
#--------------------------------------------------------------------------
def set_mode(mode)
@mode = mode if ["M", "U", "A", "T"].include?(mode)
end
#--------------------------------------------------------------------------
# ● 地图截图
# map_id: 地图ID
#--------------------------------------------------------------------------
def snap(map_id)
# 如果是ULDS模式,放大率强制为1
set_scale(1) if @mode == "U"
# 加载地图数据
map_name = sprintf("Data/Map%03d.rxdata", map_id)
if FileTest.exist?(map_name)
@map_id = map_id
@map_data = load_data(map_name)
@width = @map_data.width
@height = @map_data.height
@tileset = @tilesets[@map_data.tileset_id]
@tile_bitmap = RPG::Cache.tileset(@tileset.tileset_name)
@tile_rect = Rect.new(0, 0, 32, 32)
# 用于输出的位图
@output_bitmap = Bitmap.new(@width * 32 / @scale, @height * 32 / @scale)
for i in 0..6
@autotiles[i] = RPG::Cache.autotile(@tileset.autotile_names[i])
end
@auto_stretch = {}
# 渲染
snapshot
# 输出截图
filename = sprintf("MapSnapshots/%03d-%s.png", map_id, @mapnames[map_id])
@output_bitmap.output_png(filename)
# 如果是ULDS模式,渲染第二张图
if @mode == "U"
@output_bitmap.clear
snapshot(true)
f2 = sprintf("MapSnapshots/%03d-%s[U].png", map_id, @mapnames[map_id])
@output_bitmap.output_png(f2)
end
# 释放位图
@output_bitmap.dispose
@auto_stretch.each_value {|v| v.dispose}
for i in 0..6
@autotiles[i].dispose
end
@autotiles = [nil, nil, nil, nil, nil, nil, nil]
@tile_bitmap.dispose
@tile_bitmap = nil
end
end
#--------------------------------------------------------------------------
# ● 渲染地图
# ulds: ULDS第二层渲染专用
#--------------------------------------------------------------------------
def snapshot(ulds = false)
# 筛选需要渲染的事件集
@effect_events = @map_data.events.select do |k, v|
# 事件的地图元件有效的情况下,总是渲染
effective = (v.pages[0].graphic.tile_id > 0)
# 分层模式的情况下
if @mode == "U"
# 事件还需要满足优先级条件才渲染
effective &= (v.pages[0].always_on_top == ulds)
# 攻略模式的情况下
elsif @mode == "T"
# 事件不移动且朝向固定也需渲染
effective |= (v.pages[0].graphic.character_name != "" and
v.pages[0].move_type == 0)
# 航拍模式的情况下
elsif @mode == "A"
# 所有非空事件一律渲染
effective |= (v.pages[0].graphic.character_name != "")
end
# 筛选
effective
end
# 纯地图模式的情况下,直接按格快速渲染
return direct_paint if @mode == "M"
# 分层渲染底图
unless ulds
# 渲染没有优先级的图块
for k in 0...3
for j in 0...@height
for i in 0...@width
# 取得图块
tile_id = @map_data.data[i, j, k]
# 优先级为0的情况下
if tile_id > 0 and @tileset.priorities[tile_id] == 0
paint(i, j, tile_id)
end
end
end
# 每层汇报进度
Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id),
sprintf("渲染下层...%d%%", (k + 1) * 33))
end
# 渲染不在最前显示的图块事件
@effect_events.each do |f|
e = f[1]; g = e.pages[0].graphic
if g.tile_id > 0 and not e.pages[0].always_on_top
paint(e.x, e.y, g.tile_id, g.character_hue, g.opacity, g.blend_type)
end
end
# 分层模式的情况下,渲染结束
return if @mode == "U"
end
# 分层渲染顶图
# 计算剩余所有图块的 Z 坐标
z_indexes = {}
for k in 0...3
for j in 0...@height
for i in 0...@width
# 取得图块
tile_id = @map_data.data[i, j, k]
# 优先级不为0的情况下
if tile_id > 0 and @tileset.priorities[tile_id] > 0
z = (@tileset.priorities[tile_id] + j) * 32 + 32
z_indexes[z] = (z_indexes[z] || []).push([i, j, tile_id])
end
end
end
end
# 计算所有需要渲染的事件的 Z 坐标
@effect_events.each do |f|
e = f[1]; g = e.pages[0].graphic
# 事件的 Z 坐标
z = e.pages[0].always_on_top ? 32768 : e.y * 32 + 32
# 是普通事件的情况下
if g.tile_id == 0 or e.pages[0].always_on_top
z_indexes[z] = (z_indexes[z] || []).push([e.x, e.y, g])
end
end
# 按 Z 坐标开始绘制
l = n = z_indexes.keys.size
z_indexes.keys.sort.each do |k|
v = z_indexes[k]
while not v.empty?
tile = v.shift
x = tile[0]; y = tile[1]; g = tile[2]
# 如果此处是图块
if g.is_a?(Numeric)
paint(x, y, g)
# 如果此处是事件
elsif g.tile_id > 0
paint(x, y, g.tile_id, g.character_hue, g.opacity, g.blend_type)
else
paint_character(x, y, g)
end
end
n -= 1
# 已绘制20层的情况下,汇报进度
if n % 20 == 0
Scene_Reporter.update("", sprintf("渲染上层...%d%%",(l - n) * 100 / l))
end
end
end
#--------------------------------------------------------------------------
# ● 快速逐格渲染(M模式用)
#--------------------------------------------------------------------------
def direct_paint
# 变换有效事件列表
events = @effect_events.inject({}) do |s, f|
e = f[1]
s[[e.x, e.y]] = [e.pages[0].graphic, e.pages[0].always_on_top]
s
end
# 逐格绘制
for j in 0...@height
for i in 0...@width
# 获得此处的三层图块
tiles = [@map_data.data[i, j, 0],
@map_data.data[i, j, 1], @map_data.data[i, j, 2]]
# 获得此处三层图块的 Z 坐标
z_indexes = [@tileset.priorities[tiles[0]] * 32,
@tileset.priorities[tiles[1]] * 32 + 1,
@tileset.priorities[tiles[2]] * 32 + 2]
# 如果此处有事件,压入图块数据
if events.has_key?([i, j])
tiles.push(events[[i, j]][0].tile_id)
z_indexes.push(events[[i, j]][1] ? 999 : 3)
end
# 从最小值 Z 坐标开始绘制
while tiles.size > 0
z_index = z_indexes.min
index = z_indexes.index(z_index)
tile_id = tiles[index]
# 图块是事件的情况下,按事件图块的合成方式绘成
if z_index == 3 or z_index == 999
opacity = events[[i, j]][0].opacity
hue = events[[i, j]][0].character_hue
blend_type = events[[i, j]][0].blend_type
else
# 基本绘成
hue = blend_type = 0
opacity = 255
end
paint(i, j, tile_id, hue, opacity, blend_type) if tile_id > 0
tiles.delete_at(index)
z_indexes.delete_at(index)
end
end
# 每绘制 20 行汇报一次进度
if j % 20 == 0 or j == @height - 1
Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id),
sprintf("渲染地图...%d%%", (j + 1) * 100 / @height))
end
end
end
#--------------------------------------------------------------------------
# ● 绘制格子
# x, y: 地图的坐标
# tile_id: 元件 ID
# hue_change: 色相
# opacity: 不透明度
# blend_type: 合成方式 (0: 普通、1: 加法、2: 减法)
#--------------------------------------------------------------------------
def paint(x, y, tile_id, hue_change = 0, opacity = 255, blend_type = 0)
# 透明的图块不需要绘制
return if opacity == 0
# 绘制的原点
ox = x * 32 / @scale
oy = y * 32 / @scale
# 是普通元件的情况下
if tile_id >= 384
# 取得源位图
if hue_change != 0
(src = @tile_bitmap.clone).hue_change(hue)
else
src = @tile_bitmap
end
# 传送矩形
tile_id -= 384
src_rect = Rect.new((tile_id % 8) * 32, (tile_id / 8) * 32, 32, 32)
# 绘制合成
if blend_type == 0
if @scale == 1
@output_bitmap.blt(ox, oy, src, src_rect, opacity)
else
@output_bitmap.stretch_blt(Rect.new(ox, oy,
32 / @scale, 32 / @scale), src, rect, opacity)
end
else
@output_bitmap.blend_blt(Rect.new(ox, oy,
32 / @scale, 32 / @scale), src, rect, opacity, blend_type)
end
# 色相有差异的情况下要释放
src.dispose if hue_change != 0
# 不是普通元件的情况下(即自动元件)
else
# 获得自动元件的展开样式
autotile = @autotiles[tile_id / 48 - 1]
tile_form = AUTOTILE_EXPAND[tile_id % 48]
tile_lu = tile_form & 0xff
tile_ru = (tile_form & 0xff00) >> 8
tile_ld = (tile_form & 0xff0000) >> 16
tile_rd = (tile_form & 0xff000000) >> 24
# 缩放比为1的情况下,直接拷贝原件
if @scale == 1
@output_bitmap.blt(ox, oy, autotile, auto_rect(tile_lu), 255)
@output_bitmap.blt(ox + 16, oy, autotile, auto_rect(tile_ru), 255)
@output_bitmap.blt(ox, oy + 16, autotile, auto_rect(tile_ld), 255)
@output_bitmap.blt(ox + 16, oy + 16, autotile, auto_rect(tile_rd), 255)
# 缩放比不为1的情况下
else
s = 32 / @scale
temp_bitmap = Bitmap.new(32, 32)
temp_bitmap.blt(0, 0, autotile, auto_rect(tile_lu), 255)
temp_bitmap.blt(16, 0, autotile, auto_rect(tile_ru), 255)
temp_bitmap.blt(0, 16, autotile, auto_rect(tile_ld), 255)
temp_bitmap.blt(16, 16, autotile, auto_rect(tile_rd), 255)
@output_bitmap.stretch_blt(Rect.new(ox, oy, s, s),
temp_bitmap, @tile_rect, 255)
temp_bitmap.dispose
end
end
end
#--------------------------------------------------------------------------
# ● 绘制事件
# x, y: 地图的坐标
# g: 事件的图像(RPG::Event::Graphic)
#--------------------------------------------------------------------------
def paint_character(x, y, g)
# 透明的角色不需要绘制
return if g.opacity == 0
# 绘制的原点
bitmap = RPG::Cache.character(g.character_name, g.character_hue)
rect = char_rect(bitmap.width, bitmap.height, g.direction, g.pattern)
ox = (x * 32 - rect.width / 2 + 16) / @scale
oy = (y * 32 - rect.height + 32) / @scale
w = rect.width / @scale
h = rect.height / @scale
# 普通叠加的情况下,传送位图
if g.blend_type == 0
if @scale == 1
@output_bitmap.blt(ox, oy, bitmap, rect, g.opacity)
else
@output_bitmap.stretch_blt(Rect.new(ox, oy, w, h), bitmap, rect,
g.opacity)
end
else
@output_bitmap.blend_blt(Rect.new(ox, oy, w, h), bitmap, rect,
g.opacity, g.blend_type)
end
end
#--------------------------------------------------------------------------
# ● 事件的传送矩形
# width, height: 事件的位图宽高
# direction: 事件的朝向
# pattern: 事件的模式
#--------------------------------------------------------------------------
def char_rect(width, height, direction, pattern)
Rect.new(pattern * width / 4, (direction - 2) * height / 8,
width / 4, height / 4)
end
#--------------------------------------------------------------------------
# ● 自动元件的传送矩形
# region: 自动元件的展开方式(0-47)
#--------------------------------------------------------------------------
def auto_rect(region)
Rect.new((region % 6) * 16, (region / 6) * 16, 16, 16)
end
#--------------------------------------------------------------------------
# ● 连续截图
# range: 截图的地图ID列表
#--------------------------------------------------------------------------
def snaps(range)
Scene_Reporter.update("准备就绪")
if range.is_a?(Range) or range.is_a?(Array)
range.each do |i|
snap(i)
end
end
Scene_Reporter.close("完成,按B或C键继续")
end
#--------------------------------------------------------------------------
# ● 全部截图
#--------------------------------------------------------------------------
def snap_all
snaps(1..999)
end
end
ms = Map_Snapshot.new
ms.set_scale(1)
ms.set_mode("T")
ms.snap_all
exit
运行时截图:
截图样例:
|
评分
-
查看全部评分
|