Project1

标题: 解决脚本改分辨率潜在问题(欢迎进入讨论) [打印本页]

作者: 一箭烂YiJL    时间: 2011-4-10 15:12
标题: 解决脚本改分辨率潜在问题(欢迎进入讨论)
本帖最后由 一箭烂YiJL 于 2011-4-11 20:19 编辑

0.序
嗯~潜在问题,用Graphics.resize_screen这个函数来修改的游戏应该都会有。
(欢迎各位试一下会否出现此问题。)我在想着这个会是VX的bug?

虽然(画面)分辨率的确大了,但是窗体没大,所以看不清楚,
除此之外,还会令鼠标系统变得诡异。


1.楸出问题所在如果不会弄以上的,二楼提供了一个用脚本楸出问题的办法。

正常的(请按一下图片放大至1比1后才做比较):

如果不相信者可以自己开新工程试,或者对照上图的窗口边的大小。
这种情况会发生在忙于弄其他窗口的玩家身上。
虽然分辨率的确大了,但是窗体没大,所以看不清楚,看不仔细。
除此之外,鼠标系统这种平面视觉都会很诡异!!!。

2.解决办法
先要统一使用紫苏大人的精准获取窗口句柄,请复制其中的脚本。然后才能用:
A.直接的方法——在改分辨率前强制最大化:

  1. $window_width  = 640      # 设置的长度
  2. $window_height = 480      # 设置的高度

  3. hWnd = get_hWnd
  4. ShowWindow = Win32API.new("user32", "ShowWindow", "ll", "l")
  5. ShowWindow.call(hWnd, 9)
  6. Graphics.resize_screen($window_width, $window_height)
复制代码
这个方法可能会有碍游戏给人的好感。

B.婉转的方法——不断的改直到有效
  1. $window_width  = 640      # 设置的长度
  2. $window_height = 480      # 设置的高度

  3. hWnd = get_hWnd
  4. GetClientRect = Win32API.new("user32", "GetClientRect", "lp", "l")
  5. rect = [0,0,0,0].pack("l4")

  6. while rect.unpack("l4")[2,3] != [$window_width, $window_height]
  7.   Graphics.resize_screen(544, 416)
  8.   Graphics.resize_screen($window_width, $window_height)
  9.   GetClientRect.call(hWnd, rect)
  10. end
复制代码
这样的好处就是在最大化的时候才真正改动,不用强制启动窗口。

C.更婉转的方法——面对着窗口的时候才会改:
  1. $window_width  = 640      # 设置的长度
  2. $window_height = 480      # 设置的高度

  3. hWnd = get_hWnd
  4. IsIconic = Win32API.new("user32", "IsIconic", "l", "l")
  5. while IsIconic.call(hWnd) != 0
  6. end
  7. Graphics.resize_screen($window_width, $window_height)
复制代码
这办法比以上二种都要好,但是关于while的停顿写的不好,希望有人指正。

欢迎讨论更多有关这问题的解决办法或思路。

作者: 剑兰的马甲    时间: 2011-4-10 15:53
标题: 用脚本的得出异常的办法
本帖最后由 剑兰的马甲 于 2011-4-10 16:36 编辑

二楼这里提供一个用脚本来得出异常的办法,
同样的需要紫苏大人的精准获取窗口句柄的脚本。然后插进脚本:
  1. hWnd = get_hWnd
  2. CloseWindow = Win32API.new("user32", "CloseWindow", "l", "l")
  3. CloseWindow.call(hWnd)
  4. Graphics.resize_screen(640, 480)
  5. ShowWindow = Win32API.new("user32", "ShowWindow", "ll", "l")
  6. ShowWindow.call(hWnd, 9)
复制代码
测试游戏时什么都不用干就可以了。(你就会发现和一楼的状况差不多。)
这个脚本没有什么动作,只是纯粹最小化然后改分辨率再最大化。
作者: summer92    时间: 2011-4-10 17:06
- -是不是又是开始就更改分辨率,然后减少错误。。。原来我用了个先限制窗口显示再显示的馊办法,进来顶
作者: 一箭烂YiJL    时间: 2011-4-10 17:23
回复 summer92 的帖子
不是又是开始就更改分辨率,然后减少错误

