Skip to content

触发的本质

概念

定义

触发: 指在某个时机或某个条件下,执行自定义指令。

设计触发: 指为了实现某种功能,专门设计某个时机或某个条件下,执行自定义指令。

**作者我知道这个文档的字很多,****但没办法,内容太重要,老老实实给我看完。w(゚Д゚)w**

快速理解

在设计游戏时我们经常提到”触发”这个词。

之所以提及”触发”,就是因为我们想实现在 某个时机或某个条件 下,执行自定义指令。

1)完整的触发描述

按一下按钮,就触发开门。

语句中 ”按一下按钮” 是时机/条件,”开门” 是执行的自定义指令。

按一上方向键,就触发获得物品。

语句中 ”按上方向键” 是时机/条件,”获得物品” 是执行的自定义指令。

计时器到零时,就触发关门。

语句中 ”计时器到零时” 是时机/条件,”关门” 是执行的自定义指令。

玩家没有装备时,就触发装备界面选择。

语句中 ”没有装备时” 是时机/条件,”装备界面选择” 是执行的自定义指令。

按快进键,就触发跳出当前对话。

语句中 ”按快进键” 是时机/条件,”跳出当前对话” 是执行的自定义指令。

要写一个触发,让小爱丽丝在看见玩家时,立即拉响警报。

语句中 ”小爱丽丝看见玩家时” 是时机/条件,”拉响警报” 是执行的自定义指令。

点击装备装备装备。

语句中 ”点击装备(按钮)” 是时机/条件,”(穿上)装备” 是执行的自定义指令。

有上述的描述可知,完整的触发描述要有 具体时机或具体条件具体自定义指令 两个内容。不管功能是否能实现,首先要把自己的想法和需求描述清楚。

2)不完整的触发描述

想要实现鼠标点击触发

语句中 ”鼠标点击” 是时机/条件,但是自定义指令 缺失。

有没有办法触发激活任务

语句中 ”激活任务” 是自定义指令,但时机/条件 缺失。

我要实现触发剧情

语句中 ”(执行)剧情” 是自定义指令,但时机/条件 缺失。

在特定条件下要能触发机关

语句中 ”触发机关” 是自定义指令,但”特定条件”指代不明,所以时机/条件 缺失。

我要触发玩家失败的结局

语句中 ”玩家失败” 是自定义指令,但时机/条件 缺失。

有上述的描述可知,不完整的触发描述一般都省略了主语和环境,所以这样说就没有把需求描述清楚。
为什么作者我这里要强调完整的触发描述呢?因为我们日常使用的自然语言很难把一件事情描述清楚、描述透彻,而我们设计的触发最终要转换为完整的计算机指令,如果最初的描述就说不准确,那后面的事情全是白搭。

3)触发的本质

触发: 指在某个时机或某个条件下,执行自定义指令。

设计触发: 指为了实现某种功能,专门设计某个时机或某个条件下,执行自定义指令。

触发的本质: 触发的本质就是命题 ,若p则q。

这里的”若p”指某个时机或某个条件,”则q”指执行自定义指令。

命题的概念分为 原命题、逆命题、否命题、逆否命题,由于群友都表示看不懂了(作者我自己也经常绕晕),所以放后面再讲:触发与命题
不管实现 触发 这个过程多么复杂,都不要忘了触发基本定义的两个必要条件:** 某个时机或某个条件**、自定义指令

名词索引

以下你可以按住ctrl键点击下面的词,可以直接定位到想了解的名词:

触发触发 设计触发 触发的本质
触发的表现形式魔兽争霸地图编辑器 星际争霸地图编辑器英雄无敌3地图编辑器 rmmv编辑器
触发设计触发的传递性 触发的拆分方法 触发的套娃方法根据拆分结果找插件 事件页设计与触发套娃
物体触发原理触发(地图界面的定义) 主动方 被动方操作触发 开关触发 区域触发公共事件类插件
触发与命题 原命题 否命题 逆命题 逆否命题开关触发与逆否命题
触发与时间持续触发 单次触发串行设置 并行设置

触发的表现形式

注意,游戏编辑器之间没有高低贵贱之分。游戏编辑器的最终目的是 设计触发,而不是去比谁写的指令好看、谁的UI界面好看。优秀的游戏编辑器之所以优秀,就在于其是否提供了成熟的齐全的 触发 功能体系。
另外,这里介绍的是 游戏编辑器,游戏编辑器不需要写脚本,不需要写代码,直接提供了一套可视化的触发与指令设计。而Godot、Unity、虚幻都是要会写代码才能制作游戏的,那些算 游戏引擎。

魔兽争霸地图编辑器

1)触发的定义

触发:指在某个时机或某个条件下,执行自定义指令。

如下图的编辑器中,通过一个触发器对象,来定义 触发 。

其中,

触发器的“事件”对应 某个时机或某个条件。(图中的英文意思为 地图初始化时 )

触发器的“动作”对应 执行自定义指令。

2)触发的附加条件

编辑器图中间的“环境”为 附加条件。

附加条件的功能其实可以直接转移到动作中进行判定,

如下面的两个图,效果是一样的。

3)简易的触发设置

在游戏编辑器中建立一个单位后,双击单位能配置一些基本属性,

其中就包括掉落物品的设置,这类功能都算作简易的触发设置,

即“单位死亡时,就触发掉落物品”。

星际争霸地图编辑器

1)触发的定义

触发:指在某个时机或某个条件下,执行自定义指令。

如下图的编辑器中,通过一条触发器对象,来定义 触发 。

其中,

触发器的“Conditions”对应 某个时机或某个条件。

