Badoo secara teratur berpartisipasi dengan stan dalam pameran konferensi TI. Karena itu, setiap tahun, kami, bersama kolega - insinyur dan devrels - datang dengan sesuatu untuk melakukan hal yang baik sehingga tidak bosan di sela-sela laporan.
Nama saya Ivan, saya pengembang frontend. Dalam artikel ini, bersama dengan kolega kami dan penggemar DIY lilek, Yura Lilekov, kami akan memberi tahu Anda bagaimana, menggunakan dua tombol merah, satu mikrokontroler, kode Bereaksi dan 250 kata untuk topik-topik TI, kami membuat game "IT guessing game" dan membuat hangout yang nyaman di Highload ++ dan Heisenbug.

Konten:
TK nontrivial
Mekanika game dan penilaian
Animasi
Frontend
Perangkat keras: dua tombol merah
Hasil
TK nontrivial
Konferensi IT memiliki atmosfer mereka sendiri: ada banyak orang, tidak mudah untuk menangkap dan mempertahankan perhatian mereka di mimbar. Agar mereka datang kepada kami secara tepat di sela-sela laporan, kami perlu memberi mereka pelajaran yang menarik tetapi tidak rumit.
Terinspirasi oleh keberhasilan alias TI tahun lalu, kami merumuskan persyaratan berikut untuk permainan baru:
- Itu harus multi-pengguna. Komunikasi para peserta adalah tugas utama. Kita tahu bahwa banyak yang datang sendirian dan tidak selalu mudah memulai percakapan dengan orang asing. Permainan harus memberi kesempatan untuk berbicara satu sama lain dan dengan insinyur Badoo.
- Sesi harus singkat. Mungkin ada satu hingga tiga ribu orang di konferensi, dan kami ingin menjangkau sebanyak mungkin peserta.
- Gamenya harus spektakuler. Jika seseorang tidak berpartisipasi dalam permainan, maka biarkan dia setidaknya menontonnya. Bunga ini menarik, membantu untuk memahami esensi dan memutuskan untuk berpartisipasi.
- Manajemen yang paling sederhana. Seperti kita semua tahu, jika sesuatu bisa pecah, maka itu pasti akan pecah.
- Tanpa registrasi dan SMS!
Setelah melakukan brainstorming, berpikir dalam mimpi dan mencoba mendapatkan inspirasi, kami menemukan "IT Guessing Game" - permainan sederhana dengan kata-kata tentang topik-topik TI.

Apa inti dari:
- dua peserta bermain secara bersamaan.
- Tugasnya adalah menekan tombol lebih cepat dari lawan dan menebak kata terenkripsi yang ditampilkan di layar.
- Dua tahap: sederhana ("Pintasan"), di mana kata-kata ditulis kembali ke depan, dan yang sulit ("Pengaduk"), di mana semua huruf dalam kata-kata dicampur.
- Jika jawabannya benar, satu poin dihitung ke responden. Salah - skor jatuh ke lawan.
- Mereka yang mencetak setidaknya N poin dapat berpartisipasi dalam pengundian headphone yang membatalkan kebisingan keren.
Tampaknya semuanya cukup mudah dan sederhana, tetapi kesulitan ada di depan.
Mekanika game dan penilaian

