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

Project1

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

[交流讨论] 歪门邪道事件心得[1]:为什么我的事件标题手感不好

[复制链接]

Lv5.捕梦者 (版主)

梦石
28
星屑
10170
在线时间
4673 小时
注册时间
2011-8-22
帖子
1279

开拓者

跳转到指定楼层
1
发表于 2018-4-7 11:01:16 | 显示全部楼层 |只看大图 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 ⑨姐姐 于 2018-9-12 16:36 编辑

一直想开这个坑,今天终于开了。这一系列会专注于一些比较边缘地带的知识,它们经常被作者们当做“玄学”,或者被不屑一顾。但是,每个现象都是有它的道理的,深入了解下去,就能对RM的运作方式更加熟悉,制作出更符合心意的游戏效果。
这系列面向的是有一定事件基础的制作者们,并没有脚本水平的要求(完全不会也没关系)。另一方面,也许写了很长时间脚本但对RM的默认内容关注不多的,也能从中得到一些有用的东西吧。

欢迎反馈关于内容深浅以及描述方式等等的各种问题,也欢迎提供各种大家在RM中的“玄学”以及一直当做习惯却难以理解的地方,在以后的几期中也可以把这些作为主题的。
-------------------------------------------------------------

一天,埃里克百无聊赖地在海洋上行走(不要问他是如何做到的)。


他觉得,是时候开始游戏了。“开始游戏”……就是说需要个游戏标题:



用图片当做三个按钮,然后用并行事件判断当前的选项和图片的透明度,像这样——





可是,埃里克发现了一个问题:按左右键的时候,不是每次都成功的,有时候按了但是毫无反应。
“为什么我的事件标题手感不好呢?明明所有地方都写对了。”

“你遇到问题总是愁眉苦脸,这可不是勇者该有的样子呢。”娜塔莉不知什么时候出现在这里。


“我猜,按键没反应,是不是RM内部的按键输入时好时坏?”

“不可能。”娜塔莉否定了埃里克的猜想,“如果RM的输入真的有问题,为什么其他菜单的窗口都那么流畅呢?”

“难道是很多人说的,事件的效率天生不如脚本,用事件就会卡顿?呜呜呜,我要去学脚本……”

“给我打起精神来你这白毛!你忘了事件的背后就是脚本在运行吗?这两者又有什么区别呢。”

“事件的背后就是脚本?”

“一看你就没有好好听大贤者的讲课。来,我们打开脚本编辑器,找到Game_Interpreter。46行。”

RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2. # * Event Setup
  3. #--------------------------------------------------------------------------
  4. def setup(list, event_id = 0)
  5.   clear
  6.   @map_id = $game_map.map_id
  7.   @event_id = event_id
  8.   @list = list
  9.   create_fiber
  10. end

在埃里克疑惑的目光中,娜塔莉解释道:“你看,这个setup,就是把事件的内容放入脚本中去执行了。list是事件列表,event_id是事件编号。所以我们编辑的每一个事件,其实都会丢到脚本里去执行的。既然这样,为什么要说事件速度慢呢?根本就是无稽之谈。”

埃里克还是没有完全搞懂:“我还记得一些脚本,这种等于号的都只是把一个值放到另一个变量里的操作,比如a=2就是把a变成2。就算我生成了好多个变量,但它们也只是数据倒来倒去而已,事件放进去以后,怎么执行呢?”

“事件执行的奥秘,就在create_fiber里了。”

娜塔莉一遍说着,一遍顺着脚本往下追溯:

RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2. # * Create Fiber
  3. #--------------------------------------------------------------------------
  4. def create_fiber
  5.   @fiber = Fiber.new { run } if @list
  6. end

RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2. [font=&quot]# * Execute[/font]
  3. #--------------------------------------------------------------------------
  4. def run
  5.   wait_for_message
  6.   while @list[@index] do
  7.     execute_command
  8.     @index += 1
  9.   end
  10.   Fiber.yield
  11.   @fiber = nil
  12. end



“埃里克,你看这个run,不就是执行事件的过程吗。execute_command的意思是执行一条事件指令,@index += 1的意思是把事件执行的位置往下移一格。你可以想象,你用铅笔指着一条事件,执行完以后再执行下一条事件的感觉。”

埃里克反而更疑惑了:“从这里看来,我上面写的事件应该是一点问题也没有啊,怎么可能按键失效呢。除非事件没有正常执行,没能通过条件分歧判断到我的按键,才会出现失效的情况吧。”

娜塔莉沉思片刻,两眼突然放出了光芒,把埃里克吓了一跳:“我明白了,你的事件确实没问题,问题出在事件结束的时候。埃里克,我考你一个问题,从上面的run当中,你能看出事件结束的时候会发生什么吗?”