(图中的蓝色那一条的英文意思为 玩家没有建筑物时 )

触发器的“Actions”对应 执行自定义指令。

(图中的蓝色那一条的英文意思为 该玩家游戏失败 )

2)触发的附加条件

星际争霸的 触发 是绑定在Player身上的,

下图勾选了All players,

意思为所有8个玩家,只要满足Conditions,就会执行Action,会被执行至少8次。

英雄无敌3地图编辑器

1)触发的定义

触发:指在某个时机或某个条件下,执行自定义指令。

如下图的编辑器中,通过一个事件对象,来定义 触发 。

其中,

事件的“常规”对应 某个时机或某个条件。(游戏中的玩家接触到事件才会触发)

事件的“内容”对应 执行自定义指令。

2)简易的触发设置

在游戏编辑器中建立一个怪物后,双击怪物能配置一些基本属性,

其中就包括宝藏的设置,这类功能都算作简易的触发设置,

即“怪物被击败时,就触发获得资源或宝物”。

同样的,你也可以在地图中放置宝物,双击宝物可以配置守卫,

即”玩家获取宝物时,就触发守卫的战斗”。

英雄无敌的游戏编辑器由于 没有自定义变量、没有自定义开关。所有触发都依赖于 怪物、宝物、资源。所以你会发现编辑器中有一些奇妙的触发设计思路:> 必须访问绿色首领营帐,才能通过绿色边境大门> 必须击败敌人某个英雄,才能通过边境/获得属性、资源、魔法、宝物奖励> 必须给对方某个宝物,你才能通过边境/获得属性、资源、魔法、宝物奖励于是,一些宝物和边境大门,会被用来作为剧情推演用道具来制作游戏。比如:“腐化荆棘缠绕着大门,斩断后会立即长回原样,唯有火神剑能净化它们”。

rmmv编辑器

1)触发的定义(地图界面)

触发:指在某个时机或某个条件下,执行自定义指令。

如下图的编辑器中,通过一个事件对象,来定义 触发 。

其中,

事件的“触发条件”对应 某个时机或某个条件。

事件的“执行内容”对应 执行自定义指令。

图中的事件还有 图像、自主移动、选项 等属性。注意这些属性与 触发 没有关系,只是显示在同一个面板里面了而已。

2)触发的附加条件(地图界面)

编辑器图中的“出现条件”为 附加条件。

附加条件的功能会影响事件页的切换,从而改变事件页对应的 触发 内容。

具体事件页切换原理可以去看看文档:“8.物体 > 独立开关与事件页.docx”。

3)简易的触发设置(地图界面)

地图界面设计中,右键提供了快速创建事件的功能。

这个功能本质上还是建立 事件对象,只不过提供了一些简易创建的模板。

4)触发的定义(战斗界面)

触发:指在某个时机或某个条件下,执行自定义指令。

如下图的编辑器中,通过一个战斗事件,来定义 触发 。

其中,

战斗事件的“条件”对应 某个时机或某个条件。

战斗事件的“执行内容”对应 执行自定义指令。

5)触发的附加条件(战斗界面)

战斗事件没有附件条件设置。

由于战斗事件与敌群的配置一对一,所以只有基本的 触发 功能。

触发设计

触发的传递性

触发的传递性: 若p则q,若q则r,能推导出:若p则r。

触发的传递性其实就是命题的传递性。

传递性的概念很重要,耐心看。

1)触发的传递性(举例1)

从数学角度来看:

“若p则q”:如果三角形的三条边相等,则三角形为等边三角形。

“若q则r”:如果三角形为等边三角形,则三角形的三个角均为60度。

根据上述两个情况,能推导出:

“若p则r”:如果三角形的三条边相等,则三角形的三个角均为60度。

从日常角度来看:

“若p则q”:如果你有一斤黄瓜,黄瓜3块钱一斤,则你能换到3块钱。

“若q则r”:如果你有3块钱,胡萝卜1块钱一斤,则你能换到三斤胡萝卜。

根据上述两个情况,能推导出:

“若p则r”:如果你有一斤黄瓜,则你能换到三斤胡萝卜。

从游戏角度来看:

“若p则q”:如果你有100金币,则能找量子妹购买小爱丽丝蝴蝶结。

“若q则r”:如果你有小爱丽丝蝴蝶结,则能找小爱丽丝换取200金币。

根据上述两个情况,能推导出:

“若p则r”:如果你有100金币,则你能换到200金币。

从上述的推理角度来看,想要实现 ”若p则r”,必须要有中间过程q 。比如,只要量子妹不卖小爱丽丝蝴蝶结,那么你就无法用100金币换到200金币了。

2)触发的传递性(举例2)

你可以将触发的传递性,与独立开关结合起来:

“若p则q”:玩家踩到重力开关上时,就触发独立开关A。

“若q则r”:若独立开关A开启,就执行开门。

根据上述两个情况,能推导出:

“若p则r”:玩家踩到重力开关上时,就执行开门。

实现“玩家脚踩重力开关,就执行开门的事件指令”这个触发功能之后。独立开关A就被这个触发功能占用了,不要和 其他触发 混合使用独立开关A。

3)触发与独立开关

由上图的应用示意,

我们可以将 触发的传递性+独立开关,定义为 触发与独立开关 的关系:

触发与独立开关: 若p则开启独立开关A,若开启独立开关A则r,独立开关A作为中间过程,能实现p到r的触发设计。

触发的拆分方法

1)描述想要的触发

前面介绍了触发的传递性:”若p则q,若q则r,能推导出:若p则r”。

