查看: 58|回复: 0

[转载发布] 地图截图工具v1.3(猫儿的RMXP工具包第九弹)更新!

[复制链接]
  • TA的每日心情
    开心
    4 天前
  • 签到天数: 33 天

    连续签到: 1 天

    [LV.5]常住居民I

    2022

    主题

    32

    回帖

    7144

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5074
    OK点
    16
    积分
    7144
    发表于 同元一千年八月七日(秋) | 显示全部楼层 |阅读模式
    好像看到有人写过,但是为了给地图截个图自写一个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分多一点点。

    RUBY 代码
    1. #==============================================================================
    2. # ■ Map_Snapshot 1.3 (Build 171106)
    3. #------------------------------------------------------------------------------
    4. #  地图截图工具 by SailCat @ Project1
    5. #   该程序能将地图转换为PNG图片格式,包括三层图块和用图块ID绘制的事件,遮挡正确。
    6. #   使用方法:
    7. #   1. 插入本脚本到Game_Temp(不是Main)之前。
    8. #   2. 在插入脚本的下方,输入代码:
    9. #      ms = Map_Snapshot.new
    10. #      ms.set_scale(8) # 将地图缩小8倍,可以设定的值有1、2、4、8,默认为1
    11. #      ms.set_mode("U") # 设置输出模式为 ULDS分层模式
    12. #        支持的模式有"M"普通地图、"U"ULDS分层模式、"T"攻略模式、"A"航拍模式
    13. #        M模式:默认的模式、渲染F5、F6、F7层的全部和F8层的地图元件事件
    14. #        U模式:内容同M模式,但将一张地图渲染成主角上层和主角下层的两张截图
    15. #        T模式:在M模式的基础上,再加上不移动的事件,事件取第1页、初始位置
    16. #        A模式:在M模式的基础上,再加上所有的非空事件,事件取第1页、初始位置
    17. #        注:使用U模式会将地图放大率强制设为1:1
    18. #      ms.snap(6) # 转换Map006到图片
    19. #      ms.snaps(1..19) # 转换Map001到Map019到图片
    20. #      ms.snaps([1, 3, 7, 15]) # 转换Map001, Map003, Map007, Map015到图片
    21. #      ms.snap_all # 转换工程中所有地图到图片
    22. #      exit # 转换工程后退出
    23. #   3. 注释掉700行以下的内容可以屏蔽此工具,正常测试游戏。
    24. #   4. 该工具不修改工程内含文件,故执行完后不需要退出重新打开工程。
    25. #==============================================================================
    26. #==============================================================================
    27. # ■ Scene_Reporter
    28. #------------------------------------------------------------------------------
    29. #  通用工具处理进度显示模块。
    30. #==============================================================================
    31. module Scene_Reporter
    32.   @sprite = nil
    33.   @message = ""
    34.   @value = ""
    35.   #--------------------------------------------------------------------------
    36.   # ● 更新显示
    37.   #     message: 主要信息(滚屏)
    38.   #     value: 次要信息(不滚屏)
    39.   #--------------------------------------------------------------------------  
    40.   defself.update(message = "", value = "")
    41.     # 初期化精灵
    42.     if@sprite == nil
    43.       @sprite = Sprite.new
    44.       @sprite.bitmap = Bitmap.new(640, 480)
    45.       @sprite.bitmap.font.name = "楷体"
    46.       @sprite.bitmap.font.size = 20
    47.       @start = Time.now
    48.       @elapse = -1
    49.     end
    50.     # 信息和所显信息完全相同的情况下,直接返回
    51.     returnif(message == ""or@message == message)and@value == value
    52.     # 主信息不相同的情况下,滚屏
    53.     if message != ""and@message != message
    54.       @sprite.bitmap.blt(0, 0, @sprite.bitmap, Rect.new(0, 32, 640, 448))
    55.       @message = message
    56.       @elapse = 0
    57.     end
    58.     # 显示已用时间
    59.     elapse = Integer(Time.now - @start)
    60.     if@elapse < elapse
    61.       @elapse = elapse
    62.       min = @elapse / 60
    63.       sec = @elapse % 60
    64.       @sprite.bitmap.fill_rect(580, 0, 60, 32, Color.new(0, 0, 0))
    65.       @sprite.bitmap.draw_text(580, 0, 60, 32, sprintf("%2d:%02d", min, sec))
    66.     end
    67.     # 显示信息
    68.     @sprite.bitmap.fill_rect(0, 448, 640, 32, Color.new(0, 0, 0))
    69.     @sprite.bitmap.draw_text(0, 448, 640, 32, @message + value)
    70.     @value = value
    71.     # 更新画面
    72.     Graphics.update
    73.   end
    74.   #--------------------------------------------------------------------------
    75.   # ● 结束处理
    76.   #     message: 最后的信息
    77.   #--------------------------------------------------------------------------  
    78.   defself.close(message)
    79.     # 更新最后的信息
    80.     Scene_Reporter.update(message)
    81.     # 等待按键结束
    82.     loopdo
    83.       Graphics.update
    84.       Input.update
    85.       # 按下 C 键或 B 键的情况下
    86.       if Input.trigger?(Input::C)or Input.trigger?(Input::B)
    87.         break
    88.       end
    89.     end
    90.     # 释放精灵
    91.     if@sprite != nil
    92.       @sprite.bitmap.dispose
    93.       @sprite.dispose
    94.     end
    95.   end
    96. end
    97. #==============================================================================
    98. # ■ PNG
    99. #------------------------------------------------------------------------------
    100. #    PNG文件输出模块 by SailCat
    101. #    鸣谢:SixRC(取内存地址相关代码)
    102. #    用法:bitmap.output_png(filename)
    103. #     filename: 输出的文件名,可含路径
    104. #==============================================================================
    105. module PNG
    106.   #--------------------------------------------------------------------------
    107.   # ● API 声明
    108.   #--------------------------------------------------------------------------  
    109.   CopyMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
    110.   CopyMemory_ii = Win32API.new('kernel32', 'RtlMoveMemory', 'iii', 'i')
    111.   CopyMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
    112.   CallWindowProc_p = Win32API.new('user32.dll','CallWindowProc','pppii','i')
    113.   CallWindowProc_i = Win32API.new('user32.dll','CallWindowProc','ppiii','i')
    114.   #--------------------------------------------------------------------------
    115.   # ● API 调用代码
    116.   #--------------------------------------------------------------------------  
    117.   RGBAConvert = [
    118.     0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x33, 0xC9,
    119.     0xEB, 0x0D, 0x8B, 0x10, 0x0F, 0xCA, 0xC1, 0xCA,
    120.     0x08, 0x89, 0x10, 0x41, 0x83, 0xC0, 0x04, 0x3B,
    121.     0x4D, 0x0C, 0x72, 0xEE, 0xC9, 0xC2, 0x10, 0x00].pack('C*')
    122.   GetAddress = [
    123.     0x8B, 0x74, 0x24, 0x08, 0x8B, 0x36, 0x8B, 0x76,
    124.     0x08, 0x8B, 0x76, 0x10, 0x8B, 0x7C, 0x24, 0x04,
    125.     0x89, 0x37, 0xC2, 0x10, 0x00].pack("C*")
    126.   #--------------------------------------------------------------------------
    127.   # ● PNG 常量
    128.   #--------------------------------------------------------------------------  
    129.   PNG_HEADER = "\211\120\116\107\015\012\032\012\000\000\000\015"
    130.   PNG_IHDR_HEAD = "\111\110\104\122"
    131.   PNG_IHDR_TAIL = "\010\006\000\000\000"
    132.   PNG_IEND_CHUNK = "\000\000\000\000\111\105\116\104\256\102\140\202"
    133.   #--------------------------------------------------------------------------
    134.   # ● 生成 PNG 文件情报头数据块(IHDR)
    135.   #--------------------------------------------------------------------------  
    136.   def make_png_ihdr
    137.     data = PNG_IHDR_HEAD + [width, height].pack("N*") + PNG_IHDR_TAIL
    138.     return data + [Zlib.crc32(data)].pack("N")
    139.   end
    140.   #--------------------------------------------------------------------------
    141.   # ● 保存 PNG 文件
    142.   #     filename: 保存的文件名
    143.   #--------------------------------------------------------------------------  
    144.   def output_png(filename)
    145.     # 检查并建立路径
    146.     dir = filename.split("/")
    147.     for i in0...dir.size - 1
    148.       unless dir == "."
    149.         add_dir = dir[0..i].join("/")
    150.         Dir.mkdir(add_dir)rescuenil
    151.       end
    152.     end
    153.     # 依次写入 PNG 文件内容
    154.     file = File.open(filename,"wb")
    155.     file.write(PNG_HEADER)
    156.     file.write(make_png_ihdr)
    157.     file.write(make_png_idat)
    158.     file.write(PNG_IEND_CHUNK)
    159.     file.close
    160.     Scene_Reporter.update("", "完成")
    161.   end
    162.   #--------------------------------------------------------------------------
    163.   # ● 使用临时文件生成 PNG 图像数据(IDAT)
    164.   #--------------------------------------------------------------------------  
    165.   def make_png_idat
    166.     # 数据头
    167.     header = "IDAT"
    168.     # 输出图像信息为临时文件并获得校验码
    169.     adler = [make_data_file].pack("N")
    170.     # 读取临时文件
    171.     data = "\170\332"
    172.     fsize = File.size("temp.gz")
    173.     File.open("temp.gz", "rb")do |f|
    174.       f.pos = 10
    175.       data.concat(f.read(fsize - 18))
    176.       data.concat(adler)
    177.     end
    178.     # 删除临时文件
    179.     File.delete("temp.gz")
    180.     # 附加校验码
    181.     crc = [Zlib.crc32(header + data)].pack("N")
    182.     size = [data.length].pack("N")
    183.     # 返回数据
    184.     return size + header + data + crc
    185.   end
    186.   #--------------------------------------------------------------------------
    187.   # ● 将内存数据转储为文件,并返回adler32校验值
    188.   #--------------------------------------------------------------------------  
    189.   def make_data_file
    190.     # 建立缓存
    191.     cache = "\000" * 1
    192.     # 保存缓存原有结构信息
    193.     cache_info = [cache.size].pack("L")+ [cache].pack("p")
    194.     cache_len = cache.id * 2 + 8; cache_addr = cache_len + 4
    195.     # 将缓存的指针覆盖使之指向 Bitmap 的图像数据
    196.     byte_size = 4 * width * height
    197.     bitmap_info = [byte_size].pack("L") + [address].pack("L")
    198.     CopyMemory_ip.call(cache_len, bitmap_info, 8)
    199.     # 进度汇报线程
    200.     t = Thread.newdo
    201.       loopdo; sleep(0.5); Scene_Reporter.update("", "转换格式..."); end
    202.     end
    203.     # BGRA 转 RGBA
    204.     CallWindowProc_p.call(RGBAConvert, cache, width * height, 0, 0)
    205.     # 结束进度汇报
    206.     Thread.kill(t)
    207.     # 准备写入文件
    208.     x = 4 * width; y = [address + byte_size]; null = "\000"
    209.     # adler32 校验码初期化
    210.     adler = Zlib.adler32
    211.     # 将缓存的大小改为单行位图
    212.     CopyMemory_ip.call(cache_len, [x].pack("L"), 4)
    213.     # 打开临时文件
    214.     Zlib::GzipWriter.open("temp.gz", 8)do |gz|
    215.       # 进度汇报线程
    216.       t = Thread.newdo
    217.         loopdo
    218.           sleep(0.5)
    219.           Scene_Reporter.update("", sprintf("压缩图片...%d%%",
    220.             (byte_size - y[0] + @address) * 100 / byte_size))
    221.         end
    222.       end
    223.       # 逐行上移
    224.       while y[0] > @address
    225.         y[0] -= x
    226.         # 更改缓存指针
    227.         CopyMemory_ip.call(cache_addr, y.pack("L"), 4)
    228.         # 写入文件数据
    229.         gz.write(null)
    230.         adler = Zlib.adler32(null, adler)
    231.         gz.write(cache)
    232.         adler = Zlib.adler32(cache, adler)
    233.       end
    234.       # 结束进度汇报
    235.       Thread.kill(t)
    236.       # 关闭临时文件
    237.       gz.close
    238.     end
    239.     # 恢复指针原始结构信息以便释放
    240.     CopyMemory_ip.call(cache_len, cache_info, 8)
    241.     # 返回校验码
    242.     return adler
    243.   end
    244.   #--------------------------------------------------------------------------
    245.   # ● 位图的数据内存地址
    246.   #--------------------------------------------------------------------------  
    247.   def address
    248.     if@address == nil
    249.       buffer = "xxxx"
    250.       CallWindowProc_i.call(GetAddress, buffer, object_id * 2 + 16, 0, 0)
    251.       @address = buffer.unpack("L")[0]
    252.     end
    253.     return@address
    254.   end
    255. end
    256. #==============================================================================
    257. # ■ Bitmap
    258. #------------------------------------------------------------------------------
    259. #  内部位图类
    260. #==============================================================================
    261. class Bitmap
    262.   #--------------------------------------------------------------------------
    263.   # ● 导入 PNG 模块
    264.   #--------------------------------------------------------------------------  
    265.   include PNG
    266.   #--------------------------------------------------------------------------
    267.   # ● 合成
    268.   #     rect: 合成的矩形
    269.   #     src_bitmap: 合成的位图
    270.   #     src_rect: 合成位图的传送元矩形
    271.   #     opacity: 不透明度
    272.   #     blend_type: 合成方式(1: 加法、2: 减法)
    273.   #--------------------------------------------------------------------------  
    274.   def blend_blt(rect, src_bitmap, src_rect, opacity, blend_type)
    275.     # 纯透明的情况下 不合成
    276.     returnif opacity == 0
    277.     # 建立临时位图
    278.     temp_bitmap = Bitmap.new(rect.width, rect.height)
    279.     # 将源位图合成到临时位图,考虑缩放
    280.     if rect.width != src_rect.widthor rect.height != src_rect.height
    281.       temp_bitmap.stretch_blt(temp_bitmap.rect, src_bitmap, src_rect, opacity)
    282.     else
    283.       temp_bitmap.blt(0, 0, src_bitmap, src_rect, opacity)
    284.     end
    285.     # 逐点合成
    286.     for i in0...rect.width
    287.       for j in0...rect.height
    288.         # 取色
    289.         c1 = self.get_pixel(rect.x + i, rect.y + j)
    290.         c2 = temp_bitmap.get_pixel(i, j)
    291.         # 源位图此点无色的情况下,继续
    292.         nextif c2.alpha == 0
    293.         # 加法
    294.         if blend_type == 1
    295.           c1.red += c2.red * c2.alpha / 255 * opacity / 255
    296.           c1.green += c2.green * c2.alpha / 255 * opacity / 255
    297.           c1.blue += c2.blue * c2.alpha / 255 * opacity / 255
    298.         # 减法
    299.         else
    300.           c1.red = [0, c1.red - c2.red * c2.alpha / 255 * opacity / 255].max
    301.           c1.green = [0, c1.green - c2.green * c2.alpha / 255 * opacity / 255].max
    302.           c1.blue = [0, c1.blue - c2.blue * c2.alpha / 255 * opacity / 255].max
    303.         end
    304.         # 设色
    305.         self.set_pixel(rect.x + i, rect.y + j, c1)
    306.       end
    307.     end
    308.     # 释放临时位图
    309.     temp_bitmap.dispose
    310.   end
    311. end
    312. #==============================================================================
    313. # ■ Map_Snapshot
    314. #------------------------------------------------------------------------------
    315. #    地图截图渲染引擎
    316. #==============================================================================
    317. class Map_Snapshot
    318.   #--------------------------------------------------------------------------
    319.   # ● 常量
    320.   #--------------------------------------------------------------------------  
    321.   AUTOTILE_EXPAND = [
    322.     555752218, 555752196, 555746586, 555746564, 186653466, 186653444,
    323.     186647834, 186647812, 554310426, 554310404, 554304794, 554304772,
    324.     185211674, 185211652, 185206042, 185206020, 522066200, 522061080,
    325.     186521880, 186516760, 353636110, 185863950, 352980750, 185208590,
    326.     589438236, 587865372, 589438212, 587865348, 757868326, 757868292,
    327.     757859622, 757859588, 589176088, 757862158, 319950092, 185732364,
    328.     387322128, 386535696, 791554344, 791554308, 724182308, 724174116,
    329.     387059980, 724176140, 791292196, 791548176, 791286028, 117833984
    330.   ]# 自动元件的展开方式
    331.   #--------------------------------------------------------------------------
    332.   # ● 初期化
    333.   #--------------------------------------------------------------------------  
    334.   def initialize
    335.     @tilesets = load_data("Data/Tilesets.rxdata")
    336.     @mapnames = load_data("Data/MapInfos.rxdata")
    337.     @mapnames.each{|k, v| @mapnames[k] = v.name.gsub(/[\\\/:*?|]/,"_")}
    338.     @map_data = nil
    339.     @output_bitmap = nil
    340.     @tile_bitmap = nil
    341.     @autotiles = [nil, nil, nil, nil, nil, nil, nil]
    342.     @width = 0
    343.     @height = 0
    344.     @map_id = 0
    345.     @scale = 1
    346.     @mode = "M"
    347.   end
    348.   #--------------------------------------------------------------------------
    349.   # ● 设置缩放
    350.   #     scale: 缩放比(1/1、1/2、1/4或1/8)
    351.   #--------------------------------------------------------------------------  
    352.   def set_scale(scale)
    353.     @scale = scale if[1, 2, 4, 8].include?(scale)
    354.   end
    355.   #--------------------------------------------------------------------------
    356.   # ● 设置渲染模式
    357.   #     mode: 渲染模式(M、U、A、T)
    358.   #--------------------------------------------------------------------------  
    359.   def set_mode(mode)
    360.     @mode = mode if["M", "U", "A", "T"].include?(mode)
    361.   end
    362.   #--------------------------------------------------------------------------
    363.   # ● 地图截图
    364.   #     map_id: 地图ID
    365.   #--------------------------------------------------------------------------  
    366.   def snap(map_id)
    367.     # 如果是ULDS模式,放大率强制为1
    368.     set_scale(1)if@mode == "U"
    369.     # 加载地图数据
    370.     map_name = sprintf("Data/Map%03d.rxdata", map_id)
    371.     ifFileTest.exist?(map_name)
    372.       @map_id = map_id
    373.       @map_data = load_data(map_name)
    374.       @width = @map_data.width
    375.       @height = @map_data.height
    376.       @tileset = @tilesets[@map_data.tileset_id]
    377.       @tile_bitmap = RPG::Cache.tileset(@tileset.tileset_name)
    378.       @tile_rect = Rect.new(0, 0, 32, 32)
    379.       # 用于输出的位图
    380.       @output_bitmap = Bitmap.new(@width * 32 / @scale, @height * 32 / @scale)
    381.       for i in0..6
    382.         @autotiles[i] = RPG::Cache.autotile(@tileset.autotile_names[i])
    383.       end
    384.       @auto_stretch = {}
    385.       # 渲染
    386.       snapshot
    387.       # 输出截图
    388.       filename = sprintf("MapSnapshots/%03d-%s.png", map_id, @mapnames[map_id])
    389.       @output_bitmap.output_png(filename)
    390.       # 如果是ULDS模式,渲染第二张图
    391.       if@mode == "U"
    392.         @output_bitmap.clear
    393.         snapshot(true)
    394.         f2 = sprintf("MapSnapshots/%03d-%s[U].png", map_id, @mapnames[map_id])
    395.         @output_bitmap.output_png(f2)
    396.       end
    397.       # 释放位图
    398.       @output_bitmap.dispose
    399.       @auto_stretch.each_value{|v| v.dispose}
    400.       for i in0..6
    401.         @autotiles[i].dispose
    402.       end
    403.       @autotiles = [nil, nil, nil, nil, nil, nil, nil]
    404.       @tile_bitmap.dispose
    405.       @tile_bitmap = nil
    406.     end
    407.   end
    408.   #--------------------------------------------------------------------------
    409.   # ● 渲染地图
    410.   #     ulds: ULDS第二层渲染专用
    411.   #--------------------------------------------------------------------------  
    412.   def snapshot(ulds = false)
    413.     # 筛选需要渲染的事件集
    414.     @effect_events = @map_data.events.selectdo |k, v|
    415.       # 事件的地图元件有效的情况下,总是渲染
    416.       effective = (v.pages[0].graphic.tile_id > 0)
    417.       # 分层模式的情况下
    418.       if@mode == "U"
    419.         # 事件还需要满足优先级条件才渲染
    420.         effective &= (v.pages[0].always_on_top == ulds)
    421.       # 攻略模式的情况下
    422.       elsif@mode == "T"
    423.         # 事件不移动且朝向固定也需渲染
    424.         effective |= (v.pages[0].graphic.character_name != ""and
    425.           v.pages[0].move_type == 0)
    426.       # 航拍模式的情况下
    427.       elsif@mode == "A"
    428.         # 所有非空事件一律渲染
    429.         effective |= (v.pages[0].graphic.character_name != "")
    430.       end
    431.       # 筛选
    432.       effective
    433.     end
    434.     # 纯地图模式的情况下,直接按格快速渲染
    435.     return direct_paint if@mode == "M"
    436.     # 分层渲染底图
    437.     unless ulds
    438.       # 渲染没有优先级的图块
    439.       for k in0...3
    440.         for j in0...@height
    441.           for i in0...@width
    442.             # 取得图块
    443.             tile_id = @map_data.data[i, j, k]
    444.             # 优先级为0的情况下
    445.             if tile_id > 0and@tileset.priorities[tile_id] == 0
    446.               paint(i, j, tile_id)
    447.             end
    448.           end
    449.         end
    450.         # 每层汇报进度
    451.         Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id),
    452.           sprintf("渲染下层...%d%%", (k + 1) * 33))
    453.       end
    454.       # 渲染不在最前显示的图块事件
    455.       @effect_events.eachdo |f|
    456.         e = f[1]; g = e.pages[0].graphic
    457.         if g.tile_id > 0andnot e.pages[0].always_on_top
    458.           paint(e.x, e.y, g.tile_id, g.character_hue, g.opacity, g.blend_type)
    459.         end
    460.       end
    461.       # 分层模式的情况下,渲染结束
    462.       returnif@mode == "U"
    463.     end
    464.     # 分层渲染顶图
    465.     # 计算剩余所有图块的 Z 坐标
    466.     z_indexes = {}
    467.     for k in0...3
    468.       for j in0...@height
    469.         for i in0...@width
    470.           # 取得图块
    471.           tile_id = @map_data.data[i, j, k]
    472.           # 优先级不为0的情况下
    473.           if tile_id > 0and@tileset.priorities[tile_id] > 0
    474.             z = (@tileset.priorities[tile_id] + j) * 32 + 32
    475.             z_indexes[z] = (z_indexes[z] || []).push([i, j, tile_id])
    476.           end
    477.         end
    478.       end
    479.     end
    480.     # 计算所有需要渲染的事件的 Z 坐标
    481.     @effect_events.eachdo |f|
    482.       e = f[1]; g = e.pages[0].graphic
    483.       # 事件的 Z 坐标
    484.       z = e.pages[0].always_on_top ? 32768 : e.y * 32 + 32
    485.       # 是普通事件的情况下
    486.       if g.tile_id == 0or e.pages[0].always_on_top
    487.         z_indexes[z] = (z_indexes[z] || []).push([e.x, e.y, g])
    488.       end
    489.     end
    490.     # 按 Z 坐标开始绘制
    491.     l = n = z_indexes.keys.size
    492.     z_indexes.keys.sort.eachdo |k|
    493.       v = z_indexes[k]
    494.       whilenot v.empty?
    495.         tile = v.shift
    496.         x = tile[0]; y = tile[1]; g = tile[2]
    497.         # 如果此处是图块
    498.         if g.is_a?(Numeric)
    499.           paint(x, y, g)
    500.         # 如果此处是事件
    501.         elsif g.tile_id > 0
    502.           paint(x, y, g.tile_id, g.character_hue, g.opacity, g.blend_type)
    503.         else
    504.           paint_character(x, y, g)
    505.         end
    506.       end
    507.       n -= 1
    508.       # 已绘制20层的情况下,汇报进度
    509.       if n % 20 == 0
    510.         Scene_Reporter.update("", sprintf("渲染上层...%d%%",(l - n) * 100 / l))
    511.       end
    512.     end
    513.   end
    514.   #--------------------------------------------------------------------------
    515.   # ● 快速逐格渲染(M模式用)
    516.   #--------------------------------------------------------------------------  
    517.   def direct_paint
    518.     # 变换有效事件列表
    519.     events = @effect_events.inject({})do |s, f|
    520.       e = f[1]
    521.       s[[e.x, e.y]] = [e.pages[0].graphic, e.pages[0].always_on_top]
    522.       s
    523.     end
    524.     # 逐格绘制
    525.     for j in0...@height
    526.       for i in0...@width
    527.         # 获得此处的三层图块
    528.         tiles = [@map_data.data[i, j, 0],
    529.           @map_data.data[i, j, 1], @map_data.data[i, j, 2]]
    530.         # 获得此处三层图块的 Z 坐标
    531.         z_indexes = [@tileset.priorities[tiles[0]] * 32,
    532.           @tileset.priorities[tiles[1]] * 32 + 1,
    533.           @tileset.priorities[tiles[2]] * 32 + 2]
    534.         # 如果此处有事件,压入图块数据
    535.         if events.has_key?([i, j])
    536.           tiles.push(events[[i, j]][0].tile_id)
    537.           z_indexes.push(events[[i, j]][1] ? 999 : 3)
    538.         end
    539.         # 从最小值 Z 坐标开始绘制
    540.         while tiles.size > 0
    541.           z_index = z_indexes.min
    542.           index = z_indexes.index(z_index)
    543.           tile_id = tiles[index]
    544.           # 图块是事件的情况下,按事件图块的合成方式绘成
    545.           if z_index == 3or z_index == 999
    546.             opacity = events[[i, j]][0].opacity
    547.             hue = events[[i, j]][0].character_hue
    548.             blend_type = events[[i, j]][0].blend_type
    549.           else
    550.             # 基本绘成
    551.             hue = blend_type = 0
    552.             opacity = 255
    553.           end
    554.           paint(i, j, tile_id, hue, opacity, blend_type)if tile_id > 0
    555.           tiles.delete_at(index)
    556.           z_indexes.delete_at(index)
    557.         end
    558.       end
    559.       # 每绘制 20 行汇报一次进度
    560.       if j % 20 == 0or j == @height - 1
    561.         Scene_Reporter.update(sprintf("正在生成截图Map%03d.png...", @map_id),
    562.         sprintf("渲染地图...%d%%", (j + 1) * 100 / @height))
    563.       end
    564.     end
    565.   end
    566.   #--------------------------------------------------------------------------
    567.   # ● 绘制格子
    568.   #     x, y: 地图的坐标
    569.   #     tile_id: 元件 ID
    570.   #     hue_change: 色相
    571.   #     opacity: 不透明度
    572.   #     blend_type: 合成方式 (0: 普通、1: 加法、2: 减法)
    573.   #--------------------------------------------------------------------------  
    574.   def paint(x, y, tile_id, hue_change = 0, opacity = 255, blend_type = 0)
    575.     # 透明的图块不需要绘制
    576.     returnif opacity == 0
    577.     # 绘制的原点
    578.     ox = x * 32 / @scale
    579.     oy = y * 32 / @scale
    580.     # 是普通元件的情况下
    581.     if tile_id >= 384
    582.       # 取得源位图
    583.       if hue_change != 0
    584.         (src = @tile_bitmap.clone).hue_change(hue)
    585.       else
    586.         src = @tile_bitmap
    587.       end
    588.       # 传送矩形
    589.       tile_id -= 384
    590.       src_rect = Rect.new((tile_id % 8) * 32, (tile_id / 8) * 32, 32, 32)
    591.       # 绘制合成
    592.       if blend_type == 0
    593.         if@scale == 1
    594.           @output_bitmap.blt(ox, oy, src, src_rect, opacity)
    595.         else
    596.           @output_bitmap.stretch_blt(Rect.new(ox, oy,
    597.             32 / @scale, 32 / @scale), src, rect, opacity)
    598.         end
    599.       else
    600.         @output_bitmap.blend_blt(Rect.new(ox, oy,
    601.           32 / @scale, 32 / @scale), src, rect, opacity, blend_type)
    602.       end
    603.       # 色相有差异的情况下要释放
    604.       src.disposeif hue_change != 0
    605.     # 不是普通元件的情况下(即自动元件)
    606.     else
    607.       # 获得自动元件的展开样式
    608.       autotile = @autotiles[tile_id / 48 - 1]
    609.       tile_form = AUTOTILE_EXPAND[tile_id % 48]
    610.       tile_lu = tile_form & 0xff
    611.       tile_ru = (tile_form & 0xff00) >> 8
    612.       tile_ld = (tile_form & 0xff0000) >> 16
    613.       tile_rd = (tile_form & 0xff000000) >> 24
    614.       # 缩放比为1的情况下,直接拷贝原件
    615.       if@scale == 1
    616.         @output_bitmap.blt(ox, oy, autotile, auto_rect(tile_lu), 255)
    617.         @output_bitmap.blt(ox + 16, oy, autotile, auto_rect(tile_ru), 255)
    618.         @output_bitmap.blt(ox, oy + 16, autotile, auto_rect(tile_ld), 255)
    619.         @output_bitmap.blt(ox + 16, oy + 16, autotile, auto_rect(tile_rd), 255)
    620.       # 缩放比不为1的情况下
    621.       else
    622.         s = 32 / @scale
    623.         temp_bitmap = Bitmap.new(32, 32)
    624.         temp_bitmap.blt(0, 0, autotile, auto_rect(tile_lu), 255)
    625.         temp_bitmap.blt(16, 0, autotile, auto_rect(tile_ru), 255)
    626.         temp_bitmap.blt(0, 16, autotile, auto_rect(tile_ld), 255)
    627.         temp_bitmap.blt(16, 16, autotile, auto_rect(tile_rd), 255)
    628.         @output_bitmap.stretch_blt(Rect.new(ox, oy, s, s),
    629.           temp_bitmap, @tile_rect, 255)
    630.         temp_bitmap.dispose
    631.       end
    632.     end
    633.   end
    634.   #--------------------------------------------------------------------------
    635.   # ● 绘制事件
    636.   #     x, y: 地图的坐标
    637.   #     g: 事件的图像(RPG::Event::Graphic)
    638.   #--------------------------------------------------------------------------  
    639.   def paint_character(x, y, g)
    640.     # 透明的角色不需要绘制
    641.     returnif g.opacity == 0
    642.     # 绘制的原点
    643.     bitmap = RPG::Cache.character(g.character_name, g.character_hue)
    644.     rect = char_rect(bitmap.width, bitmap.height, g.direction, g.pattern)
    645.     ox = (x * 32 - rect.width / 2 + 16) / @scale
    646.     oy = (y * 32 - rect.height + 32) / @scale
    647.     w = rect.width / @scale
    648.     h = rect.height / @scale
    649.     # 普通叠加的情况下,传送位图
    650.     if g.blend_type == 0
    651.       if@scale == 1
    652.         @output_bitmap.blt(ox, oy, bitmap, rect, g.opacity)
    653.       else
    654.         @output_bitmap.stretch_blt(Rect.new(ox, oy, w, h), bitmap, rect,
    655.           g.opacity)
    656.       end
    657.     else
    658.       @output_bitmap.blend_blt(Rect.new(ox, oy, w, h), bitmap, rect,
    659.         g.opacity, g.blend_type)
    660.     end
    661.   end
    662.   #--------------------------------------------------------------------------
    663.   # ● 事件的传送矩形
    664.   #     width, height: 事件的位图宽高
    665.   #     direction: 事件的朝向
    666.   #     pattern: 事件的模式
    667.   #--------------------------------------------------------------------------  
    668.   def char_rect(width, height, direction, pattern)
    669.     Rect.new(pattern * width / 4, (direction - 2) * height / 8,
    670.       width / 4, height / 4)
    671.   end
    672.   #--------------------------------------------------------------------------
    673.   # ● 自动元件的传送矩形
    674.   #     region: 自动元件的展开方式(0-47)
    675.   #--------------------------------------------------------------------------  
    676.   def auto_rect(region)
    677.     Rect.new((region % 6) * 16, (region / 6) * 16, 16, 16)
    678.   end
    679.   #--------------------------------------------------------------------------
    680.   # ● 连续截图
    681.   #     range: 截图的地图ID列表
    682.   #--------------------------------------------------------------------------  
    683.   def snaps(range)
    684.     Scene_Reporter.update("准备就绪")
    685.     if range.is_a?(Range)or range.is_a?(Array)
    686.       range.eachdo |i|
    687.         snap(i)
    688.       end
    689.     end
    690.     Scene_Reporter.close("完成,按B或C键继续")
    691.   end
    692.   #--------------------------------------------------------------------------
    693.   # ● 全部截图
    694.   #--------------------------------------------------------------------------  
    695.   def snap_all
    696.     snaps(1..999)
    697.   end
    698. end
    699. ms = Map_Snapshot.new
    700. ms.set_scale(1)
    701. ms.set_mode("T")
    702. ms.snap_all
    703. exit
    复制代码


    运行时截图:


    截图样例:






                本帖来自P1论坛作者89444640,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=403282  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    天天去同能,天天有童年!
    回复 论坛版权

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

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

    GMT+8, 2024-5-2 22:08 , Processed in 0.073805 second(s), 44 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表