两个红色按钮,烙铁和React:我们如何推动IT会议

Badoo经常通过展位参加IT会议的展览。 因此,每年,我们都会与同事-工程师和精疲力竭-一起做一件事情,做一件好事,以免在报告之间感到无聊。


我叫Ivan,我是前端开发人员。 在本文中,我们将与我们的同事和DIY爱好者lilek Yura Lilekov一起,向您介绍如何使用两个红色按钮,一个微控制器,一个React代码和250个有关IT主题的单词,制作出“ IT猜测游戏”游戏,并在Highload ++上进行舒适的聚会和Heisenbug。



内容:


不平凡的传统知识
游戏机制和得分
动画制作
前端
硬件:两个红色按钮
结果


不平凡的传统知识


IT会议有自己的氛围:有很多人,要吸引和吸引他们的注意力并不容易。 为了使他们能够在两次报告休息之间准确地来找我们,我们需要为他们提供有趣但简单的课程。


受到去年IT别名成功的启发,我们对新游戏制定了以下要求:


  • 它必须是多用户。 参与者的沟通是主要任务。 我们知道,有许多人独自一人,并不总是很容易与陌生人对话。 游戏应该给彼此和与Badoo工程师交谈的机会。
  • 会议时间应简短。 会议可能有1-3千人,我们希望尽可能多地吸引与会人员。
  • 游戏应该是壮观的。 如果一个人不参加游戏,那么至少让他观看。 这激发了兴趣,有助于理解本质并决定参与。
  • 最简单的管理。 众所周知,如果某些东西可以破裂,那肯定会破裂。
  • 无需注册和短信!

经过集思广益,在梦中进行思考并尝试获得灵感,我们提出了“ IT猜谜游戏” —一个简单的游戏,上面写有有关IT主题的文字。



的本质是什么:


  • 两个参与者同时玩。
  • 任务是比对手更快地按下按钮,然后猜测屏幕上显示的加密单词。
  • 分为两个阶段:简单的(“快捷方式”),将单词写回到最前面;困难的阶段(“ Stirrers”),将单词中的所有字母混合在一起。
  • 如果答案是正确的,则计分到响应者。 错误-比分归于对手。
  • 得分至少为N分的人可以参加降噪耳机的抽奖。

看起来一切都很简单,但困难重重。


游戏机制和得分



从此gif来看,很明显,舍入过程是什么样的:


  1. 出现一个加密的单词。
  2. 计时器开始10秒钟。
  3. 如果其中一个玩家按下按钮,则此计时器停止,而另一个计时器开始-3秒钟。 在这段时间内,必须给玩家一个答案,否则分数将记入对手。
  4. 如果没有人按该按钮,则单词会自动更改,然后再次重复整个过程。

我们面临的主要问题是如何保持得分和记录球员。 我们希望使游戏尽可能快,而不是迫使参与者在任何地方注册。 但是,有必要了解其中的哪些人得分达到一定数量并可以得到主要奖励。


我们不是第一次提出计算机制。 经过几次测试,才变得清楚如何使游戏变得既方便又简单-无论是对于参与者还是对于主持人。


失败的想法


想法#1:1分= 1小块巧克力


对于每个正确答案,首先我们决定提供一个巧克力棒。 最后,参与者带来了巧克力(或者至少从被吃掉的“要点”中拿出糖果包装纸),就这样! 我们计算奖杯,我们认识赢家。


但是有几点。


第一:不方便。 事实证明,适度游戏并同时计算积分是不可能的;需要第二个助手。 就摊位上的人的力量和时间而言,这太昂贵了。 考虑到游戏的速度,我将不得不向参与者扔巧克力。


第二点-如何区分我的巧克力和其他人的巧克力? 玩家可以合作并从中堆叠巧克力或糖果包装。 因此,电路不起作用! 此外,会议为期两天,您可以无休止地收集巧克力。


第三点:您需要太多巧克力。 我们通过实验检查了一个普通玩家的得分,并意识到至少一辆货车需要巧克力。 而且我们只有一个小推车。



想法#2:排名


一些人在比赛时,其他人将自己记录在积分榜中。 在这种情况下,我们将遇到所有可能的问题:同名,同名,书写错误,书写不清(或需要放置另一台大型显示器和笔记本电脑进行输入),不愿离开您的联系人等等。


因此,我们继续搜索。


想法3:参与者徽章上的标记


为了解决注册玩家的问题,我们使用了现成的解决方案:将徽章分发给所有参与者。 这是没有人会失去的,每个参与者都有。 我们决定直接向他们写一个帐户。 参与者来计数,看了徽章,数了点并确定了获胜者。 但是这个计划也有一个陷阱:玩家可以“伪造”徽章上的最终分数。