而我们 设计触发 时,先要把想要的描述清楚,(可见前面章节1)完整的触发描述

如下:

我想设计一个触发:玩家踩在重力开关上之后,触发开门的功能。

我想设计一个触发:鼠标点击小爱丽丝后,立即触发小爱丽丝的对话。

我想设计一个触发:小爱丽丝生命值到0后,进入到倒下状态。

我想设计一个触发:小屋持续召唤小怪,小怪数量大于7后,停止召唤。

2)拆分触发

触发与独立开关拆分: 要实现若p则r,可以插入独立开关A作为中间过程,将其变成 “若p则开启独立开关A” 与 “若独立开关A开启则执行r”。

拆分触发是一个重要的 设计触发 的思路,这个思路避免你产生这样的疑问:“我要设计玩家踩脚踏开关就触发开门的功能,和独立开关A有什么关系?”。而是让你产生这样的想法:“为了实现玩家踩脚踏开关就触发开门的功能,我必须先实现脚踏开关触发独立开关A,然后独立开关A触发开门,独立开关A是必要的中间过程”。

3)根据拆分结果找相关插件

我想设计一个触发:玩家踩在重力开关上之后,触发开门的功能。

该触发可以拆分为:

玩家踩在重力开关上之后,触发独立开关A。

若独立开关A开启,则执行开门指令。

前者功能,可以找到对应插件:

Drill_EventPressureSwitch 物体 - 重力开关

后者功能,可以直接自己写,比如直接修改门的独立开关,使其开启。

也可以通过 计数开关插件,让门触发自己的独立开关,切换门的事件页。

Drill_EventMutiSwitch 物体 - 计数开关

这里的拆分与实现,可以直接去 机关管理层 去看看介绍。

我想设计一个触发:鼠标点击小爱丽丝后,立即触发小爱丽丝的对话。

该触发可以拆分为:

鼠标点击小爱丽丝后,触发独立开关A。

若独立开关A开启,立即执行小爱丽丝的对话。

前者功能,可以找到对应插件:

Drill_MouseTriggerEvent 鼠标 - 鼠标触发事件

后者功能,可以直接自己写对话的事件指令即可。

注意,这里介绍的拆分方法,只拆分了一次。拆分一次只能实现比较粗糙的功能。示例中的鼠标触发功能,还有更多功能:鼠标接近能触发响声并且小爱丽丝变色;鼠标离开后能触发小爱丽丝恢复变色;这是将 触发多次拆分 来实现的,具体可以看看后面章节:触发的套娃方法

我想设计一个触发:小爱丽丝生命值到0后,进入到倒下状态。

该触发可以拆分为:

小爱丽丝生命值到0后,触发独立开关A。

若独立开关A开启,执行倒下状态的事件页。

”小爱丽丝生命值到0后,触发独立开关A。” 这个功能暂时没有直接对应的插件。

(写文档时是3.40版本,事件生命触发功能仍然一直遥遥无期)

因此,你只能想想有没有其他的方法来实现这个功能,

比如使用变量,来模拟事件的生命。

然后,事件扣除生命的方法,变成了另一个新的触发需求:

“我要设计一个触发:小爱丽丝受到伤害时,触发变量生命值-1。”

该触发可以拆分为:

小爱丽丝受到伤害时,触发独立开关B。

若独立开关B开启,触发生命值变量-1。

以此类推,触发越分越细,直到最终完成全部功能。

拆分有个坏处:“我现在有一个问题,经过我的思考,把它分解成了两个问题。好了,现在我有两个问题了……”如果没有直接能用的插件,你会发现有一些触发功能,越拆越多。所以,评估一下你想要的触发功能是否真的需要,如果不那么重要的话就放弃吧。

我想设计一个触发:小屋持续召唤小怪,小怪数量大于7后,停止召唤。

该触发可以拆分为:

小怪数量大于7后,触发独立开关A。

若独立开关A开启,停止召唤。

由上面触发可知,开独立开关A就停止召唤,

那么默认没开A的时候,就可以写并行执行召唤小怪的功能。

可以通过 计数开关插件,每个小怪事件身上都带特定钥匙,如果钥匙总数量大于7,就触发独立开关。

Drill_EventMutiSwitch 物体 - 计数开关

召唤小怪的功能,可以使用 事件复制器 实现:

Drill_EventDuplicator 物体管理 - 事件复制器

复制事件后,播放一个召唤的动画效果即可。

啊?什么?你问召唤出来的小怪能攻击量子妹吗?能战斗吗?当然不能啊。目前的版本是3.40,事件攻击事件的功能还不知道什么时候会开坑呢。没办法,游戏设计灵感 永远领先 游戏实际进度。“我有一个绝妙的想法,你看,现有插件能实现这个,能实现那个。但,还差一个插件才能实现……也或许是一个大系统……”

触发的套娃方法

1)套娃定义

根据前面章节介绍的:触发的传递性,我们可以把概念进一步推导:

触发与独立开关: 若p则开启独立开关A,若开启独立开关A则r,独立开关A作为中间过程,能实现p到r的触发设计。

触发与独立开关套娃: 根据触发的传递性,你能将独立开关AB作为中间过程,实现p到r的触发设计。

2)套娃举例

假设,我需要设计一个触发:

玩家踩在重力开关上之后,触发开门的功能,并且开门要有声音。

该触发初步可以拆分为:

玩家踩在重力开关上之后,触发独立开关A。

若独立开关A开启,则执行开门声音+开门指令。

如果开门指令是直接用事件指令实现的,

那么 开门声音和开门指令 放一起没问题,因为两个功能处于同一个事件页。

