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

Project1

 找回密码
 注册会员
搜索
查看: 13369|回复: 42
打印 上一主题 下一主题

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

 关闭 [复制链接]

Lv1.梦旅人

有事烧纸

梦石
0
星屑
154
在线时间
509 小时
注册时间
2005-10-22
帖子
6982

贵宾VX城市地图大赛冠军第1届RMTV比赛冠军第1届TG大赛冠军

跳转到指定楼层
1
发表于 2007-6-2 19:39:57 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

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

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

x
唔 ms RM里10s米刷新就会挂掉的问题,这里写个最简单且效率最高的的解决方法。= =b

在RM的脚本里加上这句就行鸟- -bbb

Thread.new{loop{Graphics.update;sleep(9)}}

现在弄什么就米那10s的限制了,随便使用- -bbbbbbbbbbbbbbbbb

以下测试:

1、先不加上面那句,直接在脚本里sleep(10),等10s后程序出现脚本已备份,挂掉= =b

2、我们把这句加进去之后再测试,sleep(20),依然不会挂掉,ok,成功= =bbbb

ps:如果只加上面那句的话有一点问题的,现在改下:

@update_thread = Thread.new{loop{Graphics.update;sleep(9)}} if @update_thread.nil?

 至于前面那句有什么问题,大家想吧……= =bbb

以下这段补充:
  1. class << Graphics

  2. alias origin_update update unless method_defined? :origin_update

  3. def update
  4.    Thread.critical = true
  5.    origin_update
  6.    Thread.critical = false
  7. end

  8. end
复制代码


              [本贴由 叶舞枫 于 2007-6-5 21:18:35 进行了编辑]
神隐中,偶尔诈尸
头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
0 小时
注册时间
2009-3-7
帖子
21
43
发表于 2009-3-15 03:50:52 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
749
在线时间
377 小时
注册时间
2009-3-9
帖子
399
42
发表于 2009-3-11 22:03:36 | 只看该作者
郁闷 完全听不懂 我是新手中的新手。。。{/dk}
新手学习中.....努力吧!!
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
0 小时
注册时间
2007-7-11
帖子
9
41
发表于 2007-7-26 23:27:41 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

逃兵

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

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

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

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2025-7-21 00:17

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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