设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
楼主: 雷欧纳德
打印 上一主题 下一主题

最简单的解决RM的10s问题

 关闭 [复制链接]

Lv1.梦旅人

梦石
0
星屑
15
在线时间
0 小时
注册时间
2007-6-5
帖子
3
31
发表于 2007-6-5 10:21:53 | 只看该作者
10s不调用Update,系统会抛出异常,捕获异常即可。另开一个线程的话,可能会造成屏幕的闪烁。

比如游戏正在重新绘制场景,画了一半,这个线程里面的update触发了,那么画一半的场景就会显示在屏幕上。另外一半画完系统原来的update触发,就可能会造成画面“闪烁”。

加在脚本最前面不是很安全,实在需要这样的处理,临时插入然后用完终止这个线程才是比较安全的使用方法。绝大多数情况可以使用捕获异常这种安全又正常的方法……

不过这只是理论上的分析,也许这样做并没有实际的影响,就好像10s抛出Hangup异常并不是什么大麻烦一样。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
0 小时
注册时间
2006-12-20
帖子
213
32
发表于 2007-6-5 14:55:58 | 只看该作者
以下引用FDR于2007-6-5 2:21:53的发言:

10s不调用Update,系统会抛出异常,捕获异常即可。另开一个线程的话,可能会造成屏幕的闪烁。

比如游戏正在重新绘制场景,画了一半,这个线程里面的update触发了,那么画一半的场景就会显示在屏幕上。另外一半画完系统原来的update触发,就可能会造成画面“闪烁”。

加在脚本最前面不是很安全,实在需要这样的处理,临时插入然后用完终止这个线程才是比较安全的使用方法。绝大多数情况可以使用捕获异常这种安全又正常的方法……

不过这只是理论上的分析,也许这样做并没有实际的影响,就好像10s抛出Hangup异常并不是什么大麻烦一样。


呃 画面闪烁这问题确实一时米想那么复杂没考虑的 那补充一部分

  1. class << Graphics
  2.   
  3.   alias origin_update update unless method_defined? :origin_update
  4.   
  5.   def update
  6.     Thread.critical = true
  7.     origin_update
  8.     Thread.critical = false
  9.   end
  10.   
  11. end
复制代码


这样就不会造成闪烁了吧。。。

虽然可以捕获异常,但有的情况下还是不捕获的好吧…… = =

比如一个计算很大的循环、计算到10s你捕获到异常 难道retry重新计算还素怎么处理呢?
还有下载东西什么的= =bbb
哼哼。。。。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

Dancer-

梦石
0
星屑
55
在线时间
76 小时
注册时间
2006-11-9
帖子
3551

开拓者贵宾

33
发表于 2007-6-6 05:17:55 | 只看该作者
发布上去 ==b
http://rpg.blue/web/htm/news747.htm
VIP 2
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
15
在线时间
0 小时
注册时间
2007-6-5
帖子
3
34
发表于 2007-6-6 07:54:41 | 只看该作者
以下引用尤莉斯于2007-6-5 6:55:58的发言:
class << Graphics

alias origin_update update unless method_defined? :origin_update

def update
   Thread.critical = true
   origin_update
   Thread.critical = false
end

end
这样就不会造成闪烁了吧。。。

没细看前面的代码,如果原来没有这个保护的话那必须加上.因为如果没的话,就不仅仅是画面闪烁的问题,而是个错误.毕竟原来的update没有说明是线程安全的,多开一个线程调用它的话,很有可能在update的内部冲突.(想像update执行到一半另外一个update执行)

我说的画面闪烁来自于RGSS层面,不是update自身重复,考虑下面的步骤:

绘制近景
绘制人物
update

本来是都画好才显示到屏幕的,如果还有线程在update,那么可能刚刚绘制完近景就显示在屏幕上了.也有可能近景绘制了一半...这样的画面比起原来就是带点"闪烁"的

个人觉得Hangup异常是可以处理的.比起可能的画面破坏,自己多写点代码处理下异常没什么.异常本来就是让你处理而不是让你回避的.至于RGSS上用多线程,感觉在网络方面的应用要比这样的trick实在.
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
0 小时
注册时间
2007-5-24
帖子
192
35
发表于 2007-6-6 17:22:24 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
0 小时
注册时间
2006-12-20
帖子
213
36
发表于 2007-6-6 19:50:04 | 只看该作者
以下引用FDR于2007-6-5 23:54:41的发言:
没细看前面的代码,如果原来没有这个保护的话那必须加上.因为如果没的话,就不仅仅是画面闪烁的问题,而是个错误.毕竟原来的update没有说明是线程安全的,多开一个线程调用它的话,很有可能在update的内部冲突.(想像update执行到一半另外一个update执行)

我说的画面闪烁来自于RGSS层面,不是update自身重复,考虑下面的步骤:

绘制近景
绘制人物
update

本来是都画好才显示到屏幕的,如果还有线程在update,那么可能刚刚绘制完近景就显示在屏幕上了.也有可能近景绘制了一半...这样的画面比起原来就是带点"闪烁"的

个人觉得Hangup异常是可以处理的.比起可能的画面破坏,自己多写点代码处理下异常没什么.异常本来就是让你处理而不是让你回避的.至于RGSS上用多线程,感觉在网络方面的应用要比这样的trick实在.


一般游戏更新顺序是:

更新游戏数据
更新画面
sleep
跳帧处理什么的

这样的步骤的吧