但是如果开门是通过 计数开关 来实现的,

Drill_EventMutiSwitch 物体 - 计数开关

那么 开门声音和开门指令 就无法放一起了,需要拆分出去。

因为计数开关,要求 重力开关 处于 被按下的事件页状态,它才会触发开门。

那么,我们将 开门声音和开门指令 分离,拆成AB两个独立开关就可以了:

玩家踩在重力开关上之后,触发独立开关A。

若独立开关A开启,则执行开门声音+触发独立开关B。

若独立开关B开启,则执行开门指令(所处事件页有 计数开关钥匙)。

触发情况如下图。

由此,我们可以开始写事件来实现触发了:

“若p则开启独立开关A”:对应重力开关实现的事件页。

“若独立开关A开启,则开启独立开关B”:对应播放开门声音的事件页。

“若独立开关B开启,则执行开门指令”:对应计数开关实现的事件页。

通过上述这种套娃拆分的方式,实现了 开门触发 的功能。

注意,触发“玩家踩在重力开关上之后,触发开门的功能,并且开门要有声音”,

只实现了 开门 这一个触发。

3)多触发的情况

按照我们对重力开关的理解,有开门那肯定还要有关门呀。

那么,我们发现我们实际上要设计的是两个触发功能:

“玩家踩在重力开关之后,触发开门的功能,并且开门要有声音”

“玩家离开重力开关之后,触发关门的功能”

那么,把触发流程都写出来吧,如下图。

为什么关门的条件为 “独立开关A和独立开关B都关闭” ?

因为 事件页条件机制,

如果设置的出现条件为空,那么必须所有独立开关都off,才能切换到开门前的第一页。

事件页机制可以去看看文档:“8.物体 > 独立开关与事件页.docx

因此,为了建立起关门的触发,我们只能在开门触发的基础上,再加新的自定义指令,

触发流程如下图,形成循环。

根据上述流程,需要在事件页第三页,

添加 ”若s,则关闭独立开关A和独立开关B” 的指令。

由于重力开关插件本身提供了 离开自动关闭独立开关A 的功能,

所以我们只需要通过 并行事件 监听独立开关A是否关闭,

若A关闭则一起把B也关了即可。

这也是为什么示例中的重力开关,看起来那么复杂的原因。因为它们纠缠了两个以上的触发功能。

4)事件页设计与触发套娃

总结一下前面章节的内容:

我们是为了实现具体功能,才去设计触发。

触发能够套娃,能拆分成更多的触发。

我们完成了一个触发,发现实际上我们的需求是两个触发。

两个触发的指令纠缠在一起,形成了循环结构,导致我们不太容易理解。

下面,我们从事件页的角度,重新理解我们设计的触发:

事件页条件
1
2独立开关A
3独立开关B

最初的触发拆分是这样的:

玩家踩在重力开关上之后,触发独立开关A。

若独立开关A开启,则执行开门声音+开门指令。

转化为事件页,如下图:

后来,为了播放开门声音,我们将触发拆分成了独立开关AB的过程:

玩家踩在重力开关上之后,触发独立开关A。

若独立开关A开启,则执行开门声音+触发独立开关B。

若独立开关B开启,则执行开门指令。

转化为事件页,如下图:

再后来,我们发现还要实现关门触发,所以有了下面的过程:

玩家离开重力开关上之后,触发关闭独立开关A和独立开关B。

若独立开关A和独立开关B都关闭,则执行关门指令。

转化为事件页,如下图:

二者合并,形成下面的结构:

事件页的跳转控制如下表:

事件页条件描述指令
1关门状态踩重力开关,开启独立开关A。
2独立开关A开门动作发出开门声音。打开B。
3独立开关B开门状态如果A被关闭,立即关闭B、C。

通过事件页,能比较直观地理解 触发与独立开关 的关系。

然而,我们现在又有新的想法:

开门加了开门的声音,那么关门能不能加关门的声音?

于是,我们要设计的是两个触发功能又变了:

“玩家踩在重力开关之后,触发开门的功能,并且开门要有声音”

“玩家离开重力开关之后,触发关门的功能,并且关门要有声音”

既然是关门,那么也按照套娃拆分方法,得出下面的流程:

玩家离开重力开关上之后,触发独立开关C,

若独立开关C开启,则播放关门声音+关闭独立开关A和独立开关B。

若独立开关A和独立开关B都关闭,则执行关门指令。

由于独立开关A和B都被 开门触发 占用了,

所以这里再加个独立开关C来处理关门声音。

最终,形成了下面这种复合触发的流程。

事件页关系如下图。

具体的事件指令、事件页细节,去 机关管理层 看看重力开关的示例即可。

你可以结合文档:“8.物体 > 独立开关与事件页.docx”来理解。

也可以去看看文档:“8.物体 > 大家族-开关.docx”来理解。

正常设计游戏中,其实直接复制粘贴示例中的开关事件就可以了。但是,了解原理很重要。先要知道为什么,才能知道怎么做。

物体触发原理

定义

触发(地图界面的定义): 指某个时机或某个条件下,执行目标事件的事件指令。

地图界面中,事件、事件页、事件指令 三者相互绑定,无法分离。

因此,在地图界面中设计自定义指令,需要先建立一个事件,再执行事件指令。

物体是指 事件/玩家/玩家队员/载具 的统称,详细可以看看文档:“0.基本定义 > 界面.docx

主动方: 指 触发过程 中的主动方,比如 玩家、主动事件。

被动方: 指 触发过程 中的被动方,比如 目标事件。

常见的触发有下面三种,主动方可以不存在。