Dari gif ini, cukup jelas seperti apa proses putarannya:
- Kata terenkripsi muncul.
- Timer mulai selama 10 detik.
- Jika salah satu pemain menekan tombol, maka penghitung waktu ini berhenti, dan yang lain akan mulai - selama 3 detik. Selama waktu ini, pemain harus diberi jawaban, jika tidak skor akan diberikan kepada lawan.
- Jika tidak ada yang menekan tombol, kata akan berubah secara otomatis, dan seluruh proses diulangi lagi.
Masalah utama yang kami hadapi adalah bagaimana menjaga skor dan merekam pemain. Kami ingin membuat game secepat mungkin dan tidak memaksa peserta untuk mendaftar di mana saja. Tapi itu perlu untuk memahami mana dari mereka yang mencetak sejumlah poin dan dapat menerima hadiah utama.
Kami tidak menemukan mekanika perhitungan pertama kali. Hanya setelah beberapa tes, menjadi jelas bagaimana membuat game ini nyaman dan sederhana - baik untuk para peserta dan untuk tuan rumah.
Gagasan yang gagal dan cemerlang
Gagasan # 1: satu poin = satu batang cokelat kecil
Untuk setiap jawaban yang benar, pada awalnya kami memutuskan untuk memberikan satu batang cokelat. Pada akhirnya, peserta membawa cokelat (atau setidaknya bungkus permen dari "poin" yang dimakan), dan hanya itu! Kami menghitung piala, kami mengenali pemenangnya.
Tetapi ada beberapa poin.
Pertama: tidak nyaman. Ternyata tidak mungkin untuk memoderasi permainan dan secara bersamaan menghitung poin, asisten kedua diperlukan. Ini terlalu mahal dalam hal kekuatan dan waktu orang-orang di stan. Dan mengingat kecepatan permainan, saya harus benar-benar melempar cokelat kepada para peserta.
Poin kedua - bagaimana membedakan cokelat saya dari cokelat orang lain? Pemain bisa bekerja sama dan menumpuk cokelat atau pembungkus permen dari mereka. Jadi, sirkuit tidak berfungsi! Selain itu, konferensi berlangsung selama dua hari, dan Anda dapat mengumpulkan cokelat tanpa henti.
Poin ketiga: Anda membutuhkan terlalu banyak cokelat. Kami secara eksperimental memeriksa berapa poin skor pemain rata-rata, dan menyadari bahwa setidaknya sebuah kereta membutuhkan cokelat. Dan kami hanya memiliki kereta kecil.

Gagasan # 2: klasemen
Sementara beberapa bermain, yang lain akan merekam diri mereka di klasemen. Dalam hal ini, kami akan menghadapi semua masalah yang mungkin terjadi: nama, nama, kesalahan penulisan, penulisan tidak terbaca (atau kebutuhan untuk menempatkan monitor besar dan laptop untuk input), keengganan untuk meninggalkan kontak Anda, dan banyak lagi.
Karena itu, kami terus mencari.
Gagasan # 3: tanda pada lencana peserta
Untuk menghilangkan masalah mendaftar pemain, kami menggunakan solusi siap pakai: lencana yang dibagikan kepada semua peserta. Ini adalah sesuatu yang tidak akan ada yang kalah dan yang dimiliki setiap peserta. Kami memutuskan untuk menulis akun langsung kepada mereka. Peserta datang ke penghitungan, melihat lencana, menghitung poin dan menentukan pemenang. Tetapi ada juga kelemahan dalam skema ini: para pemain bisa "memalsukan" skor akhir pada lencana mereka.
Kemudian kami benar-benar meninggalkan ide untuk mencatat skor. Biarkan mereka yang mendapatkan nilai ambang poin menerima tanda khusus di lencana - cap dalam bentuk hati kita - bahwa mereka melewati lingkaran "yang terpilih". Dan di antara para peserta ini kami akan secara acak menarik hadiah utama. Dan sisanya masih akan menerima hadiah: stiker, buku catatan, pemegang kartu, dan pembuat keputusan kami.

Tentu saja, karyawan Badoo tidak berpartisipasi dalam pemberian.
Skemanya adalah sebagai berikut:
- Seorang tamu ditandai pada lencana dengan tanda partisipasi: hitam untuk mencapai 20 poin atau ungu hanya untuk bermain. Tiga upaya dapat dilakukan sehari dan tiga hati diperoleh.
- Semua pemenang dengan tanda hitam berkumpul pada waktu tertentu di stand, dan dengan bantuan drum lotre tabung hangat kami memainkan headphone di antara mereka.