而rm里更新画面就是 Graphics.update 负责处理的吧
那么不管 是否先绘制近景、然后绘制远景 然后在把缓冲区显示到屏幕上,这些都是在
Graphics.update内部完成的吧~~
那么
  Thread.critical = true
  origin_update
  Thread.critical = false
这样在进入更新画面之间就把临界区标记设置为真了,也就不会进行线程的切换,所以必须更新画面全部完成后退出临界区之后才可以切换画面的了,这样会有闪烁么?
即使在没进入临时区前发生现成切换那么也不会有影响的吧。。

至于处理那个异常,其实很多地方都不太好处理的,比如load的地图过大挂掉怎么处理?这只是一个问题而已,一般许多人又8弄脚本的就更不会去处理了= =

ps:想问问fdr一个问题,在rm里调用 Win32API 然后 网络 accept这个函数的时候~~ 它直接阻塞进程了,而不是阻塞的线程,是因为。。?

哼哼。。。。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
15
在线时间
0 小时
注册时间
2007-6-5
帖子
3
37
发表于 2007-6-6 21:16:11 | 只看该作者
显示是由update完成的,但游戏画面的处理是由RGSS完成的。我说的问题出现在RGSS层面的游戏逻辑里面,不是update本身。

说得再具体一点,是Ruby脚本,脚本里面在控制游戏人物走在什么位置。单举人物的例子好了:
本来有两个sprite,下一帧需要它们平移5个单位,玩家应该看到的是两个sprite“同时”移动,本来我这样写就可以保证这个效果:

sprite1.x += 5
sprite2.x += 5
update

但是另外还有线程在update的话,sprite1移动之后就显示在屏幕上了,玩家看到了,接下来才是sprite2的移动。假如某个游戏物件是由多个sprite组合成的,譬如一个人的头和身体……这样就是错位了。我说“闪烁”是因为此过程很快,看起来像闪了一下。

除非你把整个需要update的地方包裹在critical中,这需要改动很多。你的那段代码只是保证update自身属于critical section,而不是"update游戏画面"的整个过程。

我只是要说lz帖子里面的方法可能会造成问题,理论上的,实际中要看情况。这是一个trick而不是bug fix,因此有必要让使用者了解可能的后果。对于一个游戏来说,任何时候画面都应该是不停的更新的,即使load地图也一样。这个时候load地图倒更应该作为新开的线程...

但为了简化修改,可以在load地图的时候加上这句。在load的时候保证画面的更新,在load之后要去掉。而不是在脚本的最前面加上这句,造成整个游戏过程中不可预知的问题。


===============================
至于win32api的问题我不是很清除,猜测一下……可能是因为Ruby本身解释器运行中只有1个线程负责脚本的运行,调用win32api的时候解释器本身的线程被阻塞了,因此整个都停了下来。可能Ruby的多线程不是靠OS来调度,而是靠Ruby自身的解释器,因此要停就都停下来……个人猜想而已。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
0 小时
注册时间
2006-12-20
帖子
213
38
发表于 2007-6-6 22:44:23 | 只看该作者
其实我想说的是 我说不会出现闪烁是指你前面提到的那个画面绘制了一半而另外个线程update了造成闪烁的情况而已。对于你说的游戏画面由RGSS进行处理的问题,我觉得是RM根本无法避免的问题,不仅是我的那个方法而已。
我们可以把Graphics里的update方法简单分析为这样:
def update
  1、在后台缓冲区绘制画面 # 在RM里也就是所有viewport里的内容
  2、然后把后台缓冲区显示到屏幕上 # 当然这里不管是直接copy到前台还是页面翻转
end
而改为
def update
  设置临近区 # 也就是禁止线程的切换
  1、在后台缓冲区绘制画面
  2、然后把后台缓冲区显示到屏幕上
  关闭临界区 # 允许线程的切换
end
之后,那么就算是两个线程都可以update,那么也不会存在画面只描绘了一半而出现的那种闪烁的情况。

你说的那个闪烁我觉得是无法避免的:游戏的运行过程我们这里这样认为:

主循环
  A、更新游戏数据
  B、Graphics.update
  C、线程休眠限制帧率
循环结束
那么你说的那个sprite1.x += 5 sprite2.x += 5就属于A阶段里面处理的内容,加入此时顺序为

sprite1.x += 5
另外线程插入执行然后调用B运行  # 此时也只是造成了看着1比2先显示这点而已,不会出现画面部分显示的情况
sprite2.x += 5

我说RM无法避免这个情况是这样的:

sprite1.x += 5
sprite2.x += 5
sprite3.x += 5

假设在执行sprite2.x += 5这条语句后已经10秒了 但前面的 A部分还没完,也就是没执行的刷新画面的B处,那么RM这样必然挂掉。所以我们就采用了那个极端的方法在这里强制刷新一次画面而已。在RM里不是也有这样情况么:
一般采用一个计数count

if count > 一个定值
  Graphics.update
  count = 0
end

也就是防止挂掉而已,其实和线程处理的功效是一样的。

再如果我们也这样处理:

设置临界区
sprite1.x += 5
sprite2.x += 5
退出临界区

这样可以保证在执行这两条语句之间另外的线程不会执行,但我们不能保证在执行上一条后程序就挂掉了。。= = ,所以唯一能做的就是只能强制刷新一次画面而已。。= =


哼哼。。。。
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
49
在线时间
0 小时
注册时间
2007-4-21
帖子
101
39
发表于 2007-6-9 21:27:57 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

逃兵

40
发表于 2007-6-9 23:48:34 | 只看该作者
夏大人...ORZ
回复 支持 反对

使用道具 举报

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

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-15 03:51

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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