然后我们完全放弃了记录分数的想法。 让获得积分阈值的人在徽章上获得特殊标记-以我们内心的形式邮票-他们进入了“选择的”圈子。 在这些参与者之间,我们将随机抽取主要奖项。 其余的人仍然会收到礼物:我们的贴纸,笔记本,持卡人和决策者。


当然,Badoo员工没有参加赠品。
当然,Badoo员工没有参加赠品。


该方案如下:


  1. 访客在徽章上标记有参与标记:黑色代表达到20分,紫色代表参加比赛。 一天可以进行三次尝试,并获得三颗心。
  2. 所有带有黑色标记的获奖者都将在特定时间聚集在展台上,借助温暖的电子管抽奖鼓,我们在他们之间播放耳机。


在对有生命的人进行游戏测试之后,我们计算了阈值:在游戏中获得20分并非易事。 但是在两天的Highload ++中,大约有15个人是赢家!


的确,在单词列表中,有很多术语是开发人员首先理解的,因此对于Heisenbug QA会议,我们同意将阈值定为15分。 也许是徒劳的:准决赛者竟然增加了很多倍,这意味着赢得耳机的机会更少了。


PS在开始阶段,我们认为答案错误将使参与者失去巧克力棒得分。 但是没有人喜欢被抢劫。 “这是我的巧克力棒,我赚了!”-最初的游戏测试人员都很愤慨。 因此,作为惩罚,我们开始为对手加分。



动画制作


猜词应以某种动画形式出现。 这给了我们两个好处:


  1. 单词之间的一种“跳动”。 如果玩家之间有任何动作,则从一个单词切换到另一个单词要容易得多。 记住旧的格斗游戏。 每个新回合都以“ 3..2..1..FIGHT!”开始。 我不想在这里再做一个计时器-我们已经批量使用了。
  2. 视觉多样性。 我们试图使游戏尽可能简单,我们没有动画背景和关卡之间的过渡。 我们也不能使用声音,以免干扰其他会议参与者。 因此,动画是必要的。

有了她,并不是一切都马上顺利进行。 在测试运行中,有些狡猾的家伙没有等待动画的结束,而是更早地单击了按钮。 为了教授这些技巧,当一名玩家过早按下按钮时,我们开始阻止单词出现。 单词的尚未出现的部分,在这种情况下仍隐藏在字符后面。 无论玩家是否想要,他都必须回答。 很难用几个字母猜出一个单词,所以对手得了分。


如果您提前单击按钮,则单词的外观如下:



第二个困难时刻是动画的持续时间。 它总是持续相同的时间-1.5秒。 如果您“赶上节奏”,那么您可以比对手更快地获得按下按钮的快感。 为了解决该问题,我们添加了一个0到500 ms的随机变量。 在这种情况下,调整节奏变得更加困难。


前端


我会告诉您一些有关软件部分的信息。 如果您不感兴趣,请直接看一下我们如何搜索红色按钮故事


事实证明游戏的机制很简单,我不想重新发明轮子。 为客户端使用了create-react-app 。 但是仍然需要挑战。


如此钩! 挂钩已经出现很长时间了,但是它们在Badoo主要产品中的应用需要对开发过程进行认真的重新思考。 一个小的附带项目是使用它们的绝佳跳板。


没有redux! Redux是一件伟大的事情,我们每天在工作中使用它。 但是对于如此小的应用程序,使用redux是不合理的。 此外,还有一个新的useContext挂钩。


 const { score, changeScore } = useContext(SessionContext); const { next } = useContext(QuestionsContext); const steps = useContext(StepsContext); 

是的,我们得到了三个根本不相交的上下文,而不是一个全球性的故事。


SessionContext得分。
StepsContext负责切换应用程序屏幕:简介,循环,结尾...
QuestionsContext上下文了解所有问题:回答了哪些问题,接下来是哪个问题,还剩下多少。


提供者


每个上下文都需要一个提供程序,它将提供数据到最终组件。 例如,我们将使用一个简单的提供程序进行评分。


 const increment = score => score + 1; const SessionProvider = props => { const [leftPlayerScore, changeLeftPlayerScore] = useState(0); const [rightPlayerScore, changeRightPlayerScore] = useState(0); const resetScore = useCallback(() => { changeLeftPlayerScore(0); changeRightPlayerScore(0); }, []); const changeScore = useCallback(player => { player === 'left' ? changeLeftPlayerScore(increment) : changeRightPlayerScore(increment); }, []); const score = { left: leftPlayerScore, right: rightPlayerScore }; return ( <SessionContext.Provider value={{ score, changeScore, resetScore }}> {props.children} </SessionContext.Provider> ); }; 