Setelah menguji permainan pada orang yang hidup, kami menghitung tanda ambang: untuk mencetak 20 poin dalam permainan itu tidak mudah. Tetapi dalam setiap dua hari Highload ++, sekitar 15 orang adalah pemenangnya!
Benar, dalam daftar kata ada beberapa istilah yang dipahami pertama-tama oleh pengembang, jadi untuk konferensi QA Heisenbug kami sepakat pada ambang batas 15 poin. Mungkin sia-sia: semifinalis ternyata berkali-kali lebih banyak, yang berarti ada lebih sedikit peluang untuk memenangkan headphone.
PS Pada tahap awal, kami memutuskan bahwa dengan jawaban yang salah, peserta akan kehilangan skor cokelat. Tapi tidak ada yang suka dirampok sesuatu. βIni cokelat batangan saya, saya mendapatkannya!β - penguji permainan pertama marah. Karena itu, sebagai penalti, kami mulai memberi poin pada lawan.

Animasi
Kata menebak harus muncul dengan semacam animasi. Ini memberi kita dua keuntungan:
- Semacam "pemukulan" di antara kata-kata. Jauh lebih mudah bagi pemain untuk beralih dari satu kata ke kata lain jika ada tindakan di antara mereka. Ingat game pertarungan lama. Setiap babak baru dimulai dengan "3..2..1..FIGHT!". Saya tidak ingin membuat timer lain di sini - kami sudah memilikinya secara massal.
- Variasi visual. Kami mencoba membuat permainan sesederhana mungkin, kami tidak memiliki latar belakang animasi dan transisi antar level. Kami juga tidak bisa menggunakan suara, sehingga tidak mengganggu peserta konferensi lainnya. Karena itu, animasi diperlukan.
Dengan dia, tidak semuanya berjalan lancar dengan segera. Pada uji coba, ada orang-orang licik yang tidak menunggu akhir animasi dan mengklik tombol sebelumnya. Untuk mengajarkan triknya, kami mulai menghentikan kemunculan kata ketika salah satu pemain menekan tombol secara prematur. Bagian kata yang belum sempat muncul, dalam hal ini tetap tersembunyi di balik karakter. Apakah pemain menginginkannya atau tidak, dia harus menjawab. Sulit menebak kata dengan beberapa huruf, sehingga lawan mendapat poin.
Seperti apa kata itu jika Anda mengklik tombol sebelumnya:

