{"id":533,"date":"2024-04-16T16:52:03","date_gmt":"2024-04-16T14:52:03","guid":{"rendered":"https:\/\/www.hh3dlab.fi\/blog\/?p=533"},"modified":"2024-04-16T16:52:03","modified_gmt":"2024-04-16T14:52:03","slug":"iot-space-adventure-developing-a-retro-arcade-style-handheld-gaming-device-with-esp32-and-fun-controls","status":"publish","type":"post","link":"https:\/\/www.hh3dlab.fi\/blog\/3d-robo-lab\/iot-space-adventure-developing-a-retro-arcade-style-handheld-gaming-device-with-esp32-and-fun-controls\/","title":{"rendered":"IoT Space Adventure: Developing a retro arcade style handheld gaming device with ESP32 and fun controls."},"content":{"rendered":"<h1>Introduction<\/h1>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">Video demonstration: <a href=\"https:\/\/www.youtube.com\/watch?v=9Bk4u3yt4mI\">https:\/\/www.youtube.com\/watch?v=9Bk4u3yt4mI<\/a><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">GitHub repository: <a href=\"https:\/\/github.com\/Gianou\/Haaga-Helia-IoT-Experimental-Project\">https:\/\/github.com\/Gianou\/Haaga-Helia-IoT-Experimental-Project<\/a><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">Our team consisted of three students: David, Isabelle, and Sara. We have diverse backgrounds and sets of skills within IT.<\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\"><br \/>\nSara is a second year Business Information Technology student from Haaga-Helia. Her major is in digital services and design, but she studies Front-end programming as her minor. She has had some prior experience in robotics, mostly in working with Arduino Uno, ESP32 and different kinds of sensors. She does not have a background in gaming, but she is familiar with the concept of arcade games.<\/p>\n<p><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">David is a Double Degree exchange student from HES-SO Valais\/Wallis. His major is in software development. He had no prior experience with embedded software development nor IoT, though he is experienced in coding and has made basic games from scratch in Java and JavaScript before.<\/p>\n<p><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">Isabelle is a Double Degree exchange student from HES-SO Neuch\u00e2tel. Her major is in software development. She had no prior experience in IoT nor game development, but she is experienced in coding and loves gaming.<\/p>\n<p><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">For this project, our goal was to create a game device that would run a game with fun controls using many sensors. The game that we produced is an infinite scroller where the player controls a spaceship and is trying to avoid asteroids. The controls change over the course of the game. At first the ship is controlled with a conventional joystick, then it is controlled with a proximity sensor and finally with a gyroscope!<\/p>\n<p><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">The game and the device are inspired by retro arcade games and by the Nintendo Gameboy. We also thought that adding Ethernet communication to our game device would give it an interesting anachronistic twist. So, we added an online leaderboard.<\/span><\/p>\n<h1>Ideas<\/h1>\n<p style=\"margin-top: 0; margin-bottom: 0;\">We started our ideation with 6-3-5 brainwriting session. The aim for this session was to create a large number of ideas that would later be discussed and developed further. After selecting ideas from our brainwriting.<\/p>\n<figure id=\"attachment_545\" aria-describedby=\"caption-attachment-545\" style=\"width: 250px\" class=\"wp-caption alignnone\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\" wp-image-545\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload-4.png?resize=250%2C366&#038;ssl=1\" alt=\"Idea lists\" width=\"250\" height=\"366\" srcset=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload-4.png?resize=205%2C300&amp;ssl=1 205w, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload-4.png?resize=700%2C1024&amp;ssl=1 700w, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload-4.png?resize=768%2C1124&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload-4.png?w=911&amp;ssl=1 911w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/><figcaption id=\"caption-attachment-545\" class=\"wp-caption-text\">Idea lists<\/figcaption><\/figure>\n<p style=\"margin-top: 0; margin-bottom: 0;\">\nAfter our brainwriting session we narrowed our choices down to two options: a smart alarm clock or an arcade style handheld gaming device with IoT functions. Lotus blossom was made for both ideas and based on discussions within the team the idea of creating an arcade style handheld gaming device with an online leaderboard was selected for this project.<\/p>\n<h1>What did you need to learn<\/h1>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Our project is ambitious so to better understand what we had to learn and what we already knew. So, we used the Lotus blossom to create a scope and learning objectives for the project.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 838px; height: 494px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/9a0ac729126f522fba12075e90da2b4f.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">\nAfter listing project requirements into the Lotus Blossom, we opened them up further in the subproject excel.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 1724px; height: 372px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/f6bfe338de08ca65f51c71dc287a4e19.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">As the excel suggested, there were a lot of things we needed to learn. Regarding hardware we needed to figure out how to incorporate multiple sensors to the device. The first components we integrated to the game were two buttons and a Joystick. We also wanted to include other sensors, for example an ultrasonic distance sensor and a gyroscope, that required some research from us. We wanted to create a retro look and feel to the game, so we needed to figure out how to show pixel art and colours in the display. Regarding software, one of the biggest learning points was to figure out how to transition to VScode from the Arduino IDE. This was instrumental in facilitating collaborative development across multiple files, enhancing our workflow efficiency. Wrangling with C++ and its .cpp and .h files felt like building blocks in a Lego set \u2013 sometimes frustrating, but ultimately rewarding as we started to piece together our project&#8217;s backbone. We needed to learn more about the integration of Firebase, that provided a robust framework for cloud connectivity and data management. These learning experiences not only fortified our technical competencies but also underscored the imperative of adaptability and continuous learning in IoT innovation.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">During our project development process, we convened a focused and dynamic Crazy 8&#8217;s innovation session among our team of three. This collaborative brainstorming session served as a catalyst for refining the specifics of the game to be featured on our handheld gaming device platform. Through structured ideation and rapid iteration, we explored various gameplay mechanics, visual aesthetics, and interactive features. Each member contributed unique perspectives and insights, fostering a rich exchange of ideas and sparking creative synergies. The session facilitated strategic decision-making, guiding us towards a cohesive and compelling vision for our game. Ultimately, this iterative process enabled us to distil complex concepts into actionable design elements. The decision of creating a 2D infinite scroller game with a space theme, where player must fly a spaceship and dodge asteroids during the game was made. Also, the idea of switching controls of the game instead of levelling up the difficulty in every level came up during the ideation. This way we were able to incorporate more sensors to the hardware.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 825px; height: 1101px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/cb32ca6ef33d696a3766a05e68706319.jpeg?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">The building phase was started immediately after the project scope and requirements were decided.<\/p>\n<h1>The building phase<\/h1>\n<h2>Hardware<\/h2>\n<p style=\"margin-top: 0; margin-bottom: 0;\">During the first classes in the 3D lab, we were able to hook up two buttons, a joystick, and a TFT LCD screen to our ESP32. We assembled two breadboards together and the device was already looking like a handheld gaming device.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 955px; height: 1266px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/5ce4f199ce63e3e46a0401021dc1b973.jpeg?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">After that, it was decided that we should concentrate on building a working code architecture, a base version of the game, and a connection to a database. And then once this would work, we could start adding more, less conventional, controls.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">HC-SR04 proximity sensor is the first fun control that we added. The proximity sensor is composed of a speaker and a microphone. In our case, the player has to place their hand closer or farther from the sensor to move the ship.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">GY-521 Accelerometer\/Gyroscope came next, allowing the player to change the orientation of the gaming device to move the ship. This is similar to balancing a marble on a board.<\/p>\n<h2>Software<\/h2>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Making a game from scratch requires a rather complex code architecture and so we opted to use Object Oriented Programming (OOP) for this project. This allowed us to encapsulate logic inside of classes and make development easier. So instead of having a single Sketch (.ino) file, we have many C++ files where we define new classes. Each class is split into a header (.h) and a C++ file (.cpp). This is the same technique that is used to write libraries for Arduino and ESP32 development.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">A video game works like a flipbook, each frame, the elements of the scene are redrawn in a slightly different spot and that creates an animation effect. In our game, the ship and the asteroids have x and y attributes that define where they are and therefore where they must be drawn on the screen. Each frame, those value are updated and that makes the ship, and the asteroids move.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Then, all that is required for the player to control the ship, is some sort of input. Making the ship move based on the joystick inputs was straightforward and so was using the sonar and the gyroscope. The challenge was to setup the phases in the game where the controls changes and the tutorial on how to use the new control is displayed.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">The general architecture of the game engine is based on a composite design pattern where every element of the game extends the GameObject.h abstract class. The root node of the composite pattern is the GameEngine and this allows us to have a loop() function in the Sketch that looks like this:<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 460px; height: 208px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/c4e1c0e59103ca73c3ce976bf8ed5ecb.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">All the code can be found on the project\u2019s GitHub repository: <a href=\"https:\/\/github.com\/Gianou\/Haaga-Helia-IoT-Experimental-Project\">https:\/\/github.com\/Gianou\/Haaga-Helia-IoT-Experimental-Project<\/a><\/p>\n<h2>Database<\/h2>\n<p style=\"margin-top: 0; margin-bottom: 0;\">We decided to use the realtime Firebase database as it is free as long as it stays a small DB, which is perfect for our project. We were also familiar with it, as we used it in a React Native project.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">We used the library Firebase_Arduino_Client_Library_for_ESP8266_and_ESP32 (URL: <a href=\"https:\/\/github.com\/mobizt\/Firebase-ESP-Client\">https:\/\/github.com\/mobizt\/Firebase-ESP-Client<\/a>) which is well documented. We were easily able to link our project to the database.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Sending the data to the database was easy, we used a JSON object:<\/p>\n<p style=\"margin-bottom: 0pt;\">{<\/p>\n<p style=\"margin-bottom: 0pt;\">\u201cpseudo\u201d: \u201cMyPseudo\u201d,<\/p>\n<p style=\"margin-bottom: 0pt;\">\u201cscore\u201d: \u201cMyScore\u201d<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">}<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">However, getting back the data was trickier. It was easy to get them, but harder to use them. Indeed, the data were sent back to us in String, so to be able to read all the pseudo and scores, we would have needed to create methods to deserialize the String. This would have been possible, but we decided to come up with another solution.<\/p>\n<p>We created an index; the idea is that this index would work a bit like a primary key in the database. So, the index starts at 1 and each time a new score is added to the database, it is incremented by 1. Because of this, we do not need to send JSON object to database anymore. Here is a simplified version of the code for a better understanding:<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-family: 'Consolas';\">config.api_key<\/span><span style=\"font-family: 'Consolas';\"> = _<\/span><span style=\"font-family: 'Consolas';\">apiKey<\/span><span style=\"font-family: 'Consolas';\">; \/\/the <\/span><span style=\"font-family: 'Consolas';\">api<\/span><span style=\"font-family: 'Consolas';\"> key of our database<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">config.database_url<\/span><span style=\"font-family: 'Consolas';\"> = _<\/span><span style=\"font-family: 'Consolas';\">databaseUrl<\/span><span style=\"font-family: 'Consolas';\">; \/\/the URL of our database<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">FirebaseData<\/span><span style=\"font-family: 'Consolas';\"> _<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">;<\/span><\/p>\n<p><span style=\"font-family: 'Consolas';\">Firebase.begin<\/span><span style=\"font-family: 'Consolas';\">(&amp;config, &amp;auth); <\/span><br \/>\n<span style=\"font-family: 'Consolas';\">Firebase.RTDB.getInt<\/span><span style=\"font-family: 'Consolas';\">(&amp;_<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">, &#8220;index&#8221;); \/\/get the index from the database<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">int index = _<\/span><span style=\"font-family: 'Consolas';\">fbdo.intData<\/span><span style=\"font-family: 'Consolas';\">(); \/\/set the integer index with the value of the <\/span><br \/>\n<span style=\"font-family: 'Consolas';\"> \/\/<\/span><span style=\"font-family: 'Consolas';\">index in the database<\/span><\/p>\n<p><span style=\"font-family: 'Consolas';\">\/\/sends the pseudo (username) to the database in the specified index<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">Firebase.RTDB.setString<\/span><span style=\"font-family: 'Consolas';\">(&amp;_<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">, \u201c<\/span><span style=\"font-family: 'Consolas';\">score_board<\/span><span style=\"font-family: 'Consolas';\">\/pseudo\/\u201d+String(index), pseudo);<\/span><\/p>\n<p><span style=\"font-family: 'Consolas';\">\/\/sends the pseudo (username) to the database in the specified index<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">Firebase.RTDB.setInt<\/span><span style=\"font-family: 'Consolas';\">(&amp;_<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">, \u201c<\/span><span style=\"font-family: 'Consolas';\">score_board<\/span><span style=\"font-family: 'Consolas';\">\/score\/\u201d+String(index), score)<\/span><span style=\"font-family: 'Consolas';\">;<\/span><\/p>\n<p><span style=\"font-family: 'Consolas';\">\/\/increment the index by 1 and sends the new value to the database<\/span><br \/>\n<span style=\"font-family: 'Consolas';\">Firebase.RTDB.setInt<\/span><span style=\"font-family: 'Consolas';\">(&amp;_<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">, &#8220;index\/&#8221;, index + 1);<\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Here is what it looks like in the database:<br \/>\n<img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 435px; height: 407px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/1b3a62cfbe0d497dd947d8d329c4a7a1.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p>&nbsp;<\/p>\n<h3>Leaderboard<\/h3>\n<p style=\"margin-top: 0; margin-bottom: 0;\">As the screen that we used for our project is quite small, we decided to just show the leaderboard, aka the top 10 scores. There were two possibilities for this:<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">\nFetch the whole database, sort it and show on the screen the 10 first usernames and scores<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Create a leaderboard in the database which contains the top 10 scores and is updated if needed<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">every time a score is added to the scoreboard in the database.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">We opted for the second possibility; the first one is good if you only have a small amount of data. And, even if we know we\u2019ll never have a huge database, we did not know how much time and memory it would use on the ESP32 to each time sort through all the data before displaying the leaderboard.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">We created the leader_board in the database. We added 10 new entries in it (all with a score of 0) and added the entry min, which represent the lowest score of the leaderboard (the score of the entry number 10). The leader_board looks like this:<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 598px; height: 466px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/e3fcb0773a0cf669fde18f202da94c2c.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">\nEach time a new score is added to the score board, the score is compared to min (the lowest score in the leaderboard), if it is greater or equals to it. If it is the case, then the new score value is compared to the leaderboard values (starting at the bottom) until it reaches the rank it should be at (when the new score is lower than one of the scores in the leaderboard). The leaderboard is then updated with the new score and the min is updated with the score of the 10th entry.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Here is a part of the code to explain a bit better how we update the leaderboard:<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\">\/\/check if the score has to be added to leader_board<\/span><span style=\"font-family: 'Consolas';\">, if true, the data from <\/span><br \/>\n<span style=\"font-family: 'Consolas';\">\/\/the leader_board are fetched and put in a table<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> if (score &gt;= min) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> int leader_board_score[10];<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> String leader_board_pseudo[10];<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> for (int i = 0; i &lt; 10; i++) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_score[i] = receiveDataScore(String(i+1));<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_pseudo[i] = receiveDataUserName(String(i+1));<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> int rank = 0;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> \/\/loop to find which rank the score will be<\/span><span style=\"font-family: 'Consolas';\"> at<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> for (int i = 8; i &gt;= 0; i&#8211;) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> if (score &lt; leader_board_score[i]) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> rank = i+1;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> break;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> \/\/loop to <\/span><span style=\"font-family: 'Consolas';\">update<\/span><span style=\"font-family: 'Consolas';\"> the ranks of the leader_board<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> for (int i = 9; i &gt; rank; i&#8211;) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_score[i] = leader_board_score[i-1];<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_pseudo[i] = leader_board_pseudo[i-1];<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> \/\/add the new score and pseudo to the leader_board<\/span><span style=\"font-family: 'Consolas';\"> table<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_score[rank] = score;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> leader_board_pseudo[rank] = pseudo;<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> \/\/loop to change the leader_board in the database<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> for (int i = 0; i &lt; 10; i++) {<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> String path_leader = &#8220;leader_board\/&#8221;;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> String pathIndex_leader = path_leader += String(i+1);<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> String pathScore_leader = pathIndex_leader += &#8220;\/score&#8221;;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> String pathPseudo_leader = path_leader += &#8220;\/pseudo&#8221;;<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> Firebase.RTDB.setInt(&amp;_fbdo, pathScore_leader, leader_board_score[i]);<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> Firebase.RTDB.setString(&amp;_fbdo, pathPseudo_leader,<\/span><br \/>\n<span style=\"font-family: 'Consolas';\"> leader_board_pseudo[i]);<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> \/\/change the min value in the database<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\">Firebase.RTDB.setInt<\/span><span style=\"font-family: 'Consolas';\">(&amp;_<\/span><span style=\"font-family: 'Consolas';\">fbdo<\/span><span style=\"font-family: 'Consolas';\">, &#8220;<\/span><span style=\"font-family: 'Consolas';\">leader_board<\/span><span style=\"font-family: 'Consolas';\">\/min&#8221;, <\/span><span style=\"font-family: 'Consolas';\">leader_board_score<\/span><span style=\"font-family: 'Consolas';\">[9]);<\/span><\/p>\n<p style=\"margin-bottom: 0pt;\"><span style=\"font-family: 'Consolas';\"> }<\/span><\/p>\n<h2>Online leaderboard<\/h2>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Once a connection to the database was established an online scoreboard was built for the game. The page was created as a simple ReactJs + Vite application, with a retro look and feel.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">Some pixel artwork was created for the site using PixilArt and a \u201cPress Start 2P\u201d Google font was used.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 467px; height: 333px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/478e49025dcd0730acc0bcda058190df.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">One requirement for the scoreboard was a connection to the Firebase Realtime Database. We&#8217;re essentially fetching data from a specific path in the database, which likely contains information about a leaderboard. Whenever there&#8217;s a change in the data at that path, our application receives updates in real-time.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\">This is facilitated by setting up a listener function that constantly monitors for changes. When new data arrives, our application updates its internal state accordingly. It&#8217;s important to clean up this listener when the component is no longer in use to prevent any unnecessary resource consumption. This ensures that our React component always stays in sync with the latest data in the database, providing users with up-to-date information without the need for manual refreshes. The scoreboard data is showcased in a simple Material UI table.<\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><img data-recalc-dims=\"1\" decoding=\"async\" style=\"width: 1125px; height: 524px;\" src=\"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/c7179734345f60f39ed0342e7450dc7b.png?w=640&#038;ssl=1\" border=\"0\" \/><\/p>\n<h1>The outcome<\/h1>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\"><span style=\"font-family: 'Calibri';\">Throughout our journey in developing our IoT <\/span><span style=\"font-family: 'Calibri';\">handheld<\/span><span style=\"font-family: 'Calibri';\"> arcade <\/span><span style=\"font-family: 'Calibri';\">gaming<\/span><span style=\"font-family: 'Calibri';\"> system, we&#8217;ve gained invaluable insights and experiences that have not only enhanced our technical skills but also enriched our collaborative dynamics and personal growth<\/span><span style=\"font-family: 'Calibri';\">.<\/p>\n<p><\/span><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\"><span style=\"font-family: 'Calibri';\">We<\/span><span style=\"font-family: 'Calibri';\"> obviously<\/span><span style=\"font-family: 'Calibri';\"> improved our understanding of IoT technology<\/span><span style=\"font-family: 'Calibri';\">, but more <\/span><span style=\"font-family: 'Calibri';\">importantly, we learned a valuable lesson: <\/span><span style=\"font-family: 'Calibri';\">the importance of enjoyment in our work. <\/span><span style=\"font-family: 'Calibri';\">By incorporating fun and creativity into our project, we not only maintained our <\/span><span style=\"font-family: 'Calibri';\">motivation,<\/span><span style=\"font-family: 'Calibri';\"> but <\/span><span style=\"font-family: 'Calibri';\">it <\/span><span style=\"font-family: 'Calibri';\">also helped us overcome obstacles.<\/p>\n<p><\/span><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\">While we all were already tinkering at different levels, this course helped us see new possibilities. It reinforced our passion for tinkering and <\/span><span style=\"font-family: 'Calibri';\"><span style=\"font-size: 18px;\">showed us how cool it can be when technology and creativity come together. Now, we&#8217;re eager to keep exploring and trying new things in this area.<\/span><\/p>\n<p><\/span><\/p>\n<p style=\"margin-top: 0; margin-bottom: 0;\"><span style=\"font-size: 18px;\"><span style=\"font-family: 'Calibri';\">This course<\/span><span style=\"font-family: 'Calibri';\"> inspired us with ideas for crafting useful items for our homes<\/span>, trying to build them instead of just buying them and in doing so, allowing us to make thing that suits our exact needs.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Video demonstration: https:\/\/www.youtube.com\/watch?v=9Bk4u3yt4mI GitHub repository: https:\/\/github.com\/Gianou\/Haaga-Helia-IoT-Experimental-Project Our team consisted of three students: David, Isabelle, and Sara. We have diverse backgrounds and sets of skills within IT. Sara is a second year Business Information Technology student from Haaga-Helia. Her major is in digital services and design, but she studies Front-end programming as her minor. She [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[16,3,39,20,61,33],"tags":[],"class_list":["post-533","post","type-post","status-publish","format-standard","hentry","category-3d","category-3d-robo-lab","category-blog","category-esp32","category-gaming","category-lcd-display"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":5,"url":"https:\/\/www.hh3dlab.fi\/blog\/3d-robo-lab\/tervetuloa-haaga-helian-3d-robo-labiin\/","url_meta":{"origin":533,"position":0},"title":"Haaga-Helia 3D + Robo Lab equipment","author":"Heikki Hietala, lab admin","date":"13.3.2022","format":false,"excerpt":"Haaga-Helia 3D + Robo Lab is the 3D, robotics and IoT research lab at our University. 3D is a family of technologies that can be seen to affect every field of business today. Virtual reality, augmented reality, mixed reality, 3D modeling, scanning and printing open new business opportunities every day.\u2026","rel":"","context":"In &quot;3D + Robo Lab&quot;","block_context":{"text":"3D + Robo Lab","link":"https:\/\/www.hh3dlab.fi\/blog\/category\/3d-robo-lab\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20190202_194403_807.jpg?fit=1200%2C1200&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20190202_194403_807.jpg?fit=1200%2C1200&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20190202_194403_807.jpg?fit=1200%2C1200&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20190202_194403_807.jpg?fit=1200%2C1200&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20190202_194403_807.jpg?fit=1200%2C1200&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":268,"url":"https:\/\/www.hh3dlab.fi\/blog\/madrid-2022\/team-5-introduction\/","url_meta":{"origin":533,"position":1},"title":"Team 5 &#8211; Introduction","author":"Madrid Team 5","date":"30.3.2022","format":false,"excerpt":"Hello all, this is an introduction post to Team 5 for Madrid seminar 2022. Our group of students from Haaga-Helia UAS will go to Madrid seminar to teach other students how to build an IoT device that sends GPS, temperature etc. data to the server and displays the information on\u2026","rel":"","context":"In &quot;ESP32&quot;","block_context":{"text":"ESP32","link":"https:\/\/www.hh3dlab.fi\/blog\/category\/esp32\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2022\/03\/IMG_20220328_161500-2-scaled.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":524,"url":"https:\/\/www.hh3dlab.fi\/blog\/3d-robo-lab\/524\/","url_meta":{"origin":533,"position":2},"title":"Person counter for the 3D + Robo Lab","author":"Heikki Hietala, lab admin","date":"16.4.2024","format":false,"excerpt":"Introduction Hello! Our team consists of four students who worked together on a project for our 3D and Robotics course at Haaga-Helia. Although the four of us come from different backgrounds, we managed to combine our strengths to work together to get this project done. In our team we have\u2026","rel":"","context":"In &quot;3D&quot;","block_context":{"text":"3D","link":"https:\/\/www.hh3dlab.fi\/blog\/category\/3d\/"},"img":{"alt_text":"First test device","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/04\/upload1-225x300.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":550,"url":"https:\/\/www.hh3dlab.fi\/blog\/esp32\/550\/","url_meta":{"origin":533,"position":3},"title":"Air Quality and Control System","author":"Heikki Hietala, lab admin","date":"11.10.2024","format":false,"excerpt":"October 2024 - (c) Stephen Swanson Check it out on GitHub Introduction Hi! I\u2019m Stephen, a 3rd-year student at Haaga-Helia UAS. Programming and creating IoT and embedded devices are recent hobbies of mine, which I picked up in summer 2024 after some friends (Alisa Dunaeva and David Gianadda) suggested I\u2026","rel":"","context":"In &quot;BMP 280 sensor&quot;","block_context":{"text":"BMP 280 sensor","link":"https:\/\/www.hh3dlab.fi\/blog\/category\/bmp-280-sensor\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/10\/Picture2.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/10\/Picture2.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2024\/10\/Picture2.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":481,"url":"https:\/\/www.hh3dlab.fi\/blog\/uncategorized\/irrigation-project\/","url_meta":{"origin":533,"position":4},"title":"Irrigation project","author":"Heikki Hietala, lab admin","date":"1.6.2023","format":false,"excerpt":"Group members: Sara, Youmna, Anna, Olympe Introduction Hello! We are four students who worked together for five months on an interesting project for our Innovation and Prototyping course at Haaga-Helia. We all have different backgrounds, but we managed to combine our strengths to work together and to get this project\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2023\/06\/image-21.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":658,"url":"https:\/\/www.hh3dlab.fi\/blog\/3d-robo-lab\/the-weatherslayeaer-project\/","url_meta":{"origin":533,"position":5},"title":"The Weatherslayeaer project","author":"Heikki Hietala, lab admin","date":"25.3.2026","format":false,"excerpt":"Introduction We are a team of three second\u2011year students from different areas of digital and technical studies, each bringing our own strengths into this 3D and Robotics course. Hey there! I\u2019m Saana, and I\u2019m currently in my second year of studying digital services. When I started the IoT course, I\u2026","rel":"","context":"In &quot;3D&quot;","block_context":{"text":"3D","link":"https:\/\/www.hh3dlab.fi\/blog\/category\/3d\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2026\/03\/word-image-658-6.jpeg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2026\/03\/word-image-658-6.jpeg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2026\/03\/word-image-658-6.jpeg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.hh3dlab.fi\/blog\/wp-content\/uploads\/2026\/03\/word-image-658-6.jpeg?resize=700%2C400&ssl=1 2x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/posts\/533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/comments?post=533"}],"version-history":[{"count":1,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/posts\/533\/revisions"}],"predecessor-version":[{"id":546,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/posts\/533\/revisions\/546"}],"wp:attachment":[{"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/media?parent=533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/categories?post=533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hh3dlab.fi\/blog\/wp-json\/wp\/v2\/tags?post=533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}