这个只是防止"分辨率变大,但是窗体没大"导致模糊的bug。
总之主楼的几个办法可以取代Graphics.resize_screen。
(其实可以重写Graphics.resize_screen的...但是目前的方法比较多。)

先限制窗口显示再显示

理解不能。能详细说明办法或者展示脚本吗?
作者: summer92    时间: 2011-4-10 17:30
回复 一箭烂YiJL 的帖子

脚本是使用API那些东西,就是紫苏大的创建窗口前就更改分辨率(XP版),不过是XP版的,我想用在VX上可惜不行,后来只能来个伪方法,先删除game.exe内的显示窗口API函数(这样打开游戏窗口,它就不显示),然后等窗口( 虽然看不见)分辨率改成640480后,再vx脚本里通过API函数将窗口显示出来,只是过程比较慢仔细观察还是能看出来,具体可以看我的帖子
http://rpg.blue/thread-170349-1-1.html
脚本大部分都是API,还有你标题里面的重设大小

作者: 一箭烂YiJL    时间: 2011-4-10 18:09
标题: 潜在问题?:resize_screen改分辨率(欢迎进入讨论)
回复 summer92 的帖子

窗体为最大化改分辨率才有效,而删除Game.exe的ShowWindow并不是好的方法,
毕竟可能还有更重要的任务留在Game.exe。第一个方法也用到ShowWindow,
删不删的分别是不删会弹出来一次。不删的话还有主楼的另外两个方法。

如果你用:精准获取窗口句柄
再加上ShowWindow的API的话。
会否无法显示呢? 精准获取窗口句柄 其中API牵涉到前台(焦点)窗口,
当没把窗口显示出来的时候,会否一直停在获取窗口句柄中呢? (希望你能帮我求证下.)

作者: summer92    时间: 2011-4-10 18:18
回复 一箭烂YiJL 的帖子

- -我试过啊,就是不会用,API方面我什么都不懂,就是想把XP的移植到VX上,可能是哪个关键环节有问题,主要是不知道通过API控制Window窗口的核心代码吧,要是ruby代码我倒是还会,

“当没把窗口显示出来的时候,会否一直停在获取窗口句柄中呢?” 伪方法的使用倒是没什么问题,game.exe中也只修改了一个显示的DD没影响其他的,只是用起来比紫苏大真正的简洁式要慢一点点,从目的上来说是一样的
作者: 一箭烂YiJL    时间: 2011-4-10 18:37
本帖最后由 一箭烂YiJL 于 2011-4-10 18:37 编辑

回复 summer92 的帖子

核心代码? API函数和参数是吧。

什么从目的上来说一样,我是指不用HWND.dll来获取窗口句柄,
而使用紫苏大人的纯Ruby来获取。于是我自己尝试了一次,
虽然纯Ruby的获取窗口句柄是可以,但是开了等很久才执行ShowWindow,
反而对游戏造成玩家的不便。
作者: summer92    时间: 2011-4-10 19:01
回复 一箭烂YiJL 的帖子

对啊,就是怎么在ruby里用API控制窗口,不过根据贴子内容似乎不可能,因为创建窗口必须先要经过game.exe处理,所以必须在外面动手不可,XP版的好象是通过代理dll (user33.dll)控制窗口创建过程(user33.dll放到vx工程下无用。。悲剧),句柄的话是在VX脚本内获得的,那个全局变量就是,所以单纯依靠VX代码实现窗口控制是不行的,而且,VX还会在窗口创建后再检查并改回一次分辨率(幸好有大大做了一个删除检查的dll),,综合下来没有dll还是不行,还是等真正的XP游戏窗口启动控制移植VX吧。。。dll我也是外行。。
作者: 一箭烂YiJL    时间: 2011-4-10 20:00
回复 summer92 的帖子

user33.dll? user32.dll!
如果你说的XP是这个:http://rpg.blue/article-40821.html
原理是用SetWindowPos,其他API都是用于获取窗口句柄和正确坐标,
而SetWindowPos和MoveWindow的功能差不多,他们能让窗口变大,
但不能让RM的像素分辨率上升,也就是把窗口拉长拉高而已。
也就是说,这样可以说不是我们所追求的分辨率。