Momen sulit kedua adalah durasi animasi. Itu selalu berlangsung bersamaan - 1,5 detik. Jika Anda "menangkap ritme", maka Anda bisa terbiasa menekan tombol lebih cepat dari lawan. Untuk mengatasi masalah, kami menambahkan variabel acak yang dari 0 hingga 500 ms. Dalam hal ini, menyesuaikan dengan ritme menjadi jauh lebih sulit.
Frontend
Saya akan menceritakan sedikit tentang bagian perangkat lunak. Jika Anda tidak tertarik, langsung ke kisah tentang bagaimana kami mencari tombol merah .
Mekanik permainan ternyata cukup sederhana, dan saya tidak ingin menciptakan sepeda. Mengambil create-react-app
untuk sisi klien. Namun tantangan itu tetap dibutuhkan.
Jadi kait! Hooks muncul di cakrawala sejak lama, tetapi aplikasi mereka di produk Badoo utama membutuhkan pemikiran ulang yang agak serius dari proses pengembangan. Proyek sampingan kecil adalah batu loncatan besar untuk penggunaannya.
Tidak ada redux! Redux adalah hal yang hebat, dan kami menggunakannya dalam pekerjaan kami setiap hari. Tetapi untuk aplikasi sekecil itu, menggunakan redux tidak dibenarkan. Selain itu, ada hook useContext
baru.
const { score, changeScore } = useContext(SessionContext); const { next } = useContext(QuestionsContext); const steps = useContext(StepsContext);
Ya, alih-alih cerita global, kami mendapat tiga konteks yang tidak bersinggungan sama sekali.
SessionContext
mencetak gol.
StepsContext
bertanggung jawab untuk mengganti layar aplikasi: intro, loop, outro ...
QuestionsContext
tahu semua tentang pertanyaan: mana yang dijawab, pertanyaan mana yang akan berikutnya, berapa banyak yang tersisa.
Penyedia
Setiap konteks membutuhkan penyedia yang akan mengirimkan data ke komponen akhir. Sebagai contoh, kami akan menggunakan penyedia sederhana untuk penilaian.
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> ); };
Seperti yang dapat Anda lihat dari kode, kami melacak poin secara independen. Ada keadaan terpisah untuk pemain "kiri" dan "kanan". Serta fungsi untuk mengelola akun: setel ulang akun dan ubah.
API penyedia yang dihasilkan sangat sederhana. Secara umum, hampir semua logika yang terkait dengan penyedia sangat sederhana, jadi kami tidak akan fokus pada itu.
Pengatur waktu
Komponen babak utama permainan ternyata menarik: ada momen-momen ambigu di dalamnya. Komponennya sama untuk kedua mode (mundur dan acak - "Pintasan" dan "Mixer").
Dari uraian babak, jelas bahwa ada banyak interaksi dengan waktu.
Pertama, ada timer yang bertanggung jawab atas durasi kata di layar: 10 detik untuk menekan tombol. Jika tidak ada yang menekan tombol, kata berikutnya muncul secara otomatis.
Kedua, penghitung waktu yang dimulai ketika salah satu pemain mengklik tombol. Kemudian dia memiliki 3 detik untuk menebak kata itu.
Tampaknya tidak ada yang rumit dalam hal ini, jadi kami menulis kode yang tampaknya jelas:
const [time, nextTick] = useState(0); useEffect(() => { let id = setInterval(() => { nextTick(time + 1); }, 1000); return () => clearInterval(id); }, []);
Tapi, seperti yang bisa Anda tebak, ini tidak berhasil. Itu sama sekali tidak berhasil!
Timer mencapai 1 dan berhenti pada saat itu. Faktanya adalah bahwa nilai time
lama "dikunci" di dalam fungsi pawang. Oleh karena itu, dengan setiap centang, setInterval
mengacu pada nilai time
dari render pertama.
Ada solusi untuk masalah menggunakan fungsi alih-alih nilai langsung:
nextTick(currentTime => currentTime + 1);
Ya, dengan begitu kami selalu memiliki nilai "segar" untuk timer. Tapi kita tidak bisa mendapatkan props
"segar", misalnya.
Jelas, pendekatan yang berbeda harus ditemukan. Dan keputusan paling pasti adalah membuat fungsi pawang bisa berubah. Bereaksi memiliki hook useRef
khusus untuk useRef
.
Paling sering digunakan untuk bekerja dengan elemen DOM, tetapi ini bukan satu-satunya aplikasi. Kami dapat "mengingat" variabel apa pun di properti current
ini dan memperbaruinya dengan setiap render.
function callback() { setCount(count + 1); } useEffect(() => { savedCallback.current = callback; }); useEffect(() => { function tick() { savedCallback.current(); } let id = setInterval(tick, 1000); return () => clearInterval(id); }, []);
Ada artikel bagus oleh Dan Abramov tentang bekerja dengan setInterval
dan React hooks: Membuat setInterval Declarative dengan React Hooks . Dia dengan sempurna menggambarkan semua jebakan dan semua tahapan refleksi pada implementasi hook useInterval
, yang kami ambil sebagai solusi untuk masalah kami.
Karena stan dibuka sepanjang konferensi, sesi yang berkelanjutan menggunakan permainan sangat besar. Halaman itu tidak diperbarui sama sekali (F5), jadi sangat penting untuk memantau memori pada tahap pengembangan. Seperti yang Anda tahu, kebocoran berjalan beriringan dengan timer, dan jika semua ini dibumbui dengan re-renders dari reaksi, maka akan sangat mudah untuk menulis kode yang memakan memori yang sangat, sangat banyak.
Countdown
dimulai, berhenti, diatur ulang, dan dimulai kembali puluhan (atau mungkin ratusan) kali dalam satu sesi permainan. Agar tidak repot dengan cek, yang seharusnya banyak, kami menggunakan "trik" yang agak sederhana - kami menambahkan key
pada komponen ini.
<QuestionCountdown key={question.text} onComplete={nextQuestion} />
Kami tidak akan membahas hal ini secara rinci, deskripsi lengkap tentang proses rekonsiliasi reaksi masih dengan Dan Abramov yang sama: Bereaksi sebagai Runtime UI .
Perangkat keras: dua tombol merah
Jadi, kami telah memenuhi beberapa persyaratan untuk permainan: itu multipemain, cepat dan dengan mekanik sederhana. Masih menambah hiburannya. Kisah ini akan diikuti oleh Yura Lilekov lilek - penggemar DIY kami, seorang pembicara konstan dari komunitas, pencipta sayap terbang dan perangkat do-it-yourself lainnya.
Kami benar-benar ingin menemukan dua tombol mekanis besar. Dan untuk memastikan yang merah - seperti dalam meme dengan Agutin.
Sayangnya, semua yang ditemukan di toko online terlalu kecil (diameter 5 cm) atau tidak ada tombol sama sekali. Tentu saja, ada AliExpress lama yang bagus, tetapi tidak ada waktu untuk menunggu pengiriman.
Hasilnya, kami menemukan tombol yang tepat di situs agensi kreatif. Tombol-tombol di suatu tempat di pinggiran kota dilakukan Alexander (ternyata, lulusan Fakultas Radio Elektronika). Kami menelepon, bertanya mikrokontroler mana yang dijahit ke dalam kotak, dan diminta untuk meninggalkan akses ke sana, karena kami perlu memprogram ulang.
Alexander, secara sederhana, terkejut dengan pertanyaan seperti itu. Ketika kami bertanya apakah tombol-tombol itu akan tahan terhadap tekanan para programmer yang antusias, dia meyakinkan kami bahwa tombol-tombol seperti itu ada di mesin slot di "Cosmic" dan mengatasi aliran anak-anak dengan sempurna. Ke depan, saya akan mengatakan bahwa para insinyur yang dipanaskan menahan tombol juga (hanya baterai yang harus diganti sekali).

