查看: 6558|回复: 4

[原创发布] 【最终版】XP用菜单界面模糊地图

[复制链接]
梦石
0
星屑
76
在线时间
1379 小时
注册时间
2012-7-5
回帖
1643

开拓者

发表于 2014-7-31 14:24:46 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

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

×
本帖最后由 kuerlulu 于 2015-6-22 19:58 编辑

[fold=前版]
0.png
组合技说明(都是已有脚本):
  免dll截图 + 免dll(高斯)模糊算法 + 半透明窗口(主站已有) = XP用菜单界面模糊地图背景
个人修改:
  VX中, 生成菜单背景的方法照抄到XP
  半透明窗口原本的背景为地图, 修改成模糊的背景(连别名都没改我真是太懒了)

前版范例

Project∞.rar (189.16 KB, 下载次数: 216)
前版BUG说明:
[截图]功能为调用系统API, 原理是将屏幕指定区域的bmp内存传递给rm, 因此如果游戏窗口上方有什么东西的话也会被截进去, 比如360流量悬浮窗OeO
打开游戏菜单时第一次调用API, 此1秒内如果屏幕获取不到焦点(即不在桌面所有窗口的最上层)有一定几率触发异常, 截图矩形会始终为玩家屏幕左上角一块矩形区域

[/fold]
无bug最终版(整合兰触的xp用真截图)
(开袋即食)
[fold=代码如下]
[pre lang="ruby" file="MenuBack.txt"]#--------------------------------------------------------------------------
# ● 紫苏前辈的获取窗口句柄
#    部分细节已修改( by 晴兰 )
#--------------------------------------------------------------------------
module Kernel
  #--------------------------------------------------------------------------
  # ● 需要的 Windows API 函数
  #--------------------------------------------------------------------------
  GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", "LP", "L")
  GetWindow = Win32API.new("user32", "GetWindow", "LL", "L")
  GetClassName = Win32API.new("user32", "GetClassName", "LPL", "L")
  GetCurrentThreadId = Win32API.new("kernel32", "GetCurrentThreadId", "V", "L")
  GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", "V", "L")
  #--------------------------------------------------------------------------
  # ● 获取窗口句柄
  #--------------------------------------------------------------------------
  def hwnd
    # 获取调用线程(RM 的主线程)的进程标识
    threadID = GetCurrentThreadId.call
    # 获取 Z 次序中最靠前的窗口
    hWnd = GetWindow.call(GetForegroundWindow.call, 0)
    # 枚举所有窗口
    while hWnd != 0
      # 如果创建该窗口的线程标识匹配本线程标识
      if threadID == GetWindowThreadProcessId.call(hWnd, 0)
        # 分配一个 12 个字节的缓冲区
        className = " " * 12                         # ●
        # 获取该窗口的类名
        GetClassName.call(hWnd, className, 12)       # ●
        # 如果匹配 RGSS Player 则跳出循环
        break if className[0, 11] == "RGSS Player"
      end
      # 获取下一个窗口
      hWnd = GetWindow.call(hWnd, 2)
    end
    return hWnd
  end
end
HWND = hwnd

#--------------------------------------------------------------------------
# ● RMXP用 Graphics.snap_to_bitmap
#    就算窗口被遮盖或者显示不全也可以正常截图
#    附赠: Graphics.snap_to_clipboard
#          截图到剪贴板
# ● 作者:晴兰 @ rpg.blue
#    使用到紫苏前辈的获取窗口句柄脚本,其他部分为原创
#--------------------------------------------------------------------------
module SAFX
  module_function
  class ::Integer; def pack; self; end; def to_param; 'i'; end; def ord; self; end; end
  class ::String;def pack; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end
  def api(dll,func)
    lambda{|*args|
       Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
    }
  end
  def callproc(addr, type = :cdecl)
    stdcall = type == :stdcall
    raise "addr == 0 " if addr.pack == 0
    apicall = api('user32', 'CallWindowProcW')
    lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.pack].pack('CL')}.reverse.join+[0xb8, addr.pack, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}
  end
  LL  = api("kernel32", "LoadLibrary")
  GPA = api("kernel32", "GetProcAddress")
  def funcaddr(dll, func)
     x = GPA.call(LL.call(dll), func)
     x == 0 ? nil : x
  end
  def readmem(start, len)
    api('kernel32', 'RtlMoveMemory').call buf = "\0"*len, start, len
    buf
  end
  def writemem(start, len, value)
    api('kernel32', 'RtlMoveMemory').call start, value, [len, value.length].min
  end