那么如果是修改RGSSxxxx.dll的话,大致上分两种:
1.脚本式,也就是Graphics.resize_screen释放更大空间
2.初始化式,一开出来的窗口就那么大了
两种来说XP和VX都已经见过了。

http://rpg.blue/article-40821.html
这个无法移植?实质上是可以的。先用紫苏大人的精准获得窗口句柄的脚本。
  1. MoveWindow = Win32API.new("user32", "MoveWindow", "llllll", "i")
  2. MoveWindow.call(get_hWnd, 0, 0, 1024, 768, 0)     # 随意写,所以没理xy坐标
复制代码
出来的效果窗口内很模糊,也就是"分辨率大了,但是窗体没大"。
作者: 苏小脉    时间: 2011-4-11 03:41
精准获取窗口句柄 其中API牵涉到前台(焦点)窗口,
当没把窗口显示出来的时候,会否一直停在获取窗口句柄中呢? (希望你能帮我求证下.)

当 Ruby 脚本开始被 RM 嵌入的解释器执行时,窗口已经显示了,除非之后又刻意让它隐藏。GetWindow 应该能获取到隐藏的窗口,毕竟隐藏窗口并不会改变其 Z 次序,而且连被销毁的窗口的句柄都能引用到,又何况只是被隐藏的。

不过没有测试过,不敢下定论。

“精确获取窗口句柄”这个脚本有以下问题,虽然出现概率极低:
1、GetWindow 可能导致无限循环,或是获取到已经被销毁的窗口句柄(这个在 MSDN 的文档里有说明);
2、由于是从前台窗口开始查找,如果前台窗口的类型不同,就可能找不到 RM 的窗口(比如前台窗口是“总在最上”的窗口,但 RM 窗口不是);
3、只进行了线程标识的匹配,然后一个线程可以创建多个窗口。如果 RM 主线程被用来创建别的(辅助)窗口,很可能就匹配不到预期的主窗口了;
4、只进行了窗口类名的匹配,而多个窗口可以是同一类(即属于一种窗口实例,有相同的窗口类名,比如 "RGSS Player")。

相比之下更好的办法 MSDN 也提到了,就是使用 EnumWindows,但 EnumWindows 只能解决上述第一个问题。同时由于 EnumWindows 需要回调函数,而 RM 默认无法编写本地代码,所以纯 Ruby 只能用 GetWindow。真·后台运行用的就是 EnumWindows,因为是 DLL 管理的。

现在看来,这个脚本离精确还差得远。真正意义上的精确这两种方法做到了:
http://rpg.blue/forum.php?mod=viewthread&tid=157287
http://rpg.blue/forum.php?mod=viewthread&tid=160672
前者是劫持 CreateWindow,后者是逆向工程。



还是等真正的XP游戏窗口启动控制移植VX吧。。。

本来我都移植了一半了,但后来因为全屏那块和 XP 不太一样就放弃了,以后也不打算继续弄,反正最重要的分辨率功能 David、神思、八云等人都发过逆向的方法了嘛。
作者: summer92    时间: 2011-4-11 11:38
"出来的效果窗口内很模糊,也就是"分辨率大了,但是窗体没大"。" 没有这个问题啊,具体可一参考下我最近发的新游戏(还没发),就用了这个,除了慢一点,其他方面没什么挑剔的。。

"本来我都移植了一半了,但后来因为全屏那块和 XP 不太一样就放弃了,以后也不打算继续弄"  呜呜。。不是吧。
作者: 一箭烂YiJL    时间: 2011-4-11 17:25
回复 苏小脉 的帖子
GetWindow 应该能获取到隐藏的窗口

窗口还没显示出来针对八云这个删掉ShowWindow的exe(<--帖子)
我测试了下,还可以获取窗口句柄,那么GetWindow还可以用。

“精确获取窗口句柄”