替身事件/马甲事件: 设计触发时,经常有一些只要执行事件指令的情况。

目标事件并不需要,所以这类事件通常都是一个空图片的事件,放置在地图的角落里。

操作触发

相关插件如下:

◆Drill_PlayerAllowTrigger 互动 - 允许操作玩家触发

◆Drill_PlayerAllowEventTrigger 互动 - 允许操作事件触发

(可以去看看文档:”10.互动 > 关于允许操作触发.docx”。)

操作: 指玩家使用 输入设备 对电脑进行控制的过程。

操作触发: 是指通过 确定键、玩家接触、事件接触 三种方式触发事件指令的过程。

其中,主动方 是玩家,被动方是 目标事件。

允许操作触发: 指一种权限,权限能控制 是否允许 操作触发。

注意,“事件接触”指的是事件接触玩家的情况,不要理解为“事件接触事件”。

操作触发原理如下图。

操作触发 在脚本中就直连事件指令,没有 事件页与独立开关 的中间触发过程,因此没法拆分,没法套娃,没法执行自定义指令。

开关触发

1)定义

传感器类:

◆Drill_EventPressureSwitch 物体 - 重力开关

◆Drill_MouseTriggerEvent 鼠标 - 鼠标触发事件

……

复合传感器类:

◆Drill_EventMutiSwitch 物体 - 计数开关

◆Drill_EventSequentialSwitch 物体 - 序列开关

……

(可以去看看文档:”8.物体 > 大家族-开关.docx”。)

开关触发: 指开关插件提供某个时机/某个条件下,开启目标事件的独立开关。

你可以结合示例中 机关管理层 触发的本质 示例来了解开关触发。

开关插件分为 传感器和复合传感器,如下图。

由于”若p”的条件来源各式各样,比如 鼠标、镜头、多事件之间关系 等,

所以无法确定主动方。

2)开关触发的设计

开关触发都是基于 独立开关切换事件页 而实现执行事件指令。

你可以结合示例中 机关管理层 触发的本质 示例来了解开关触发。

触发与独立开关: 若p则开启独立开关A,若开启独立开关A则r,独立开关A作为中间过程,能实现p到r的触发设计。

触发与独立开关拆分: 要实现若p则r,可以插入独立开关A作为中间过程,将其变成 “若p则开启独立开关A” 与 “若独立开关A开启则执行r”。

触发与独立开关套娃: 根据触发的传递性,你能用套娃的方式将独立开关AB作为中间过程,实现p到r的触发设计。

触发设计方法可以去看前面章节:触发的传递性触发的拆分方法触发的套娃方法这里不再赘述。你也可以先去看看文档:”8.物体 > 独立开关与事件页.docx”。

区域触发

相关插件如下:

◆Drill_CoreOfFixedArea 物体触发 - 固定区域核心

◆Drill_EventAutoTrigger 物体触发 - 固定区域 & 玩家接近 & 条件触发

◆Drill_EventClosingTrigger 物体触发 - 固定区域 & 事件接近 & 条件触发

◆Drill_EventRangeTrigger 物体触发 - 固定区域 & 条件触发

(可以去看看文档:”9.物体触发 > 关于物体触发-固定区域.docx”。)

区域触发: 指在某区域内,则执行目标事件的事件指令的功能。

区域通常有绑定的主动方,比如玩家或事件。也可能不含主动方。

条件触发: 指在某处划定一块区域,目标事件如果在区域内且满足附加条件,则执行目标事件的事件指令。(条件触发可能有主动方,也可能没有主动方。)

如下图,附加条件为”击碎岩石”,如果目标事件能识别”击碎岩石”的触发条件,则目标事件开启独立开关A。

玩家接近触发: 指目标事件进入了玩家的触发区域时,执行目标事件的事件指令。

玩家为主动方,目标事件为被动方。

事件接近触发: 指目标事件进入了主动事件的触发区域时,执行目标事件的事件指令。

主动事件为主动方,目标事件为被动方。

公共事件类插件

相关插件如下:

◆Drill_PlayerTimerTiming 公共事件 - 时间计时器到零时

◆Drill_PlayerRegionTiming 公共事件 - 出入区域时

……

公共事件触发: 指在某个事件或某个条件下,执行公共事件。

注意,公共事件 和 物体触发 是两个大的类别,公共事件不存在主动方被动方,而是直接根据条件执行自定义指令。

触发与命题

这部分概念简单了解原理就好。这部分仔细分析很容易把自己绕晕,但需要思考/理解为什么自己会被绕晕。

定义

触发的本质: 触发的本质就是命题 ,若p则q。

这里的”若p”指某个时机或某个条件,”则q”指执行自定义指令。

(你可以百度 逻辑学名词“命题”来了解)

非: 指否定,指事物的反面。

比如我说 “q”,那么这个反面,叫”非q”,可以记作 ¬q。

(程序脚本里面用的是 !q 表示 非q)

1)非的举例

好了,下面挑战开始了,这里我把答案置灰,

你先只看问题看看能不能得出答案,测一下你的逻辑能力是否在线了哦!

提问:如果q是”人类”,那么¬q是什么?

答案:非人类。

提问:如果q是”等于10”,那么¬q是什么?

答案:不等于10。

提问:如果q是”一定”,那么¬q是什么?

答案:不一定。

提问:如果q是”大于20”,那么¬q是什么?

答案:小于或等于20。

提问:如果q是”负增长”,那么¬q是什么?

答案:增长或零增长。

提问:如果q是”在范围内”,那么¬q是什么?

答案:不在范围内,在范围以外的地方。

