Project1

标题: 【更新】提高游戏运行速度(v1.01) [打印本页]

作者: 一箭烂YiJL    时间: 2011-4-21 13:24
标题: 【更新】提高游戏运行速度(v1.01)
本帖最后由 一箭烂YiJL 于 2011-4-23 18:09 编辑

0.序
往往游戏过程因为太慢,所以想高速测试有难度。
最简单的办法是将帧频率调高,但是不能超过120。
这办法适用在游戏测试中(尤其是破关时间),请不要发布于游戏中,
因为速度不等于效率,极快会感觉一卡一卡。


1.讲解
当删掉Graphics.update时,会出现画面不更新,但是操作极快的问题。
loop do绝对超过一秒60次(帧频率)。于是这是我的猜测
Graphics.update除了有更新画面的基本动作外,还会有:
  1. sleep(1/Graphics.frame_rate - 更新画面的时间 - 逻辑运算的时间)    # 此处经过修正
复制代码
所以不用Graphics.update就会高速不断地循环计算。

2.脚本
综合以上,脚本如下:

  1. #==============================================================================
  2. # ■ 提高游戏速度(v1.01)    by 一箭烂
  3. #------------------------------------------------------------------------------
  4. #  设置$Speed_Lv以致提高游戏速度,
  5. #    请插在main之上, Scene_Base之下
  6. #
  7. #  更新:
  8. #
  9. #    - *1.0.1* (2011-04-21) By 一箭烂(YiJL)
  10. #      *对Graphics.frame_count的修正
  11. #      
  12. #
  13. #    - *1.0.0* (2011-04-21) By 一箭烂(YiJL)
  14. #      *初版
  15. #
  16. #==============================================================================
  17. class Scene_Base
  18.   $Speed_Lv = 2     # 正常速度的倍数
  19.   #--------------------------------------------------------------------------
  20.   # ● 主处理
  21.   #--------------------------------------------------------------------------
  22.   def main
  23.     start                         # 开始处理
  24.     perform_transition            # 执行渐变
  25.     post_start                    # 开始后处理
  26.     Input.update                  # 更新输入讯息
  27.     #------------------------------------------------------------------------
  28.     # 添加部分
  29.     old_time = 1
  30.     #------------------------------------------------------------------------
  31.     loop do
  32.       #----------------------------------------------------------------------
  33.       # 添加部分
  34.       old_time += 1
  35.       old_time %= $Speed_Lv
  36.       if old_time >= ($Speed_Lv - 1)
  37.         Graphics.update           # 更新游戏画面
  38.       else
  39.         Graphics.frame_count += 1
  40.       end
  41.       #----------------------------------------------------------------------
  42.       Input.update                # 更新输入讯息
  43.       update                      # 更新画面
  44.       break if $scene != self     # 切换画面时中断循环
  45.     end
  46.     Graphics.update
  47.     pre_terminate                 # 结束前处理
  48.     Graphics.freeze               # 准备渐变
  49.     terminate                     # 结束处理
  50.   end
  51. end
复制代码
用#------
 #------包着的这些是外加的意思。

3.其他
实质上帧频率不变,但是做一次Graphics.update(画面更新)就等于做了x次的其他数据运算。
当数据运算量太大时就可能会有卡的状况。(Speed_Lv影响着数据运算比起平常倍数!)
还有现在的版本只能加速/不加速,不能减速!

4.范例
没什么范例可给的,一插脚本就见效嘛~伸手要范例的回帖去吧。
已经把回复可见去掉了,VX区为啥这么多人想在草原中奔跑呢?= =
提高游戏速度_v1.01.zip (261.49 KB, 下载次数: 609)

作者: zx工作室2    时间: 2011-4-21 13:28
本帖最后由 zx工作室2 于 2011-4-21 13:29 编辑

沙发!
为什么是VX的范例啊·····
作者: daipeng76    时间: 2011-4-21 13:55
支持,抱走了,看看是否能流畅的运行99个并行事件
作者: link006007    时间: 2011-4-21 14:00
最好  能够考虑到,画面只是游戏流畅度的一部分。对于每帧都有逻辑或AI计算的游戏来说,画面和这些部分不同步也会有很多问题。
作者: kaveil    时间: 2011-4-21 14:24
容易出错吧这样弄
作者: summer92    时间: 2011-4-21 14:30
是吗?超过120.....挑战CPU啊
作者: 苏小脉    时间: 2011-4-21 14:52
本帖最后由 苏小脉 于 2011-4-21 14:53 编辑