貌似紫苏回应这个可能是因为我说:
"虽然纯Ruby的获取窗口句柄是可以,但是开了等很久才执行ShowWindow"
"Ruby窗口句柄可以"意思是不用HWND.dll(详见上面链接)来获取句柄,
也就是还没有ShowWindow的时候还可以使用“精确获取窗口句柄”。

还真想不到“精确获取窗口句柄”有缺陷。

想问一个关于Ruby语法的,主楼所以提供解决分辨率问题的第三个方法:
  1. $window_width  = 640      # 设置的长度
  2. $window_height = 480      # 设置的高度

  3. hWnd = get_hWnd
  4. IsIconic = Win32API.new("user32", "IsIconic", "l", "l")
  5. while IsIconic.call(hWnd) != 0
  6. end
  7. Graphics.resize_screen($window_width, $window_height)
复制代码
while是RGSS开始且窗口最小化时停下,这写法似乎不太好,有更好的写法么?

还是等真正的XP游戏窗口启动控制移植VX吧。。。

这句不是我说的= =是summer92- -
作者: summer92    时间: 2011-4-11 18:29
回复 一箭烂YiJL 的帖子

- -没有模糊啊,你指的模糊是画面拉伸?,分辨率是实打实的横向640像素,纵向480像素。。。。不模糊
作者: 一箭烂YiJL    时间: 2011-4-11 20:14
回复 summer92 的帖子

明白了,你指的是XP,我说的是VX。VX的窗口较为诡异,(重申10楼)不用Graphics.resize_screen而用SetWindowPos和MoveWindow,分辨率无增,但窗口大小增加的问题,导致窗口模糊。


先把SetWindowPos和MoveWindow简写为:SetWnd和MoveWnd。但是如果resize_screen失效(主楼说的问题),再用SetWnd和MoveWnd放大窗口至640x480都可以,分辨率正常。

但SetWnd和MoveWnd潜在问题和resize_screen一样(主楼说的问题),
那么比较Graphics.resize_screen和(SetWnd和MoveWnd):

那么改变画面分辨率的方法又是什么呢?具体要问有dll逆向工程的几位了。

作者: yangff    时间: 2011-4-11 20:19
我表示用的APIhook+exe,首先窗口本身就是1024*768的,再禁用movewindow(好像是这个吧……)防止VX改窗口大小……
作者: 苏小脉    时间: 2011-4-12 02:43
回复 一箭烂YiJL 的帖子
while是RGSS开始且窗口最小化时停下,这写法似乎不太好,有更好的写法么?

处理 WM_SYSCOMMAND 消息,当 wParam 是 SC_MINIMIZE 的时候就是一个最小化事件发生之后。不过……在没有扩展的情况下纯 Ruby 并不能良好地消息处理。
作者: summer92    时间: 2011-4-12 11:12
回复 一箭烂YiJL 的帖子

哦,明白了 你是指不用Rgss的Graphics.resize_screen 方法进行画面重设,是啊,这样的话API更改分辨率后,真实的分辨率是不会变的(应该是Rgss又把分辨率改回来了?),所以画面被拉伸了,不用Graphics.resize_screen的话怎么真分辨率似乎还要解决一下
作者: 苏小脉    时间: 2011-4-12 14:43
回复 summer92 的帖子
应该是Rgss又把分辨率改回来了?

是 VX 在渲染的时候按照窗口的实际矩形尺寸在渲染(通过 GetWindowRect 之类的),这一点和 XP 固定在一个预设的矩形中渲染不同。
作者: 一箭烂YiJL    时间: 2011-4-12 18:15
回复 苏小脉 的帖子

那么也就是一定要修改WindowProc函数了。听您说Graphics.update会导致GetMessage无法获得,那么纯Ruby就不可能了。(PeekMessage貌似不是好的办法。)

实际上我想问的是while的语法,我用while的目的是让RGSS暂停,当RM窗口为前台窗口的时候,才继续(才Graphics.resize_screen)。Ruby有一个能够暂停的方法么?一直循环在这个空的循环中似乎不是太好。
作者: yangff    时间: 2011-4-12 18:36
这样试试……强制修改窗口的WIDTH和Height然后在执行resize
作者: 苏小脉    时间: 2011-4-13 06:16
回复 一箭烂YiJL 的帖子
那么也就是一定要修改WindowProc函数了。

