[UP1.5] 利用AI检测玩家/游戏暂停了多长时间
本帖最后由 newtonerdai 于 2020-7-2 22:11 编辑祖安前言
哦?你问我为什么闲的蛋疼,要检测帝国游戏暂停了多久?!
因为!TM的!老是有玩家不仔细看战役任务栏里的信息,一顿乱操作下来一脸懵逼,回来怒骂作者一通。
所以劳资必须要让这些盲人玩家,先仔细看完任务栏,再给继续操作!
(咳,或者也可以给予一些醒目的提示,让玩家在热血正酣的战斗期间查看新出的任务。)
祖传过渡段
现在Userpatch 1.5的AI已经完全可以做到检测游戏暂停了多久!且看我的慢慢道来↓↓↓
原理讲解
我们需要的语句:up-get-precise-time(直译:获取精确时间)精确到ms。
设计思路:
0、时间戳是什么?
日常生活使用Unix时间戳,如 1593682976434 (ms) = 2020-07-02 17:42:56.434。你可以理解为现实世界的时间转化为一串数字,就是时间戳。不过帝国里时间戳的0点与现实世界里的不是相同的,但时间流速是相同的,大家理解这个概念就行。
(注:下图是用简单的代码获取到的决定版时间戳,具体代码就不放出来了,大家看看效果即可)
1、【核心原理】
我们让AI检测这一瞬间的时间戳,储存为time-1;再在下一瞬间检测时间戳,储存为time-2。
二者之差不就是现实世界经过的时间了吗?其代表的含义不就是【在连续两次AI检测之间,现实世界经过的时间】了吗?
那么,如果玩家暂停了5秒,那么时间戳之差必然>5,因为游戏暂停期间AI的语句也是直接暂停的。
(核心原理示意图。上图中,5175ms = 5000ms + 350ms÷2)
依照上面这个思路,我写了段简单的减法代码,其运行效果如下↓↓↓
(当然,这段代码即使不放出来,也不影响各位的理解。不妨先按捺住好奇心,继续看下去↓↓)
2、不过,倒是也不需要我们再自己做一次减法,因为up-get-precise-time这个语句是自带减法的,就很方便。
3、所以我们只需不断获取上一瞬间的时间戳,然后在下一瞬间用这个语句获取现实时间差,把时间差逐个累加起来,最后判断累计暂停时间是否满足需求即可。
那么,上菜!让我把详细做法端上来吧!
完整做法
触发部分:
触发0||初始开启不循环
效果0||发送AI触发器(旧称事件/信号) 10号
效果1||显示指南99999秒“请认真阅读任务栏……输入99可跳过”
触发1||初始开启不循环
条件0||收到AI信号10号
效果0||显示指南“看来你已了解信息,现在正式开始游戏吧!”
效果1||应答AI信号10号
触发2||初始开启不循环
条件0||收到AI信号11号
效果0||显示指南“看来你已了解信息,现在正式开始游戏吧!”
效果1||应答AI信号11号
当然,触发1 & 触发2、AI信号10号 & 11号的功能相同,是可以合并的。具体你们可以自己设计。
AI部分:
;///////////////////////////////////////////////////////////
;// 暂停时长检测模块 //
;///////////////////////////////////////////////////////////
(defconst time-1 100) ;用于目标变量编号。储存前一次检测的时间戳。
(defconst time-2 101) ;用于目标变量编号。储存两次检测的现实时间差。
(defconst time-sum 102) ;用于目标变量编号。储存累计暂停时长。
(defconst cheak-switch 103) ;用于目标变量编号。储存模块的开关状态。
(defconst ON 1) ;用于常数。代表模块开启。
(defconst OFF 0) ;用于常数。代表模块关闭。
;———————— 模块的激活与初始化 ————————
;收到10号事件后,初始化模块。
(defrule
;↓↓ 收到触发的10号事件后,模块激活,并初始化。(注意,这条规则有自锁,并不会持续执行)
(event-detected trigger 10)
=>
;↓↓ 模块开始时,获取当前时间戳作为time-1。
; 如果不这么做,那么接下来第一次得到的 time-2 将为:(时间戳+1),显然太大了,会被误判为暂停的。
(up-get-precise-time 0 time-1)
;(up-chat-data-to-all "当前时间戳 = %d" g: time-1)
;↓↓ 启动“暂停时长检测”模块。
(set-goal cheak-switch ON)
;↓↓ 启动模块时,将累计暂停时长归零。
(set-goal time-sum 0)
;↓↓ 注销10号事件,使其可以重复使用。
(acknowledge-event trigger 10)
)
;—————————— 获取部分 ——————————
;在检测启动期间,不断获取两次检测之间经过的现实时间差。
(defrule
(goal cheak-switch ON)
=>
;↓↓ 获取现实时间差,储存到time-2里。
(up-get-precise-time time-1 time-2)
;↓↓ 完事后,储存本次检测的时间戳,用于下次检测。
(up-get-precise-time 0 time-1)
;↓↓ 向所有人报告time-1的数值,用于检查。
;(up-chat-data-to-all "当前时间戳 = %d" g: time-1)
;↓↓ 向所有人报告time-2的数值,用于检查。
;(up-chat-data-to-all "距上次检测经过了 %d ms"g: time-2)
)
;—————————— 累加部分 ——————————
;为了防止AI遍历间隔的干扰,同时也考虑到玩家阅读任务应该会久一点,我们应该只累加2秒以上的暂停时长。
(defrule
(goal cheak-switch ON)
(up-compare-goal time-2 c:> 2000)
=>
;↓↓ 把time-2加到time-sum里。
(up-modify-goal time-sum g:+ time-2)
)
;—————————— 模块的关闭 ——————————
;模块启动期间,如果time-sum > 5000 ms,就判定玩家暂停了5秒钟。告知触发,同时暂时关闭“暂停时长检测”模块。
(defrule
(goal cheak-switch ON)
(up-compare-goal time-sum c:> 5000)
=>
;↓↓ 向所有人报告,用于检查。
(chat-to-all "【暂停了 5 秒以上】")
;↓↓ 发送10号AI信号,告知触发。(注:AI信号与AI事件是互相独立的)
(set-signal 10)
;↓↓ 关闭“暂停时长检测”模块。
(set-goal cheak-switch OFF)
)
;无论何时,只要玩家 1 发送数字“99”,都会关闭“暂停时长检测”模块。同时告知触发。输入99表示玩家很熟悉了,不想看任务栏而是直接跳过。
(defrule
(taunt-detected 1 99)
=>
(set-goal cheak-switch OFF)
;↓↓ 发送10号AI信号,告知触发。
(set-signal 11)
;↓↓ 应答这个数字嘲弄,使其可循环使用。
(acknowledge-taunt 1 99)
)
运行效果如下:
开局提示:
暂停累计5秒以上:
输入99跳过:
我顺便测了一下DE的AI遍历间隔:
游戏负荷极小(比如就几十行代码+一两个单位)的情况下,基本稳定在0.350~0.400现实秒,偶尔会低或高,无论是什么游戏速度。
另外,UP1.5的似乎也是这样。 Problem unsolved.
玩家在這種情況下有可能只是暫停10秒、打開外交選項10秒、打開遊戲設定10秒、打開科技樹10秒等。
就是沒有打開任務欄。{:164:}
要對付盲人玩家,你可以有100種方法,但他們會有200種盲法。
本帖最后由 blazefires 于 2020-7-3 02:35 编辑
多人游戏模式和延迟也都会影响结果
单机60FPS下都是约0.4秒一次 troytroytroy 发表于 2020-7-2 23:17
Problem unsolved.
玩家在這種情況下有可能只是暫停10秒、打開外交選項10秒、打開遊戲設定10秒、打開科技樹 ...
甚至可能不熟悉文明特性,现翻科技树。 如果为了表现有配音的对话,让他们不因为游戏速度差异而导致配音交叠或间隔大的问题,这个东西能解决吗? 本帖最后由 newtonerdai 于 2020-7-12 00:46 编辑
HudsonLee 发表于 2020-7-11 18:30
如果为了表现有配音的对话,让他们不因为游戏速度差异而导致配音交叠或间隔大的问题,这个东西能解决吗? ...
检测游戏速度的方法,我记得论坛有一个贴子讲过。你可以去搜搜,我得先下线了。
其实AI是可以获取当前游戏时间的。
理论上,通过对比游戏时间差 和 现实时间差,是可以获知游戏速度的 本帖最后由 HudsonLee 于 2020-7-24 22:48 编辑
测试了一下,检测暂停次数转换为变量
https://www.bilibili.com/video/bv1wz4y1Q7d3
页:
[1]