从代码中可以看到,我们独立跟踪点。 “左”玩家和“右”玩家有单独的状态。 以及管理帐户的功能:重置帐户并进行更改。


生成的提供程序API非常简单。 通常,几乎所有与提供程序相关的逻辑都非常简单,因此我们将不再关注它。


计时器


游戏主轮的组成部分很有趣:其中有不明确的时刻。 两种模式(反向和随机播放-“快捷方式”和“混音器”)的组件均相同。


从这一轮的描述中可以明显看出,时间之间存在很多互动。


首先,有一个计时器负责屏幕上单词的持续时间:按下按钮需要10秒。 如果没有人按下按钮,下一个单词将自动出现。


其次,一个计时器在一个玩家单击按钮时启动。 然后,他有3秒的时间来猜单词。


似乎没有什么复杂的,所以我们编写了看似显而易见的代码:


 const [time, nextTick] = useState(0); useEffect(() => { let id = setInterval(() => { nextTick(time + 1); }, 1000); return () => clearInterval(id); }, []); 

但是,您可以猜测,这没有用。 根本没用!


计时器达到1并停止在该位置。 事实是旧time值已“锁定”在处理程序的函数内部。 因此,对于每个刻度, setInterval指的是从第一个渲染开始的time值。


解决了使用函数而不是直接值的问题:


 nextTick(currentTime => currentTime + 1); 

是的,这样我们对计时器始终拥有一个“新鲜”值。 但是,例如,我们无法获得“新鲜” props


显然,必须找到一种不同的方法。 最确定的决定是使处理函数可变。 React useRef有一个特殊的useRef钩子。


大多数情况下,它用于处理DOM元素,但这并不是其唯一的应用。 我们可以“记住” current属性中的任何变量,并在每次渲染时对其进行更新。


 function callback() { setCount(count + 1); } useEffect(() => { savedCallback.current = callback; }); useEffect(() => { function tick() { savedCallback.current(); } let id = setInterval(tick, 1000); return () => clearInterval(id); }, []); 

Dan Abramov有一篇很好的文章介绍了如何使用setInterval和React钩子: 使用React Hooks使setInterval声明式 。 他完美地描述了useInterval挂钩的实现的所有陷阱和思考的所有阶段,我们将其用作解决问题的方法。


由于摊位在整个会议期间都是开放的,因此使用该游戏进行的连续会议非常多。 该页面根本没有更新(F5),因此在开发阶段监视内存非常重要。 如您所知,泄漏与计时器是并存的,如果所有这些都通过重新渲染反应来进行,那么编写吃掉非常多内存的代码将非常容易。


在一个游戏会话中, Countdown开始,停止,重置并重新启动了数十次(也许数百次)。 为了不打扰检查工作,检查工作本来应该很多,所以我们使用了一个非常简单的“技巧”-在此组件中添加了关键道具。


 <QuestionCountdown key={question.text} onComplete={nextQuestion} /> 

我们不会对此进行详细介绍,仍然使用相同的Dan Abramov: React作为UI Runtime来详尽描述反应的协调过程。


硬件:两个红色按钮


因此,我们已经满足了游戏的一些要求:它是多人游戏,速度快,而且机制简单。 它仍然增加了她的娱乐性。 故事之后将是Yura Lilekov lilek-我们的DIY爱好者,社区常任发言人,机翼和其他“自己动手”设备的创作者。


我们真的很想找到两个大型机械按钮。 并确保红色-如与Agutin的模因一样。


不幸的是,在线商店中发现的所有东西都太小(直径5厘米)或根本没有按钮。 当然,有一个很好的旧的速卖通,但是没有时间等待交货。


结果,我们在广告素材代理商的网站上找到了正确的按钮。 亚历山大在郊区的某个地方做过按钮(显然是无线电电子学院的毕业生)。 我们打电话,询问将哪个微控制器缝入盒子,并要求保留对其的访问权限,因为我们需要对其进行重新编程。


坦率地说,亚历山大对这些问题感到惊讶。 当我们问这些按钮是否能承受热情的程序员的压力时,他向我们保证,这些按钮位于“ Cosmic”中的老虎机中,可以完美地应对孩子们的流动。 展望未来,我要说的是,热情的工程师们也保留了这些按钮(只需要更换一次电池)。



馅料


但是,不幸的是,完成的设备并没有我们需要的所有质量。 而且,如果仍然可以通过断开扬声器的导线来消除声音效果,那么自动确定按下了哪个按钮并不是一件容易的事。 一个简单的建议是:将设备连接到计算机,然后将这些按钮的按下转换为键盘上的击键。