不一定,可以通过SetWindowsHookEx注册一个窗口消息的过滤器,不过本质上还是和替换 WIndowProc 一样是建立了一个自己的钩子函数。

听您说Graphics.update会导致GetMessage无法获得,那么纯Ruby就不可能了。(PeekMessage貌似不是好的办法。)

GetMessage 可以获得,但不会获得全部,有相当一部分消息会被 RGSS 底层的消息循环取走,这个在沉影的鼠标贴里和她讨论过。PeekMessage 只是不从消息队列拿走消息,仍然不能让消息掠夺的现象改观。

实际上我想问的是while的语法,我用while的目的是让RGSS暂停,当RM窗口为前台窗口的时候,才继续(才Graphics.resize_screen)。Ruby有一个能够暂停的方法么?一直循环在这个空的循环中似乎不是太好。

这个和后台运行的判断方法一样,后台运行是处理 WM_ACTIVATEAPP——一个当窗口获得键盘焦点时系统会发送的消息。要是纯 Ruby 能做到,后台运行就不需要 DLL 了。纯 Ruby 的话只能使用 WaitForSingleObject 或类似的函数,但 NT 并没有预设类似得到焦点的事件供 WaitForSingleObject 使用。

在 Ruby 中可以通过睡眠线程让当前线程的执行暂停。

  1. sleep(0.02)
复制代码
可以考虑在空的循环中添上 sleep 让线程睡眠,这是以判断的敏感度换取了 CPU 时间——在线程睡眠的时候 CPU 可以去干别的事,但同时这个判断相比之前敏感度降低了。这之间的差别在单核 CPU 架构下尤为明显,CPU 唯一内核的大部分时间都被这个空循环占用,在处理系统中其它程序的时候就没那么敏感了,对于最终用户来说,他们感觉到的就是一个字:“卡”。
作者: 一箭烂YiJL    时间: 2011-4-14 21:58
回复 苏小脉 的帖子
sleep

表示纯sleep无参数会:
由于我这台机是双核,在有sleep的情况下,第一的CPU(单核的反应?)的反应比第二的CPU使用量较为高,反而不用时第一的CPU(单核的反应?)的反应比第二的CPU使用量较为低。
感觉不用较好...但停一秒时的CPU效果理想,但灵敏度就在1秒的范围之内。就把整个空while写成:
  1. sleep(1) until IsIconic.call(Handle::HWND) == 0
复制代码
那么就要在CPU和灵敏度之间取一个平衡。



之后对外解释一下B(第二个)方法为什么先要resize_screen(544, 416)再resize_screen正确分辨率,这是因为resize_screen一次后再次同一参数执行会无效,也就是Graphics会记录resize_screen最近一次的改分辨率数字,输入同上次参数时会无动作。同时归纳出这个方法会更消耗CPU操作。

ps:消耗CPU操作只维持在改分辨率和最小化的同时。
作者: 苏小脉    时间: 2011-4-15 00:40
回复 一箭烂YiJL 的帖子
表示纯sleep无参数

无参数时使用默认值 0,表示永远睡眠。

由于我这台机是双核,在有sleep的情况下,第一的CPU(单核的反应?)的反应比第二的CPU使用量较为高,反而不用时第一的CPU(单核的反应?)的反应比第二的CPU使用量较为低。

没看明白什么意思,你是说添加了 sleep 反而提高了 CPU 使用率?断无这个道理,不知道你是怎么测试的。
作者: 一箭烂YiJL    时间: 2011-4-15 15:05
回复 苏小脉 的帖子
sleep无参数时使用默认值 0,表示永远睡眠

奇怪的没有...写sleep不会永远睡眠啊,例如:
  1. sleep    # 不会永远睡眠
复制代码
如果写这样就会永远睡眠:
  1. sleep(0);sleep
复制代码
那么这样就无效:
  1. sleep(0)            # 或者是:
  2. sleep(0);sleep(0)   # 或者是:
  3. sleep   ;sleep      # 都不会永远睡眠
复制代码
貌似sleep(无参数)只是一个执行。