Isian
Tetapi, sayangnya, perangkat yang telah selesai tidak memiliki semua kualitas yang kami butuhkan. Dan jika Anda masih bisa menghilangkan efek suara dengan memotong kabel ke speaker, maka secara otomatis menentukan tombol mana yang ditekan bukanlah tugas yang mudah. Opsi sederhana menyarankan sendiri: entah bagaimana menghubungkan perangkat ini ke komputer dan menerjemahkan penekanan tombol-tombol ini ke dalam penekanan tombol pada keyboard.
Solusi tanpa embel-embel - untuk mengambil keyboard USB lama dan membawa beberapa tombol dengan kabel tambahan dari keyboard ke perangkat - segera diberhentikan sebagai "pertanian kolektif". Dan menghubungkan kekuatan DIY.
Setelah beberapa pertimbangan, kami memutuskan untuk menggunakan papan Arduino Pro Micro berdasarkan mikrokontroler ATmega32u4 dari keluarga AVmel dari Atmel dengan ikatan yang diperlukan. Di papan ini, antara lain, port I / O dan MicroUSB dipisahkan. Dan yang paling penting - mikrokontroler ATmega32u4 dapat bertindak sebagai perangkat HID, yaitu, dalam kasus kami, meniru penekanan tombol dalam kondisi tertentu.

