Twitch minigame
Occasionally I have the urge to stream on Twitch – whether it's development work, or just playing around in Photoshop. At the same time, I also want my audience to have fun and be captivated by more than just what I'm doing.
That's why over the weekend I decided to build a Twitch minigame using JavaScript. And to make it extra meta, I built a lot of it live during a stream – with input from the audience of course.
The gist of it is that the audience can join in the race (by writing "!join" in the chat, or whispering it to my game bot). Each round, the players are populated onto the field which is overlayed on whatever I'm working on. Then the race begins. Players' speed fluctuates randomly in small amounts and at random intervals.
There are also random events that can increase or decrease a players speed (or in some cases, cause them to start leaving the field).
Each time someone wins, they earn some points. My eventual goal is to add new skins/creatures that people can spend points on to unlock. Just cosmetic changes, though. I still want the speeds and whatnot to be random.
On the technical side of things, here's what's going on in the background:
First, there is a bot running via node.js that connects to the Twitch IRC channel of my stream. It monitors the chat for incoming commands (both in public chat as well as whispers to my bot account). This is done with help from the Twitch Messaging[1] library. The second half of the equation is the "client"; this is simply a single page served locally that displays the game view and communicates over sockets[3] with the bot script. The view is written using PhaserJS[4] to handle the graphics rendering.
When a player joins the race they are added to the queue which is stored in Redis[2]. This is similar to a player sending the "!points" or "!stats" commands; the information is queried from Redis and then returned via Twitch Messaging.
if (message === '!stats') {
getPlayerData(uID, function(pData) {
client.whisper(from, 'You have won ' + pData.wins + ' time' + ((pData.wins) !== 1 ? 's' : ''));
}, this);
return;
}
Once the race finally begins the bot uses a socket connection to populate the field in the game view. Since the display is only rendered in the stream and is not directly accessible by the audience the socket calls are not authenticated. When a player hits the chest at the end of the race it triggers the "game over" condition and fires a message back to the bot. It's at this point that the number of wins and points are updated in Redis.
One final piece to the overlay is the "Currently listening" to bit. I modified the Scroblr[5] extension to send the current track information to my bot script. Captured as an HTTP request, the data is then stored in Redis and also sent via socket to the game view.
var data = require('querystring').parse(request.url);
var currentSong = {
"artist": data.artist,
"track": data.track
};
rdb.set('currentSong', JSON.stringify(currentSong));
io.sockets.emit('listeningTo', currentSong);
Resources:
[1] Twitch Messaging (node module)
[2] Redis (node module)
[3] socket.io (node module)
[4] Phaser JS
[5] Scroblr browser extension
[6] Pixel art courtesy KnoblePersona