该解决方案毫不费吹灰之力-拿起旧的USB键盘,并通过键盘将几个带有附加导线的按钮从键盘连接到设备-立即被取消为“集体农场”。 并接上了DIY的力量。


经过深思熟虑,我们决定使用基于Atmel AVmel系列ATmega32u4微控制器的Arduino Pro Micro板,并进行必要的绑定。 在该板上,I / O和MicroUSB端口分开。 最重要的是-ATmega32u4微控制器可以充当HID设备,在我们的情况下,即在某些条件下模拟按键。


(图片是从AliExpress.com的一位卖家拍摄的


要对该微控制器进行编程,您只需要通常的MicroUSB线和Arduino IDE开发环境即可。


安装开发环境后,最简单的代码示例将立即可用。


例如,位于下面的程序可以模拟在按下按钮(连接到输入/输出端口)时在键盘上打字:


文件->示例-> USB->键盘-> KeyboardMessage


击键的模拟非常简单地实现:


 #include "Keyboard.h" //      void setup() { Keyboard.begin(); //   } void loop() { Keyboard.print("Test"); //   4  delay(1000); //   1  } 

读取输入端口状态也不是多余的事情:


 int button_pin = 7; //  ,     void setup() { pinMode(button_pin, INPUT); //     } void loop() { if (digitalRead(button_pin)) { //   } else { //    } } 

由于端口是通过电压而不是电流打开的,因此从按钮到端口的电线中的最小感应电流会产生误报。 因此,我们建议使用高阻电阻器“拉”输入端口:感应电流会立即流过它,进入“地”,防止输入和“地”之间出现高电压差,因此不会出现误触发。 为了这些目的,一个5-10kΩ的电阻就足够了,该电阻连接在微控制器的输入与其“地”之间。


因此,我们得到以下方案:



通过microUSB的Arduino Pro Micro开发板通过游戏的软件部分连接到笔记本电脑,两个按钮连接开发板的两个输入和常规电源。 另外,这两个输入被两个电阻器拉至地。


当按下其中一个按钮时,来自板的电源输出通过按钮的电流将流至板的相应输入-因此我们将在输入处看到一个逻辑“单位”。


在软件部分,我们决定模拟击键“左箭头”和“右箭头”,并在确定按下后还给出4秒钟的延迟,以避免参与者反复单击或按钮中的联系人嘎嘎作响。


 #include <Keyboard.h> char leftKey = KEY_LEFT_ARROW; char rightKey = KEY_RIGHT_ARROW; int btn1pin = 7; int btn1value = 0; int btn2pin = 8; int btn2value = 0; void setup() { pinMode(btn1pin, INPUT); pinMode(btn2pin, INPUT); Keyboard.begin(); } void loop() { btn1value = digitalRead(btn1pin); btn2value = digitalRead(btn2pin); if (btn1value == 1 && btn2value == 1) { //    =    } else if (btn1value == 0 && btn2value == 0) { //    =    } else if (btn1value == 1) { //    =       4  Keyboard.press(leftKey); delay(100); Keyboard.releaseAll(); delay(4000); } else if (btn2value == 1) { //    =       4  Keyboard.press(rightKey); delay(100); Keyboard.releaseAll(); delay(4000); } } 

因此,借助简单的设备,我们教会了按钮以识别比对手更快地单击它们的玩家,并向演示者发出信号。


管理学


完全手动且尽可能简单:


  • 空间 -下一个字
  • 输入 -显示正确的单词
  • + -正确(1分)
  • 0-错误(指向对手)
  • 左移 -下一步
  • 右移-上一步

结果


在Badoo展位的所有为期四天的会议(两场在Highload ++上,两场在Heisenbug上)持续播放“ IT猜测游戏”。 我们所有的希望都实现了:


  • 这场比赛吸引了参与者和观众:一排排的人聚集在展位上。 在会议的第二天,参加人数没有减少,这是特别令人愉快的。
  • 按钮是最重要的! 加100兴奋。 即使竞争对手彼此之间是陌生人,游戏也引起了很多情绪。
  • 在徽章上带有标记的想法行得通:毫不费力地找到获奖者并收集联系人。 几个人要求保持徽章清洁,因此我们在手腕上做了标记(它们很容易擦除)。
  • 我们分发了14对耳机和几百个小礼物。 没有人没有礼物!


为了参加会议上的游戏,我们赠送了很酷的商品

决策者如痴如醉。 不知道该如何处理任务-旋转魔术盘! 由于分发了所有内容,我们只剩下了几张照片:



对于质量检查工程师



对于开发人员


IT预测性Cookie
自己发明了预测(52种选择)。 实现可能性高达100%。



Source: https://habr.com/ru/post/zh-CN482028/


All Articles