提问:如果q是”该来的没来”,那么¬q是什么?

答案:该来的来了。

提问:如果q是”全部都气晕了”,那么¬q是什么?

答案:有至少一个没气晕。

提问:如果q是”都是笨蛋”,那么¬q是什么?

答案:不都是笨蛋,至少有一个不是笨蛋。

提问:如果q是”都不是笨蛋”,那么¬q是什么?

答案:不都不是笨蛋,至少有一个是笨蛋。

提问:如果q是”小爱丽丝不得不去战斗”,那么¬q是什么?

答案:小爱丽丝没有去战斗。

提问:如果q是”小爱丽丝敲打了量子妹”,那么¬q是什么?

答案:小爱丽丝没有敲打量子妹。

提问:如果q是”小爱丽丝被打哭了”,那么¬q是什么?

答案:小爱丽丝没有被打 或 小爱丽丝被打了没有哭。

提问:如果q是”造成了成吨的伤害”,那么¬q是什么?

答案:没有造成伤害 或 造成的伤害没有成吨。

提问:如果q是”开启独立开关”,那么¬q是什么?

答案:没有执行开启独立开关。

提问:如果q是”关闭独立开关”,那么¬q是什么?

答案:没有执行关闭独立开关。

提问:如果q是”小爱丽丝聪明又可爱”,那么¬q是什么?

答案:小爱丽丝不聪明也不可爱 或 聪明但不可爱 或 可爱但不聪明。

怎么样?你答错了几个?

作者我也一样,在这些千奇百怪的 命题/触发 面前,经常犯错。最容易被这些p和非p绕晕了。只有冷静下来慢慢分析,慢慢试错,才能找对答案。

2)原命题、否命题、逆命题、逆否命题

原命题: 若p则q。

否命题: 若p则¬q。

逆命题: 若q则p。

逆否命题: 若¬q则¬p。

其中,原命题 = 逆否命题。原命题成立,则逆否命题必然成立。

即:若p则q = 若¬q则¬p 。

并且,否命题 = 逆命题。否命题成立,则逆命题必然成立。

即:若p则¬q = 若q则p 。

虽然数学逻辑上,原命题 = 逆否命题,否命题 = 逆命题。但是根据前面的章节:1)非的举例,我们其实连日常的 否命题 都很难说清楚,很容易犯错。所以不要认为自己写的触发只要满足 命题的逻辑规则后 就100%正确。小心设计,小心试错。

举个例子:

红色蝴蝶结的小爱丽丝们,全部蹲下。

“p”,指:“红色蝴蝶结的小爱丽丝”。

“q”,指:“蹲下”。

“¬p”,指:“红色蝴蝶结以外的小爱丽丝”。

“¬q”,指:“不执行蹲下”。

原命题 = 逆否命题 即:

”红色蝴蝶结的小爱丽丝,蹲下” = ”没有执行蹲下的小爱丽丝,不是红色蝴蝶结”。

若玩家踩在重力开关上,则开启独立开关。

“p”,指:“玩家踩在重力开关上”。

“q”,指:“开启独立开关”。

“¬p”,指:“玩家没有踩在重力开关上”。

“¬q”,指:“不执行开启独立开关”。

原命题 = 逆否命题 即:

”若玩家踩在重力开关上,则开启独立开关” = ”若开启独立开关没有执行,则玩家肯定没有踩在重力开关上”。

注意,原命题、逆否命题,全都没有提到 ”关闭独立开关”,也就是说这里的命题与 ”关闭独立开关” 完全无关。而且 ”开启独立开关” 的反面,不是 ”关闭独立开关”。所以 ”开启独立开关” 与 ”关闭独立开关” 是两个不同的 命题/触发 。

开关触发与命题

开关触发: 指开关插件提供某个时机/某个条件下,开启目标事件的独立开关。

1)动词的否定

前面章节中,有两个问题,这里需要详细说明一下:

提问:如果q是”开启独立开关”,那么¬q是什么?答案:没有执行开启独立开关。提问:如果q是”关闭独立开关”,那么¬q是什么?答案:没有执行关闭独立开关。

为什么开启的否定,不是关闭?

其实这个短语,省略了主语,加上主语之后,你就会发现问题了:

插件开启独立开关

插件关闭独立开关

这两个句子是典型的 主谓宾结构(名词+动词+名词)。

如果要否定这个句子,那么把 动词否定 就行。

比如:

“你打我” 的否定为 “你没有打我”

“作者我踢掉了群友” 的否定为 “作者我没有踢群友”

“量子妹敲打小爱丽丝” 的否定为 “量子妹没有敲打小爱丽丝”

“小爱丽丝往东走” 的否定为 “小爱丽丝没有往东走”

“插件开启独立开关” 的否定为 “插件没有执行开启独立开关”

换个角度:

“你去开启独立开关。”

“不,我不去”

这个过程,表示我不去做这件事情,而不是 ”我去关闭独立开关” 。

开关类插件的所有触发,都有 开启/关闭 这个动词,如果要否定触发,那么否定的是这个动词这个行为,表示没有去执行。

2)开关触发的命题

由前面章节我们知道,原命题 = 逆否命题,

”开启独立开关” 的反面是 ”不执行开启独立开关”。

那么,我们用 重力开关的触发 实际测试一下:

“若玩家踩在重力开关上,则开启独立开关。”

“p”,指:“玩家踩在重力开关上”。

“q”,指:“开启独立开关”。

“¬p”,指:“玩家没有踩在重力开关上”。

“¬q”,指:“不执行开启独立开关”。

原命题为:若玩家踩在重力开关上,则开启独立开关。