您上楼(我)有点话说错了><

我双核,任务管理器的时候会有两个CPU显示块,用sleep和不用sleep都各有高低,分别相反。
作者: 苏小脉    时间: 2011-4-16 01:41
一箭烂YiJL 发表于 2011-4-15 15:05
回复 苏小脉 的帖子

测了一下,sleep 默认参数为 0 这个好像是《Programming Ruby》的文档失误,为 0 时 sleep 应该是立即返回,昨天我是依据这个说的,很明显错了。

但如果没有传递 sleep 参数,那确实是表示永久睡眠,这是各种文档都明确说明的。process.c 中 sleep 的实现也是如此显示:
  1. static VALUE
  2. rb_f_sleep(int argc, VALUE *argv)
  3. {
  4.     time_t beg, end;

  5.     beg = time(0);
  6.     if (argc == 0) {
  7.         rb_thread_sleep_forever();
  8.     }
  9.     else if (argc == 1) {
  10.         rb_thread_wait_for(rb_time_interval(argv[0]));
  11.     }
  12.     else {
  13.         rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
  14.     }

  15.     end = time(0) - beg;

  16.     return INT2FIX(end);
  17. }
复制代码
当没有参数时调用 rb_thread_sleep_forever。

RM 要么是刻意做了什么手脚,要么就是在嵌入解释器的时候没考虑周全产生了 BUG。

我双核,任务管理器的时候会有两个CPU显示块,用sleep和不用sleep都各有高低,分别相反。

CPU 在执行 Ruby 程序的时候如果得到空闲,自然又跑去执行别的程序了。Ruby 睡眠了线程就相当于自动放弃了当前的时间片。你应该看的是 ruby.exe (或者 Game.exe,如果用的是 RM)这个进程的 CPU 使用率。
作者: eve592370698    时间: 2011-4-24 20:31
标题: 我给您上传了个附件,您看看有多恶心吧
本帖最后由 eve592370698 于 2011-4-24 21:11 编辑

我自己东拼西凑弄了个vx1024×768分辨率的脚本,就是用起来挺那个,不知道怎么说。

GTBS1024x768D.rar

3.9 MB, 下载次数: 57


作者: xiangbd    时间: 2011-5-10 15:13
提示: 作者被禁止或删除 内容自动屏蔽
作者: 零度    时间: 2011-7-20 19:58
直接改个game.exe 和RGSS202E.dll  八紫云 大大曾经扔给我 两个分辨率的 一个640*480 一个 800*600 都是一打开就是分辨率的大小  并没有从脚本中加载 不过可惜的是 地图分辨率并没有解限
lz可以考虑一下
作者: 一箭烂YiJL    时间: 2011-7-21 20:56
零度 发表于 2011-7-20 19:58
直接改个game.exe 和RGSS202E.dll  八紫云 大大曾经扔给我 两个分辨率的 一个640*480 一个 800*600 都是一 ...
直接改个game.exe 和RGSS202E.dll

Game.exe 控制了打开的分辨率,RGSS202E.dll 监控后来的分辨率,我记得貌似这个配搭会令窗口边有一点点变化,而且 RGSS202E.dll 似乎也会出现同 SE 无法连续播放的问题。

地图分辨率并没有解限

是因为游戏脚本的 Viewport 问题,可以搜索一下关键分辨率 544 和 416 的 Viewport 。还有很多问题都是与游戏内部坐标有关的,你可以自己修改一下,或者找现成的修改好的工程。

都是一打开就是分辨率的大小  并没有从脚本中加载

被修改后的 Game.exe 和 RGSS202E.dll 当然是,但是在脚本里再修改分辨率的话就应该会出现这个潜在问题。
作者: 零度    时间: 2011-7-22 17:29
一箭烂YiJL 发表于 2011-7-21 20:56
Game.exe 控制了打开的分辨率,RGSS202E.dll 监控后来的分辨率,我记得貌似这个配搭会令窗口边有一点点 ...

不是的,dll上面有个地图限制,最大只能是640*480,6r上有人解除过这种限制,改过后的并没有任何bug,如果需要的话,我可以发上来给你看看




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1