嗯,有些人称这种方法或现象为“跳帧”。
另外睡眠那里应该是减去游戏逻辑耗费的时间比较合理,因为是固定帧率。

变慢的话可以调用两次 Graphics.update,不过这么做只能是帧率的倍数,任意比率的话就只能手动 sleep 了,嘿嘿。
作者: 一箭烂YiJL    时间: 2011-4-21 15:14
回复 苏小脉 的帖子

那么也就是Graphics.update已经考虑到逻辑运算所消耗的时间了。
如此推论的话,当实际fps下降是因为RM进程(Game.exe)/RM线程的优先级不够高?
然后抢得CPU使用量不够多?于是我做了一下实验:


用SetProcessWorkingSetSize函数将RM进程(Game.exe)提升到最高级(即时):
  1. SetProcPriority = Win32API.new("kernel32", "SetPriorityClass", "ll", "i")
  2. SetProcPriority.call(-1, 0x100)
复制代码
然后用"跳帧"的方法,10倍的跳帧。
应用在我计划的一个即时性战斗游戏里,重点在于即时性,双方、动画、逻辑运算越来越多。
然后设下一个按钮开关,准备将优先级降低至悠闲级(最低)。

然后开始,不一会,CPU介乎于90~100%,然后把优先级降低至最低,
CPU使用率马上下降了,游戏也慢了下来。
作者: 苏小脉    时间: 2011-4-21 15:36
一箭烂YiJL 发表于 2011-4-21 15:14
回复 苏小脉 的帖子

那么也就是Graphics.update已经考虑到逻辑运算所消耗的时间了。

实际帧率下降主要还是逻辑超出了预期运算时间了(预期最大不超过 (1000/帧率) 毫秒),所以原本固定 40 帧每秒,实际可能只渲染了不到 40 帧。

在抢先式多任务的操作系统下通过调整优先级就算有性能上的改善,也不是解决问题的正途,因为这种行为很流氓。抢先式系统下资源大家共有,地主老财作风从来不被提倡。微软操作系统缺省的排程还是比较人性化的,在前台的程序优先级总是稍高于后台程序。
作者: Rings    时间: 2011-4-21 19:07
我喜欢收藏,所以要回复也下,切~。。。
作者: Anson    时间: 2011-4-21 19:28
还有现在的版本只能加速/不加速,不能减速!...
用此脚本为什么要减速...
作者: 005020671    时间: 2011-4-21 22:06
xp应该也可以用吧??
作者: 一箭烂YiJL    时间: 2011-4-21 23:50
更新了,仪式上顶一下。
如果卡的话,游戏Debug测试时可以用8楼的脚本,
但是要定制监控CPU使用量,以免耗用量过大。
更重要的是游戏发布时最好别用8楼的脚本。(流氓~)
作者: 啊海    时间: 2011-4-22 05:58
这个真的能提高游戏速度吗?
作者: 一箭烂YiJL    时间: 2011-4-22 17:03
回复 005020671 的帖子

XP的发布了:提高游戏运行速度
有一个bug,就是非"平滑模式",具体看上面。
作者: 快乐·小赵    时间: 2011-4-23 11:07
提示: 作者被禁止或删除 内容自动屏蔽
作者: link006007    时间: 2011-4-27 09:29
本帖最后由 link006007 于 2011-4-27 09:30 编辑

回复 link006007 的帖子

私以为,多线程对于CPU密集型计算没什么优化效果。。只有在IO较多或者运算可以很快完成的或者是CPU多核的情况下,多线程才有其优势。
而且,用线程执行AI计算需要的是线程同步比较重要吧。。

回错了。。。  是要回我自己帖子那个yangff的留言,。。。,
作者: 一箭烂YiJL    时间: 2011-4-27 10:07
回复 link006007 的帖子

偶尔看见您的发帖。于是就说:

我们RGSS脚本是一条线程,(好像也是窗口的主线程,紫苏应该比较清楚),
所谓画面、逻辑加快也只是限于这线程。那么其他Ruby线程在没加快的情况下,
而且该线程一直执行着与游戏有关的运算,就不再同步了。

线程有他自己的优先级,与他的进程的CPU使用有关,(一下只是评论:)
RM主线程被用满的时候,就要用Ruby的线程?(Thread.new),
但是也同时依赖Game.exe这个进程。Game.exe的优先级所有的CPU使用量也用完了,
那么彻底的完蛋了= =(该优先级不是好办法...另开进程也不是好办法...)
最好就是逻辑运算高速简洁。
作者: link006007    时间: 2011-4-27 11:57
本帖最后由 link006007 于 2011-4-27 12:19 编辑