逆否命题为:若未执行开启独立开关,则玩家没有踩在重力开关上。

接下来我们测试一下这个触发:

没踩时,开关没变化,这个符合 逆否命题。

踩了,开关按下,这个符合 原命题。

踩了然后离开,开关仍然处于按下状态,这个符合 “开启独立开关” 执行的结果,因为独立开关开启了,没有任何其他触发把它关闭,所以一直处于按下状态。

经过测试我们发现,“原命题 = 逆否命题” 这个定理在实际 设计触发时,并没有什么帮助。这只能让我们理解为什么 ”开启独立开关” 和 ”关闭独立开关” 是两个不同的触发。

3)开关插件的多个触发

重力开关插件,提供了下面三个 注释。

如果只有一个触发:

” =>重力开关 : 独立开关[A] : 踩住时开启”。

那么我们按下重力开关之后,就不会再弹起了。

所以,一个简单的重力开关,需要两个触发来实现,即:

” =>重力开关 : 独立开关[A] : 踩住时开启” +

” =>重力开关 : 独立开关[A] : 没踩住时关闭”

这样,就实现了 踩住时按下,离开后弹起 的功能了。

另外,插件也提供了逆向触发,能逆向开启/关闭独立开关:

这可以实现 未踩住时,开关处于按下状态,而踩住时,开关反而弹起 的功能。

触发与时间

这部分的概念了解即可,耐心看完即可。前面介绍的所有触发,理论上都默认瞬间执行完毕(1帧内执行完)。但是在实际设计游戏时,很多指令的编写都与触发时间设定息息相关。

持续触发与单次触发

1)持续触发

持续触发: 指连续不断的触发,每帧都会对条件进行监听的触发。

持续触发主要在于实时监听(各种情况的if判断语句),若某一帧情况发生变化,才立即执行触发。

//==============================// * 地图 - 帧刷新//// 说明: > 该函数每帧都会执行1次,每秒则会执行60次。//==============================Game_Map.prototype.update = function( sceneActive ){this.refreshIfNeeded(); //帧刷新 - 请求刷新if( sceneActive ){this.updateInterpreter(); //帧刷新 - 串行解释器}this.updateScroll(); //帧刷新 - 镜头this.updateEvents(); //帧刷新 - 事件容器this.updateVehicles(); //帧刷新 - 载具this.updateParallax(); //帧刷新 - 远景};

以重力开关为例,玩家踩在重力开关上,重力开关保持独立开关A的开启状态。

独立开关A开启只在踩下的那一瞬间会被执行,其它时间都只是在监听重力开关。

如果一直踩住,这是其它事件执行了一个强制指令,把重力开关的独立开关A关闭。

因为玩家一直踩在重力开关上,所以重力开关A在关闭的一瞬间,又被重新开启了。

这就是持续触发的效果。

持续触发的优点 是无论在什么情况下,只要条件发生变化,就能立即触发开启/关闭。

持续触发的缺点 是如果有特殊情况需要处理时,必须先关闭持续触发,等特殊处理执行完毕后才能再开启持续触发。

2)单次触发

单次触发: 指只执行一次指令的触发。

单次触发就是只执行一次的指令,没有实时监听的功能。

在机关管理层中,你会发现 一次性开关 ,旁边有个回复开关事件,这个事件用于关闭独立开关A。

一次性开关执行的是单条指令,与重力开关相似,踩下之后,也开启了独立开关A。

然后独立开关A开启之后就没有被管了。

如果另一个事件执行关闭,那么就一直关闭了。

单次触发的优点 是只考虑某个时间点,在那个时间点的一瞬间执行指令即可。

单次触发的缺点 是无法让事件一直保持开启/关闭状态。当执行开启过了一段时间后,你不好确认它还是不是还处于开启的状态,因为有可能一些特殊情况会干扰开关。

3)实现方式区分

以计时开关为例,示例中的计时开关有开关和灯两个事件。

方法1:用计数开关来实现,灯绑定计数开关触发,按钮的按下事件页绑定钥匙。

如果按钮被按下,灯会自动亮起,过一段时间后,关闭按钮的独立开关即可。

这种实现方式就是通过 持续触发 实现,事件页变化时,灯会根据钥匙数量立即改变。

方法2:直接手动开启/关闭 灯 的独立开关。

如果按钮被按下,手动开 灯 的独立开关,过一段时间后,关闭 按钮和灯的独立开关。

这种实现方式就是通过 单次触发 实现。

通过这两种方式你会发现,使用 持续触发 的方法,写的指令也要少很多。以后点开事件页查看指令时,也更容易理解一些。

插件提供的 持续触发 在设计思路上,省去了一部分设计步骤。

以机关管理层的聚集开关为例,我们只需要让聚集开关归位,就算重置完毕了。

因为我们直到聚集开关就能根据聚集情况自己判断是处于开启/关闭状态。

所以把它们挪开就没事了,不需要管它们的独立开关开启/关闭状态。

以鼠标悬停响应开关为例,持续触发只用绑定一个按钮,而单次触发要两个按钮。

前面章节 3)多触发的情况 已经分析了:满足条件开+不满足条件关 是两个触发。

因此,持续触发之所以只需绑定一个按钮,是因为两个触发合并了而已。

4)性能问题

如果你是游戏设计者,单次触发和持续触发对于你来说没有区别,只是一种可选项而已。有哪种功能,就用哪种,无需多想性能问题。没有的功能,等以后出新插件。如果你是插件开发者,你应该考虑多提供 持续触发 的功能,因为持续触发的性能问题只能通过脚本底层来专门优化,减少时间复杂度。