Untuk memprogram mikrokontroler ini, Anda hanya perlu kabel MicroUSB biasa dan lingkungan pengembangan Arduino IDE.
Setelah menginstal lingkungan pengembangan, contoh kode paling sederhana akan segera tersedia.
Misalnya, program yang mengemulasi mengetik pada keyboard ketika tombol ditekan (terhubung ke port input / output) berada di sini:
File-> Contoh-> USB-> Keyboard-> KeyboardMessage
Emulasi keystrokes dicapai dengan sangat sederhana:
Membaca status port input juga tanpa embel-embel:
int button_pin = 7; // , void setup() { pinMode(button_pin, INPUT); // } void loop() { if (digitalRead(button_pin)) { // } else { // } }
Karena port dibuka oleh tegangan, dan bukan oleh arus, arus induksi terkecil di kabel yang beralih dari tombol ke port dapat memberikan hasil positif palsu. Oleh karena itu, kami menyarankan "menarik" port input dengan resistor resistansi tinggi: arus induksi langsung mengalir melalui itu ke "ground", mencegah perbedaan tegangan tinggi antara input dan "ground" dari terjadi, dan dengan demikian, tidak akan ada pemicu palsu. Untuk keperluan ini, resistor 5-10 kΞ© sudah cukup, yang terhubung antara input mikrokontroler dan "ground" -nya.
Dengan demikian, kami mendapatkan skema berikut:

Papan Arduino Pro Micro melalui microUSB terhubung ke laptop dengan bagian perangkat lunak permainan, dua tombol terhubung ke dua input papan dan catu daya umum. Juga, dua input ini ditarik ke tanah oleh dua resistor.
Ketika salah satu tombol ditekan, arus dari output catu daya papan melalui tombol menuju ke input papan yang sesuai - dengan demikian kita akan melihat "unit" logis pada input.
Pada bagian perangkat lunak, kami memutuskan untuk meniru penekanan tombol "panah kiri" dan "panah kanan", dan juga memberikan penundaan selama 4 detik setelah menentukan penekanan, untuk menghindari klik berulang oleh peserta atau mengguncang kontak di tombol.
Jadi dengan bantuan perangkat sederhana, kami mengajarkan tombol untuk mengidentifikasi pemain yang mengkliknya lebih cepat dari lawan, dan untuk memberi sinyal kepada presenter.
Manajemen
Sepenuhnya manual dan sesederhana mungkin:
- Spasi - Kata Selanjutnya
- Masukkan - tampilkan kata yang benar
- + - true (1 poin)
- 0 - salah (arahkan ke lawan)
- Shift Kiri - Langkah Selanjutnya
- Shift Kanan - langkah sebelumnya
Hasil
Semua empat hari konferensi (dua di Highload ++, dua di Heisenbug) di stand Badoo terus-menerus memainkan "IT guessing game". Semua harapan kami menjadi kenyataan:
- Gim ini menarik perhatian peserta dan penonton: seluruh barisan orang berkumpul di stan. Sangat menyenangkan bahwa pada hari kedua konferensi jumlah peserta tidak berkurang.
- Tombol adalah yang teratas! Tambahkan +100 untuk kesenangan. Sekalipun para saingan itu saling asing satu sama lain, permainan itu menimbulkan banyak emosi.
- Gagasan dengan tanda pada lencana berhasil: tidak ada kesulitan menemukan pemenang dan mengumpulkan kontak. Beberapa orang meminta agar lencana mereka tetap bersih, jadi kami memberi tanda pada pergelangan tangan kami (mereka mudah terhapus).
- Kami membagikan 14 pasang headphone dan beberapa ratus hadiah kecil. Tidak ada yang tersisa tanpa hadiah!

Untuk berpartisipasi dalam permainan di konferensi, kami menyajikan merch kerenPembuat keputusan menggunakan magnet. Tidak tahu apa yang harus dilakukan dengan tugas - putar disk ajaib! Kami hanya memiliki beberapa foto yang tersisa, karena kami membagikan semuanya:

Untuk insinyur QA

Untuk pengembang
Cookie prediksi IT
Prediksi diciptakan sendiri (52 opsi). Menjadi kenyataan dengan probabilitas hingga 100%.