RGSS只是一个封装其他语言(C\C++)函数的ruby对象集合,而ruby本身以一个解释器的方式本身运行于程序之内,对于RPG Maker而言,应该是在初始化完一个ruby解释器之后,进入RGSS的用户脚本,之后碰到loop循环(既所谓的main函数),然后导致程序的不断运行。所以,即使是ruby里面的Thread.new出来的线程应该也是属于RPGMake的进程,这样的线程就会和其他的线程分摊这个进程的CPU时间。所以,在非多核CPU或多CPU环境下,对于计算密集的进程而言,是没有优化效果的。
RM主线程被用满的时候应该是不存在的。同进程的线程会不会使得另外一个线程没有机会被调度,这个取决于操作系统的任务调度机制,对于大多数操作系统而言应该是不会的。除非那个进程本身难以被调度。多线程提供的就是一种并行的假象(多CPU是真的并行。。。),如果会有一个线程无法执行,那就失去线程的意义了。
我说的同步是,诸如画面和逻辑AI被分摊到不同线程中,只要是有关联的操作,同步就是必须的,因为永远无法知道几个线程在没有同步的条件下的确切状态,不然用信号量同步这类东西可以说再见了。
作者: 一箭烂YiJL    时间: 2011-4-27 13:31
回复 link006007 的帖子

原来确的,Ruby线程用的是时间片轮转法,开了多线程也是不会提高进程效率...但是Thread.new出来的线程是否属于窗口(RM主线程)就不知道,不过RGSS却的确被进行再RM窗口。(用GetCurrentThreadId和GetWindowThreadProcessId就能知道)。

但在任务调度机制下,优先级抢占运行。一个进程里的每一个线程都有他们的优先级,CPU是先给高优先级的进程,再由它的线程优先级分先后运行。多核是多个CPU在同时分配工作嘛~当然运行的快点啦。

控制线程操作速度...貌似要很手动,sleep少一点?
作者: 苏小脉    时间: 2011-4-27 13:46
本帖最后由 苏小脉 于 2011-4-27 13:47 编辑
所以,即使是ruby里面的Thread.new出来的线程应该也是属于RPGMake的进程,这样的线程就会和其他的线程分摊这个进程的CPU时间。

Ruby 1.8 的线程是绿色线程,是由解释器调度的,不能提升丝毫性能。其存在意义只是为了让语言拥有协程,能进行多任务设计。虽然后来 Ruby 1.9 采用了 OS 线程,但由于 YARV 不像 JVM 那么强力,只能和 CPython 一样部署全局解释器锁,大部分场合下仍然没有真正的并发,所以也不能提升性能。唯一的好处就是 Ruby 标准库以及第三方扩展可以在短时间内手动把锁解开达到并发,从而解决一些性能上的问题,比如阻塞的 I/O 操作。
RM主线程被用满的时候应该是不存在的。

这里“RM主线程”有歧义,是指 RM 的 OS 主线程,还是 Ruby 层面的绿色线程?如果用来指后者,当某个 Ruby 线程进行耗时的外部函数调用时,其它的 Ruby 线程确实会尽数僵死,因为其任务调度是由解释器负责的,而自始至终解释器都只是一条 OS 线程。
同进程的线程会不会使得另外一个线程没有机会被调度,这个取决于操作系统的任务调度机制,对于大多数操作系统而言应该是不会的。除非那个进程本身难以被调度。多线程提供的就是一种并行的假象(多CPU是真的并行。。。),如果会有一个线程无法执行,那就失去线程的意义了。

确实,如今家用计算机上常见的系统都是抢先式多任务系统,采用轮转式调度,每个线程的执行和操作系统为其分配的时间片有关,不会因为其中一个线程消耗所有 CPU 时间而出现整个系统假死的情况。不过,很多受时间约束的实时嵌入式操作系统都采用合作式调度,因为只有这样,实时程序才能有一个确定性的算法精确地控制实时序列,比如火箭上的航线修正系统。其实合作式多任务是最早被采用的调度方式,以前 Windows 9x,Mac OS Classic 等遗留系统都曾经用过。因为合作式多任务系统有上述排程缺陷,就逐渐过渡到了抢先式多任务。
作者: link006007    时间: 2011-4-27 18:30
苏小脉 发表于 2011-4-27 13:46
Ruby 1.8 的线程是绿色线程,是由解释器调度的,不能提升丝毫性能。其存在意义只是为了让语言拥有协程,能 ...

呃。。 看来我想当然了  我还以为1.8的线程是系统线程。。。
另外  你严谨的可以出教科书了 :lol




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