end

class << Graphics
  SetWindowPos = SAFX.api("user32", "SetWindowPos")
  GetSystemMetrics = SAFX.api("user32", "GetSystemMetrics")
  CAPTION_HEIGHT = GetSystemMetrics.call(4)
  CX_FRAME, CY_FRAME = GetSystemMetrics.call(32), GetSystemMetrics.call(33)
  SIZE = {:width => 640, :height => 480}
  def resize_screen(width, height)
    SetWindowPos.call(HWND, 0, 0, 0,
      width + CX_FRAME - 2, height + CAPTION_HEIGHT + CY_FRAME - 1, 2)
    SIZE[:width], SIZE[:height] = width, height
  end
  def width
    SIZE[:width]
  end
  def height
    SIZE[:height]
  end
  def do_screen_stuff
    hwnd = self.hwnd
    src = SAFX.api('user32', 'GetDC').call(hwnd)
    memdc = SAFX.api('gdi32', 'CreateCompatibleDC').call(src)
    hb = SAFX.api('gdi32', 'CreateCompatibleBitmap').call(src, width, height)
    ho = SAFX.api('gdi32', 'SelectObject').call(memdc, hb)
    bp = SAFX.funcaddr("user32", "GetDC")
    ov = "\0"*4
    str = [0xb8, memdc, 0xc2, 0x04, 0x00].pack("CLC*") # magic, touch
    SAFX.api('Kernel32', 'VirtualProtect').call(bp, str.length, 0x40, ov)
    oldstr = SAFX.readmem(bp, str.length)
    SAFX.writemem bp, str.length, str
    SAFX.api('user32', 'UpdateWindow').call(hwnd)
    Graphics.update
    SAFX.writemem bp, str.length, oldstr
    yield hb
  ensure
    SAFX.api('user32', 'ReleaseDC').call(hwnd, src)
    hb = SAFX.api('gdi32', 'SelectObject').call(memdc, ho)
    SAFX.api('gdi32', 'DeleteObject').call(ho)
    SAFX.api('gdi32', 'DeleteDC').call(memdc)
  end
  def snap_to_bitmap
    bm = Bitmap.new(width, height)
    addr  = bm.object_id * 2
    addr, = SAFX.readmem(addr + 16, 4).unpack("L")
    addr, = SAFX.readmem(addr +  8, 4).unpack("L")
    addr, = SAFX.readmem(addr + 16, 4).unpack("L")
    do_screen_stuff do |hb|
      bits = "\0"*(width * height * 4)
      SAFX.api('gdi32', 'GetBitmapBits').call(hb, bits.length, bits)
      r = SAFX.api('kernel32', 'RtlMoveMemory')
      a = bits.pack
      stride = width * 4
      h = height
     (h-1).downto(0){|i|
        r.call addr + i * stride, a + (h - i - 1)*stride, stride
      }
      bm
    end
  end
  def snap_to_clipboard
    return false if SAFX.api('user32', 'OpenClipboard').call(hwnd) == 0
    do_screen_stuff do |hb|
      SAFX.api('user32', 'SetClipboardData').call(2, hb)
      SAFX.api('user32', 'CloseClipboard').call
      true
    end
  end
end

#==============================================================================
# ■ Bitmap
#------------------------------------------------------------------------------
#   位图的类。所谓位图即表示图像其本身。
#==============================================================================

class Bitmap
  def blur(str = 3, rect = Rect.new(0, 0, self.width, self.height))
    if str < 1
      str = 1
    elsif str > 5
      str = 5
    end
    for x in -str..str
      for y in -str..str
        next if x == 0 and y == 0
        self.blt(x + rect.x, y + rect.y, self, Rect.new(rect.x, rect.y, rect.width - x, rect.height - y), 10)
      end
    end
    return self
  end
end

#==============================================================================
# ■ Game_Temp
#------------------------------------------------------------------------------
#  在没有存档的情况下,处理临时数据的类。这个类的实例请参考
# $game_temp 。
#==============================================================================

class Game_Temp
  #--------------------------------------------------------------------------
  # ● 定义实例变量
  #--------------------------------------------------------------------------
  attr_accessor :background_bitmap        # 画面背景
  #--------------------------------------------------------------------------
  # ● 初始化对象
  #--------------------------------------------------------------------------
  alias ori_init initialize
  def initialize
    ori_init
    @background_bitmap = Bitmap.new(640, 480) # Graphics.snap_to_bitmap
  end