从脚本层面上来看,单次触发的性能消耗明显要比持续触发少的多。

因为单次触发执行一条指令就够了,而持续触发要每帧都监听变化状态。

但这并不代表插件就可以偷懒,只提供单次触发的插件功能。

因为工作量摆在那,如果不是插件这边来写,那必然会传导到游戏设计者那边来写。

游戏设计者如果有 持续触发 的需求想法,那么他只能用 并行事件指令 来实现。

这种实现方式产生的性能消耗,稍不注意就会比插件要恐怖的多。

作者我提供的持续触发,都是经过数次性能优化,以及各种参数调配的最优结果。

但是性能消耗仍然有40ms左右。

如果这部分让游戏设计者来写,那性能消耗就高到无法想象了。

所以,如果你是游戏设计者,单次触发和持续触发对于你来说没有区别,只是一种可选项而已。有哪种功能,就用哪种,无需多想性能问题。没有的功能,等以后出新插件。

触发的串行与并行

1)串行设置

事件页的触发条件如果为:

确定键、玩家接触、事件接触、自动执行,

那么该事件页的执行内容为串行执行。

串行会阻塞玩家移动,阻塞其他串行事件执行。

串行可以使得所有事件指令按顺序依次执行。

串行有一定的局限性:

如果开关通过串行控制,按下按钮时播放响声,那么这个响声的等待时间,会阻塞玩家移动,并且阻塞其他事件执行。

只有一个开关倒还能接受,但若设计需要边跑边踩的开关,走走停停会非常难受,所以开关这时候会采用 并行处理 的方式来设置指令。

串行会阻塞事件指令,也会拖慢其他触发的执行。如果重力开关被触发,但是由于其他事件正在串行执行,那么重力开关的指令也会被延迟执行。这也就造成了触发的时间差。

2)并行设置

事件页的触发条件如果为:

并行处理

那么该事件页的执行内容为并行执行。

如下图,重力开关按下后,通过并行来实时监听 独立开关A,随时触发重力开关回弹的功能。

并行有一定的局限性:

并行处理会消耗较多的性能。并且并行处理对时间非常敏感,如果并行事件之间容易写出错误的时间点触发错误的功能。

另外,并行处理的执行内容中,如果没有任何 等待帧 指令,则表示每帧都执行一次内容,1秒60帧,如果这些事件数量非常多,则会极大地拖慢游戏的运行速度。

所以并行处理一般都会多等待2帧或3帧,用于减轻计算负担。

并行设置中一般为了优化会多等2帧或3帧,这也造成了触发的执行时间延迟的问题。如果你的一些触发设置对时间特别敏感,那么需要留意并行的等待帧的影响。

触发的先后顺序

1)同一帧的先后顺序

触发的先后顺序,与事件id有关。

假设触发发生在同一帧内,那么:

目标事件id小的触发,会被先执行,

目标事件id大的触发,会被后执行。

想要了解先后顺序的来源,看看作者我写的 开关 的脚本就能知道了。

重力开关会被按照事件顺序存放到 临时容器 中,然后按照容器的顺序依次处理触发。

$gameTemp._drill_EPS_switchTank = []; //重力开关容器var events = this.events();for( var i = 0; i < events.length; i++ ){var temp_event = events[i];if( temp_event == undefined ){ continue; }if( temp_event._erased == true ){ continue; }if( temp_event.drill_EPS_hasAnySwitch() ){$gameTemp._drill_EPS_switchTank.push(temp_event);}}

2)套娃中间过程的等待

前面章节,我们设计了按下重力开关时,播放按下按钮声音,然后才处于按下状态。

播放声音+按下状态的过程中,可以不等待,单看 重力开关 这一个对象,没啥问题。

但是,重力开关+灯 的时候,如果不等待,你会听到 开关声音 和 灯的声音 同时响。

这不符合设计游戏时的常规感受。

所以通常这里会多加一个等待时间,一般5-15帧左右。

注意,添加等待后,那么触发的先后顺序就发生了改变,因为触发过程与执行处于不同的帧。

延迟触发设置(聚集开关)

聚集开关插件中,有一个延迟触发时间的设置:

之所以有这个设置,是因为如果时间为0,聚集开关触发的”太快了”。

比如,消除砖块的关卡设计:

常规思路中,如果我拖动蓝色的蝴蝶结,那么这个方块会下沉到最底部。

但是,下沉的沿路旁边有个蓝色蝴蝶结,

如果聚集开关是立即触发,那么在两个蓝色蝴蝶结接触的一瞬间,它们就粉碎了。

这显然与最初的设计思路背道而驰了。

所以,需要设置延迟的触发时间,确保蓝色蝴蝶结完全停稳后,再判断是否聚集触发。

聚集开关的详细说明,可以去看看:“8.物体 > 大家族-开关.docx”的聚集开关介绍。

注意,消除砖块关卡的下沉过程判断,对帧数要求非常严格,因此不能开“是否优化每帧计算量”,需要通过插件指令手动关闭设置。

触发一体化

这部分的概念了解即可。具体也可以去示例的 体积管理层 看看。

功能来自插件:

Drill_EventUnificationOfTrigger 体积 - 一体化 & 触发

绑定触发一体化后,事件组内的所有事件,能同步触发独立开关。

注意,一体化触发只同步 开启/关闭独立开关。

而开关的触发条件本身,不会因为绑定了一体化触发,而被扩充条件。

详细介绍可以去看看:“27.体积 > 关于事件一体化.docx”。

贡献者

暂无相关贡献者

页面历史

暂无最近变更历史