How to build an HTML5 game’s controller with Arduino, NodeJS and socket.io — Part 1

April 17, 2020

Photo by Daniel Andrade on Unsplash

During the Covid 19 “vacation” I wanted to create a project for my 12 years old sun. He likes computer games and he likes Arduino.

I wanted to focus on the connectivity and the Arduino part but not on developing the game itself. So the plan is to take an existing html5 game which controlled by keyboard and add the ability to control it from an external “controller” which will be connected through a server to the game host using socket.

Like any project, I like to do small steps. Do one simple step, make sure it’s working and “complicate” it a bit more. There are the steps:

  • First, control it from a different browser window using the same keyboard keys.

  • Then, control it from a mobile phone on the same network of course.

  • Finally, control it through an nodemcu esp8266 controller which has a builtin wifi module to make it easier to establish a connection.

I was looking for a very simple light weight html5 game. As less dependencies as possible. The chosen game… https://github.com/cykod/AlienInvasion (it’s an old one, I know)

Installing dependencies

1yarn add express socket.io @types/socket @types/express

I like types..

Control the game from a different window

Currently, the user can control the game using the keyboard. The idea is to “send” the event from the controller to the game. While it’s not possible to send the actual event over socket, I’ll send only code and keyCode to the server. Those will be enough for dispatching the event in the game.

Let’s start from the server. To establish a socket, as the post’s title mention, I’m using NodeJS and socket.io. The server also will serve the “statics” — html and js files.

Since I’m new in socket.io, I’m following the “Getting Started” guide. First thing is to run an express server

1const express = require('express');
2const app = express();
3const http = require('http').createServer(app);
4const io = require('socket.io')(http);
5
6app.use(express.static(__dirname));
7
8app.get('/', (req, res) => {
9 res.sendFile(__dirname + '/index.html');
10});
11
12io.on('connection', (socket) => {
13 console.log('a user connected');
14});
15
16http.listen(3000, () => {
17 console.log('listening on *:3000');
18});

This is the very basic code to establish a socket connection.

Now, the server should listen to events through socket from the controller and “transmit” to the game.

1io.on('connection', (socket) => {
2 socket.on('event', message => {
3 socket.broadcast.emit('event', message);
4 });
5});

Notice that I’m using socket.broadcast.emit . This way it will send the events “to all clients except sender”.

Next thing is connecting the clients. The first connection is very simple:

1const socket = io();

I’m adding 2 files to the project (except the server code and package.json and.. well you get my point)

  • controller.html — to demonstrate.. well.. the controller (which will be the Arduino eventually).

  • remotely.js — for taking care of the “remote” layer. Will be added to the game file.

Currently, I want to make sure that both of the clients are connected over socket.

controller.html

1<button>Start</button>
2<script>
3 const socket = io();
4 document.querySelector('button').addEventListener('click', () => {
5 socket.emit('key', 'start');
6 });
7</script>

remotely.js

1const socket = io();
2socket.on('key', console.log);

Click on “start” in the controller, create’s a log in the gameClick on “start” in the controller, create’s a log in the game

Next step will be to actually “transmit” the “events” from the controller to the game

controller.html

1function isRelevantKey(key) {
2 return ['ArrowRight', 'ArrowLeft', ' '].includes(key);
3}
4
5['keydown', 'keyup'].forEach(type => {
6 window.addEventListener(type, ({key, keyCode}) => {
7 if (isRelevantKey(key)) {
8 socket.emit('event', {type, key, keyCode});
9 }
10 });
11});

remotely.js

1socket.on('event', ({type, key, keyCode}) => {
2 const evt = new KeyboardEvent(type, {
3 key,
4 keyCode
5 });
6 window.dispatchEvent(evt);
7});

Pressing on the keyboard while controller.html is in focus, moves the mothership in the game windowPressing on the keyboard while controller.html is in focus, moves the mothership in the game window

In the next post I’ll start the second step — turn my mobile phone to a controller and then will come the interesting part. To make it more interesting, I’ll add try to add a “joystick” UI to it. I hope to find a ready one 🤞

Feel free to review the source code and the relevant commit on Github.

Have something to say? I’d love to 👂 https://twitter.com/moshfeu

Original Post
© 2022 - Moshe Feuchtwander