end

#==============================================================================
# ■ Scene_Map
#------------------------------------------------------------------------------
#  处理地图画面的类。
#==============================================================================

class Scene_Map
  #--------------------------------------------------------------------------
  # ● 调用菜单
  #--------------------------------------------------------------------------
  alias ori_call_menu call_menu
  def call_menu
    # 生成菜单画面背景
    $game_temp.background_bitmap.dispose
    $game_temp.background_bitmap = Graphics.snap_to_bitmap
    $game_temp.background_bitmap.blur
    # 继续原有处理
    ori_call_menu
  end
end

#==============================================================================
# ■ Window_Base
#==============================================================================
class Window_Base < Window
  alias xxx_initialize initialize
  def initialize(x, y, width, height)
    xxx_initialize(x, y, width, height)
    if $scene.is_a?(Scene_Menu) or
       $scene.is_a?(Scene_Item) or  
       $scene.is_a?(Scene_Skill) or  
       $scene.is_a?(Scene_Equip) or  
       $scene.is_a?(Scene_Status) or  
       $scene.is_a?(Scene_Save) or  
       $scene.is_a?(Scene_End)
      self.back_opacity = 160  #————这个数值可调,为透明程度
    end
  end
end
module XXX
  #--------------------------------------------------------------------------
  # ● 生成菜单画面背景
  #--------------------------------------------------------------------------
  def create_menu_background
    @menuback_sprite = Sprite.new
    @menuback_sprite.bitmap = $game_temp.background_bitmap
    @menuback_sprite.color.set(16, 16, 16, 64)
  end
  #--------------------------------------------------------------------------
  # ● 释放菜单画面背景
  #--------------------------------------------------------------------------
  def dispose_menu_background
    @menuback_sprite.dispose
  end
end
class Scene_Menu
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_Item
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_Skill
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_Equip
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_Status
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_Save
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
class Scene_End
  include XXX
  alias xxx_main main
  def main
    create_menu_background
    xxx_main
    dispose_menu_background
  end
end
#==============================================================================
# 本脚本来自 rm.66RPG.com,使用和转载请保留此信息
#==============================================================================
[/pre]
[/fold]

评分

参与人数 5星屑 +492 收起 理由
牛肉面 + 50 精品文章
断电 + 100 QAQ非常感谢提醒【感动
你最珍贵 + 60 精品文章
日月星辰 + 30 精品文章
弗雷德 + 252 好棒!等好久了

查看全部评分


  -fk: -azogi:

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-7-31 14:27:21 | 显示全部楼层
太触了……话说XP竟然没有blur……

点评

楼下补英语去?  发表于 2014-7-31 15:21
blur是啥 = =blue打错了?  发表于 2014-7-31 14:55
= =|||||||(´゚Д゚`)  发表于 2014-7-31 14:32
回复

使用道具 举报

万兽

梦石
0
星屑
602
在线时间
2271 小时
注册时间
2006-11-4
回帖
4701

贵宾

发表于 2014-7-31 15:01:11 | 显示全部楼层
好棒哦,以前俺也有求过XP的BLUR法。
等等,人家都不用RM了,你还发出来做什么?!
回复

使用道具 举报

故九江太守

梦石
0
星屑
314
在线时间
2158 小时
注册时间
2012-12-5
回帖
4323
发表于 2014-7-31 15:27:32 | 显示全部楼层
好用!
回复

使用道具 举报

梦石
0
星屑
487
在线时间
908 小时
注册时间
2009-10-12
回帖
1702
发表于 2014-7-31 15:47:24 | 显示全部楼层
首先当然是感谢大触!【【【.....xp原始菜单很丑啊有木有

然后。。我自己丧病多blur几次,,画面中本来的两个人。。。黑化了?= =
屏幕截图(160).png

点评

老师说:这些知识点书上不都原有么! 众学渣无语。。。感觉是这样的?嗯无论是不是触 能帮大家整合起来也是感谢了!  发表于 2014-7-31 15:57
不是触, 你没看到都是原有脚本么  发表于 2014-7-31 15:53

评分

参与人数 1星屑 +23 收起 理由
kuerlulu + 23 23333333

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部