“事件结束的时候,@index就超过事件列表的长度了,所以@list[index]就拿不到事件的内容,这时候while……”

“答对了,while @list[index]的循环就会正常退出,事件也就结束了。接下来呢?”

“接下来……Fiber.yield,这是什么意思呢?”

娜塔莉把代码翻到了Game_Interpreter的236行:

RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2. # * Wait
  3. #--------------------------------------------------------------------------
  4. def wait(duration)
  5.   duration.times { Fiber.yield }
  6. end

“这里duration.times就是重复duration那么多次的操作。你看,一个叫做wait的东西,重复了那么多次的Fiber.yield,还不能猜出Fiber.yield是做什么的?”

埃里克恍然大悟:“wait我知道,就是事件里的等待。用N次某个操作组成了等待N帧,那某个操作就是‘等待1帧’了吧。”

娜塔莉点点头:“在这里确实可以理解成等待1帧。准确地说,是暂时退出Fiber上下文,去执行其他内容,等到1帧以后再来继续执行这个Fiber。”[如果想要了解关于Fiber更多的知识,可以看这篇文章的介绍]

“你还是别讲Fiber啊上下文什么的了,我暂且理解成等待1帧没错吧,那为什么是这里会导致出问题呢?”

“并行事件只要在地图上,它就会循环重启执行,这一点你作为事件党,应该很了解吧。”[如果想要了解它的原理,可以参考Game_Event脚本,一直拉到最后就能看到的def update]

“那是当然,我埃里克再怎么说,也是游戏制作勇者啊。”

“可是你发现了吗,你用来判断按键的并行事件,其实不是和游戏帧率一样,每秒60次,而是每秒30次。”

“每秒30次……也就是实际上一次并行事件占用了2帧吗。是不是因为,当到达下一帧的时候原本并行事件该重启了,结果却因为上面多等待了一帧,结果没有重启?这等待的一帧,就是我的键盘‘失灵’的时机?”

“你终于明白了。”娜塔莉笑道,“实际上你每次按键,都是在赌随机数啊。赌你按键的时刻是不是恰好落在执行事件的一帧上。假如落到了等待的一帧,那就没反应啦。所以快改脚本吧。”

“不行,不行。我作为勇者,怎么能认输呢,我偏要用事件的方式,把这个问题解决了。”

“这回你倒是说对了,说不定有什么其他人的脚本,会利用到这条特性呢。那就看看你能用事件搞出什么花样吧。”

只过了片刻,埃里克就找到了解决问题的办法:




果然,这样处理以后,按键就完全流畅了。

那么今天的课后习题就是,为什么这样处理以后按键流畅了呢?上面提到的“多出的一帧”去哪儿了呢?

用到的工程: DeviantEventTutorial1.zip (1.33 MB, 下载次数: 288)

正确答案

评分

参与人数 12+12 收起 理由
indio + 1 精品文章
多啦A户 + 1 精品文章
水野·迪尔 + 1 精品文章
鑫晴 + 1 精品文章
人民卫戍部队 + 1 精品文章
Mayaru + 1 塞糖
Kim_Shyuen + 1 精品文章
W.Q.C. + 1 精品文章
2256538860 + 1 精品文章
迷糊的安安 + 1 终于知道喂什么了

查看全部评分

Lv5.捕梦者 (版主)

梦石
28
星屑
10170
在线时间
4673 小时
注册时间
2011-8-22
帖子
1279

开拓者

2
 楼主| 发表于 2018-4-11 07:44:11 | 显示全部楼层
本帖最后由 ⑨姐姐 于 2018-4-11 07:54 编辑
Mayaru 发表于 2018-4-11 05:20
(哇!瞧我发现了什么!一个野生的九姐姐教程!青蛙味嘎嘣脆,蛋白质是触手的五倍x)
感谢教程~大概理解了 ...


for也是可以的,用法是 for [variable] in [range],比如
RUBY 代码复制
  1. for i in 1 .. 5
  2.   p i
  3. end

就能输出1、2、3、4、5。其中 1 .. 5 表示一个range。

上面的@index表示的是“当前执行事件的过程中正执行到的序号”。@list是事件列表,所以@list[@index]就是从@list中取出当前执行的那一条事件了。while @list[@index],只要当@index不超出@list的范围就能一直循环下去。它的初始值是@list的第一条,应该就是0了。

评分

参与人数 1+1 收起 理由
Mayaru + 1 感谢解答!

查看全部评分

回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-5-6 11:13

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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