Using an ESP32 as a web server and using WebSockets to control hardware

How to Create a Web Server (with WebSockets) Using an ESP32 in Arduino

A few months ago, I created a video showing how to use WebSockets with an ESP32. WebSockets have proven to be very fast (relatively speaking) at controlling hardware over WiFi. They still rely on TCP, but they have little overhead, so the latency is much less than other methods (e.g. using separate web pages). However, I’ve had a few requests to show how to implement a web server on the ESP32. So, this tutorial will cover exactly that (but I’m still keeping WebSockets, because they’re cool).

If you like your tutorials in video format, here you go:

 

Overview

Rather than just host a simple web page, we’re going to build on the WebSocket idea. Let’s have our ESP32 be an access point (AP) and host a web page. When a browser requests that page, the ESP32 will serve it. As soon as the page loads, the client will immediately make a WebSocket connection back to the ESP32. That allows us to have fast control of our hardware connected to the ESP32.

ESP32 web server and WebSocket server diagram

The WebSocket connection is two-way. Whenever the page loads, it first inquires about the state of the LED from the ESP32. If the LED is on, the page will update a circle (fill in red) to reflect that. The circle on the page will be black if the LED is off. Then, whenever a user presses the “Toggle LED” button, the client will send a WebSocket packet to the ESP32, telling it to toggle the LED. This packet is followed by another request asking about the LED state so that the client can keep the browser updated with the state of the LED.

Hardware Hookup

Connect an LED to pin 15 of your ESP32 (don’t forget a limiting resistor! Something like 330Ω should work). Note that I’m using an Adafruit Feather HUZZAH32, so your pin numbering might be different.

Connecting LED to ESP32

 

Install SPIFFS Plugin

An ESP32 with an attached flash storage chip, like our HUZZAH32, can be configured to hold files, much like a mass storage device. However, it uses a very basic file system (there are no folders–files are just stored in a flat structure). This file system is known as the “Serial Peripheral Interface Flash File System” (SPIFFS). You can read more about SPIFFS here.

We need to use a special program to upload files over SPI. Head to https://github.com/me-no-dev/arduino-esp32fs-plugin and follow the instructions to install the Arduino plugin. Once done, restart Arduino, and you should see the option ESP32 Sketch Data Upload in the Tools menu.

ESP32 SPIFFS upload plugin in Arduino

Install Arduino Libraries

Make sure you have the ESP32 board definition installed for your particular board. If you’re using a board that’s supported by the Espressif Arduino board manager (such as the Adafruit HUZZAH32), you can follow the directions here.

Download the .zip files for the following libraries and install them in Arduino.

Arduino Code

Enter the following code into a new Arduino sketch. Take note of the SSID and password–we’ll need these to connect our phone/computer to the ESP32’s AP.

#include <WiFi.h>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>

// Constants
const char *ssid = "ESP32-AP";
const char *password =  "LetMeInPlz";
const char *msg_toggle_led = "toggleLED";
const char *msg_get_led = "getLEDState";
const int dns_port = 53;
const int http_port = 80;
const int ws_port = 1337;
const int led_pin = 15;

// Globals
AsyncWebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(1337);
char msg_buf[10];
int led_state = 0;

/***********************************************************
 * Functions
 */

// Callback: receiving any WebSocket message
void onWebSocketEvent(uint8_t client_num,
                      WStype_t type,
                      uint8_t * payload,
                      size_t length) {

  // Figure out the type of WebSocket event
  switch(type) {

    // Client has disconnected
    case WStype_DISCONNECTED:
      Serial.printf("[%u] Disconnected!\n", client_num);
      break;

    // New client has connected
    case WStype_CONNECTED:
      {
        IPAddress ip = webSocket.remoteIP(client_num);
        Serial.printf("[%u] Connection from ", client_num);
        Serial.println(ip.toString());
      }
      break;

    // Handle text messages from client
    case WStype_TEXT:

      // Print out raw message
      Serial.printf("[%u] Received text: %s\n", client_num, payload);

      // Toggle LED
      if ( strcmp((char *)payload, "toggleLED") == 0 ) {
        led_state = led_state ? 0 : 1;
        Serial.printf("Toggling LED to %u\n", led_state);
        digitalWrite(led_pin, led_state);

      // Report the state of the LED
      } else if ( strcmp((char *)payload, "getLEDState") == 0 ) {
        sprintf(msg_buf, "%d", led_state);
        Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf);
        webSocket.sendTXT(client_num, msg_buf);

      // Message not recognized
      } else {
        Serial.println("[%u] Message not recognized");
      }
      break;

    // For everything else: do nothing
    case WStype_BIN:
    case WStype_ERROR:
    case WStype_FRAGMENT_TEXT_START:
    case WStype_FRAGMENT_BIN_START:
    case WStype_FRAGMENT:
    case WStype_FRAGMENT_FIN:
    default:
      break;
  }
}

// Callback: send homepage
void onIndexRequest(AsyncWebServerRequest *request) {
  IPAddress remote_ip = request->client()->remoteIP();
  Serial.println("[" + remote_ip.toString() +
                  "] HTTP GET request of " + request->url());
  request->send(SPIFFS, "/index.html", "text/html");
}

// Callback: send style sheet
void onCSSRequest(AsyncWebServerRequest *request) {
  IPAddress remote_ip = request->client()->remoteIP();
  Serial.println("[" + remote_ip.toString() +
                  "] HTTP GET request of " + request->url());
  request->send(SPIFFS, "/style.css", "text/css");
}

// Callback: send 404 if requested file does not exist
void onPageNotFound(AsyncWebServerRequest *request) {
  IPAddress remote_ip = request->client()->remoteIP();
  Serial.println("[" + remote_ip.toString() +
                  "] HTTP GET request of " + request->url());
  request->send(404, "text/plain", "Not found");
}

/***********************************************************
 * Main
 */

void setup() {
  // Init LED and turn off
  pinMode(led_pin, OUTPUT);
  digitalWrite(led_pin, LOW);

  // Start Serial port
  Serial.begin(115200);

  // Make sure we can read the file system
  if( !SPIFFS.begin()){
    Serial.println("Error mounting SPIFFS");
    while(1);
  }

  // Start access point
  WiFi.softAP(ssid, password);

  // Print our IP address
  Serial.println();
  Serial.println("AP running");
  Serial.print("My IP address: ");
  Serial.println(WiFi.softAPIP());

  // On HTTP request for root, provide index.html file
  server.on("/", HTTP_GET, onIndexRequest);

  // On HTTP request for style sheet, provide style.css
  server.on("/style.css", HTTP_GET, onCSSRequest);

  // Handle requests for pages that do not exist
  server.onNotFound(onPageNotFound);

  // Start web server
  server.begin();

  // Start WebSocket server and assign callback
  webSocket.begin();
  webSocket.onEvent(onWebSocketEvent);
  
}

void loop() {
  
  // Look for and handle WebSocket data
  webSocket.loop();
}

Save your code (we’ll need the Arduino directory structure for SPIFFS in an upcoming step). I’ll give my program a name like “esp32_websocket_host.” Upload the program to your ESP32 and open a serial console with a baud rate of 115200. You should see the IP address of the ESP32 printed to the screen. When you run the Arduino soft access point software on the ESP32, the default IP address is 192.168.4.1.

ESP32 Access Point IP Address

Web Page Code

Let’s write a simple web page! Like most modern pages, it will contain a mixture of HTML and JavaScript. We leave out CSS, but you’re welcome to create your own .css file, if you wish to make the page look a little nicer. If you look back up in the Arduino code, you’ll see that we have a function to serve up a .css file. However, we will not be making a .css file for the sake of simplicity in this tutorial.

For SPIFFS to work, we need to put the files we wish to upload to the ESP32 in a folder named data/ inside the Arduino project directory:

esp32_websocket_host
 |_ esp32_websocket_host.ino
 |_ data
     |_ index.html

In Arduino, click Sketch > Show Sketch Folder to navigate to your project directory. Create a folder named data and create a new file named index.html inside that new folder. Open index.html with your favorite editor.

In index.html, paste the following code:

<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>

<script language="javascript" type="text/javascript">

var url = "ws://192.168.4.1:1337/";
var output;
var button;
var canvas;
var context;

// This is called when the page finishes loading
function init() {

    // Assign page elements to variables
    button = document.getElementById("toggleButton");
    output = document.getElementById("output");
    canvas = document.getElementById("led");
    
    // Draw circle in canvas
    context = canvas.getContext("2d");
    context.arc(25, 25, 15, 0, Math.PI * 2, false);
    context.lineWidth = 3;
    context.strokeStyle = "black";
    context.stroke();
    context.fillStyle = "black";
    context.fill();
    
    // Connect to WebSocket server
    wsConnect(url);
}

// Call this to connect to the WebSocket server
function wsConnect(url) {
    
    // Connect to WebSocket server
    websocket = new WebSocket(url);
    
    // Assign callbacks
    websocket.onopen = function(evt) { onOpen(evt) };
    websocket.onclose = function(evt) { onClose(evt) };
    websocket.onmessage = function(evt) { onMessage(evt) };
    websocket.onerror = function(evt) { onError(evt) };
}

// Called when a WebSocket connection is established with the server
function onOpen(evt) {

    // Log connection state
    console.log("Connected");
    
    // Enable button
    button.disabled = false;
    
    // Get the current state of the LED
    doSend("getLEDState");
}

// Called when the WebSocket connection is closed
function onClose(evt) {

    // Log disconnection state
    console.log("Disconnected");
    
    // Disable button
    button.disabled = true;
    
    // Try to reconnect after a few seconds
    setTimeout(function() { wsConnect(url) }, 2000);
}

// Called when a message is received from the server
function onMessage(evt) {

    // Print out our received message
    console.log("Received: " + evt.data);
    
    // Update circle graphic with LED state
    switch(evt.data) {
        case "0":
            console.log("LED is off");
            context.fillStyle = "black";
            context.fill();
            break;
        case "1":
            console.log("LED is on");
            context.fillStyle = "red";
            context.fill();
            break;
        default:
            break;
    }
}

// Called when a WebSocket error occurs
function onError(evt) {
    console.log("ERROR: " + evt.data);
}

// Sends a message to the server (and prints it to the console)
function doSend(message) {
    console.log("Sending: " + message);
    websocket.send(message);
}

// Called whenever the HTML button is pressed
function onPress() {
    doSend("toggleLED");
    doSend("getLEDState");
}

// Call the init function as soon as the page loads
window.addEventListener("load", init, false);

</script>

<h2>LED Control</h2>

<table>
    <tr>
        <td><button id="toggleButton" onclick="onPress()" disabled>Toggle LED</button></td>
        <td><canvas id="led" width="50" height="50"></canvas></td>
    </tr>
</table>

Save this file. With your ESP32 plugged into your computer, open Arduino and click Tools > ESP32 Sketch Data Upload. Wait a moment, and all the files in the data/ folder (well, just the 1 file, index.html, for this example) should be uploaded to the ESP32.

Uploading files to the ESP32 using SPIFFS

Run It!

With the index.html file uploaded and the Arduino code running, you should be able to connect to the ESP32’s access point. Using your phone or computer, search for open WiFi access points and connect to the one named ESP32-AP. When asked for a password, enter LetMeInPlz (or whatever you set the AP password to in the Arduino code).

Since we are not running a captive portal, we will need to specifically browse to the IP address of the ESP32. Open a browser and enter 192.168.4.1 (or whatever you discovered the IP address of the ESP32 to be). You should be served the index.html page from the ESP32, which looks like a button and a circle. Zoom in, if needed (as we’re not doing any fancy formatting or CSS here).

Press the Toggle LED button, and you should see the LED connected to the ESP32 flicker to life. The circle on the page should also turn red to denote the state of the LED.

Using an ESP32 as a web server and using WebSockets to control hardware

Going Further

Feel free to use this as the basis for your next Internet-controlled hardware project. I suppose it fits in the category of “IoT,” and WebSockets can be super useful for controlling hardware with much less latency than many other methods. You can also use them to get fast updates, if you wish to create a custom dashboard showing sensor data.

 

 

Key listener in Phaser

Getting Started with Phaser Part 3: Sprites and Movement

In the last part, we added the Phaser framework to a web page and said “hello” on a canvas element. In this part, we create a simple sprite (a ball) and move it around the canvas.

Why a ball? I consider it to be a test of whether gaming is possible on a particular platform. In the simplest sense, reading user input and moving an object (a filled circle, in this case) shows that real time interactivity is possible. This can be on a computer with a keyboard or on an 8×7 LED array with a joystick.

Directory Structure

In your Games directory, create a new folder named BallWorld. In that directory, create two more directories, js and img. This process should look familiar; the only new thing is that we added an img directory, which is where we’ll store our image files.

Directory structure for BallWorld

Draw a Sprite

There are plenty of ways to create 2D graphics for your game. In these tutorials, we will rely on the free GNU Image Manipulation Program (GIMP) to create sprites. Head to GIMP’s download page and download the latest stable version for your operating system. Run the installer, accepting all the defaults.

Open up GIMP, and select File > New. You will be presented with a new image dialog. Set the Width to 20 and Height to 20. Click on Advanced Options and set Fill with to Transparency.

Creating a new GIMP image

Click OK to create a new image. If you don’t see the Toolbox window, select WindowsToolbox. From the Toolbox, click on the Ellipse Select Tool.

Ellipse select tool in GIMP

Back in your image window, create a circle by dragging a region from one corner to the opposite corner.

Making a circle in GIMP

In the Toolbox, select the Bucket Fill Tool.

GIMP Bucket Fill Tool

Click the color swatch at the bottom of the Toolbox to select a new color. In the Change Foreground Color window, choose the color red (e.g. set the HTML notation to ff0000).

GIMP color selector

Click OK. Click inside the selection circle in the main image window. The circle will fill in with red, and you will notice that some of the pixels around the edge are semi-transparent. This is a technique called antialiasing, which works to make the edges of an image look smoother.

Filled circle

Select File Export As… Save the file as ball.png in …/Projects/Games/BallWorld/img. When prompted, keep the default options in the Export Image as PNG window.

GIMP export image

Click Export. And that’s it! Creating a simple ball sprite is relatively easy. Creating great looking sprites, however, is its own art form. If you are feeling particularly lazy, you are welcome to save the sprite from this image:

Ball sprite

Create the Web Page

In an editor, enter the following:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8" />
    <title>Ball World</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background: #000000;
        }
    </style>
    <script src="js/phaser.min.js"></script>
</head>
<body>
    <script src="js/start.js"></script>
</body>
</html>

Save it as index.html in …/Projects/Games/BallWorld. There are a few difference between the HTML in this example and in the last part.

We change the title to <title>Ball World</title> , which simply updates the name of the page. The name is often displayed in the tab on the browser.

We also add

margin: 0;
padding: 0;

to the body’s CSS. This explicitly sets the margin and padding of the body element to nothing. The body element contains all of the page’s main content. In this case, it holds the Phaser canvas, and by explicitly setting the margin and padding, we can later configure the canvas to fill up the browser window (as much as possible while still maintaining the original aspect ratio).

Additionally, we change the page’s background color to black (#000000 ), which works well for many games, as it mimics a black border or bezel.

Finally, we removed the line <div id=”area”></div> as we want Phaser to just append its own div to the page. By letting Phaser control the div, we can more easily set the canvas to fill up the browser window.

Write Some JavaScript

To install Phaser, copy phaser.min.js from the downloaded Phaser ZIP file to …/Projects/Games/BallWorld/js.

We will write the main game code one piece at a time so we can discuss each section. The code in its entirety will be posted at the end (if you just want to scroll down and copy it).

Create a new text file and start by defining a new Phaser game object. Note that we no longer specify the div parameter as we did in Part 2. By leaving the div id parameter as an empty string, Phaser will automatically create a canvas element and append it to the page’s body.

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

To this, add the preload() , create() , and update()  functions. For now, leave the functions empty. This is our single-state Phaser template.

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {

}

// Called after preload
function create() {

}

// Called once every frame, ideally 60 times per second
function update() {

}

In the create()  function, set the scaleMode  and pageAlign  properties. By setting scaleMode  to SHOW_ALL , the canvas stretches to fill as much of the browser window as possible while maintaining the previously defined proportions (1:1 in this case, as we set the game area to 500×500). By setting pageAlignHorizontally  and pageAlignVertically  to true , we move the game area to the middle of the page.

Stretching the game area and moving it to the middle works as a good compromise for playing games on desktop and mobile devices, regardless of portrait or landscape orientation.

Finally, set the game area’s background color to light blue (#87CEEB ), which contrasts the web page’s black background.

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {

}

// Called after preload
function create() {

    // Center game canvas on page
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    game.scale.pageAlignHorizontally = true;
    game.scale.pageAlignVertically = true;
    
    // Change background color
    game.stage.backgroundColor = '#87CEEB';
}

// Called once every frame, ideally 60 times per second
function update() {

}

At this point, you should be able to run the game with:

node SimpleServer.js BallWorld/

Open up a web page, navigate to http://localhost:4242/, and you should be presented with a blue square that stretches to fill up the height or width of the page (whichever is smaller).

Blue background in Phaser

Back in the code, add game.load.image(‘ball’, ‘img/ball.png’) to the preload()  function. We use the game object to load the ball.png image (the one that we made in the Draw a Sprite section) and assign it to the asset label ‘ball’  (also known as a key).

In create() , we add the sprite using game.add.sprite()  and position it at the center of the game area, which can be found with game.world.centerX  and game.world.centerY . We then set the origin of the sprite, using this.ball.anchor.set(0.5, 0.5) , to the middle of the sprite to make it easier to center.

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {

    // Load our image assets
    game.load.image('ball', 'img/ball.png');
}

// Called after preload
function create() {

    // Center game canvas on page
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    game.scale.pageAlignHorizontally = true;
    game.scale.pageAlignVertically = true;
    
    // Change background color
    game.stage.backgroundColor = '#87CEEB';

    // Add the ball to the middle of the game area
    this.ball = game.add.sprite(game.world.centerX, game.world.centerY, 'ball');
    this.ball.anchor.set(0.5, 0.5);
}

// Called once every frame, ideally 60 times per second
function update() {

}

Note that after adding the sprite to the game, we assign the sprite object to the variable ball. If we just use var ball , the object would only live within the scope of the create()  function. In order to access the ball object from other functions, like update() , we attach the object to this , which refers to the game state (created as the fifth parameter in new Phaser.Game(…) . Any time we want to access the ball object within this particular game state, we need to use this.ball .

If you refresh the page (assuming the server is still running), you should see a red circle appear in the middle of the game area.

Loading a sprite in Phaser

To move the ball, we need to define a default velocity for the ball (i.e. how many pixels does the ball move each frame) and add some key listeners to the game.

We could hardcode the ball’s velocity, but that’s generally considered bad practice. By keeping all of the game’s parameters in one place, we can tweak the game design without having to hunt down all the hardcoded values. For our purposes, we will define a single global object with the game’s name. This object will hold key/value pairs that set the game’s parameters.

To hold the game’s parameters (we only have 1 right now), create a global object with var BallWorld , and assign it the property velocity: 8 .

In create() , create a keyboard listener using game.input.keyboard.createCursorKeys()  and assign it to this.keys  (another custom game state property).

In the update()  function, we check for specific key presses with this.keys.KEY_NAME.isDown . We can then move the ball’s position using this.ball.x  and this.ball.y .

// Global object to store our game parameters
var BallWorld = {
    velocity: 8
};

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {

    // Load our image assets
    game.load.image('ball', 'img/ball.png');
}

// Called after preload
function create() {

    // Center game canvas on page
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    game.scale.pageAlignHorizontally = true;
    game.scale.pageAlignVertically = true;
    
    // Change background color
    game.stage.backgroundColor = '#87CEEB';

    // Add the ball to the middle of the game area
    this.ball = game.add.sprite(game.world.centerX, game.world.centerY, 'ball');
    this.ball.anchor.set(0.5, 0.5);

    // Add key input to the game
    this.keys = game.input.keyboard.createCursorKeys();
}

// Called once every frame, ideally 60 times per second
function update() {

    // Poll the arrow keys to move the ball
    if (this.keys.left.isDown) {
        this.ball.x -= BallWorld.velocity;
    }
    if (this.keys.right.isDown) {
        this.ball.x += BallWorld.velocity;
    }
    if (this.keys.up.isDown) {
        this.ball.y -= BallWorld.velocity;
    }
    if (this.keys.down.isDown) {
        this.ball.y += BallWorld.velocity;
    }
}

Refresh the page again, and use the arrow keys to move the ball.

Key listener in Phaser

You might notice that you are able to drive the ball past the edges of the game area. This is usually not a desirable behavior, so we can add bounds checking on the ball each frame. This is accomplished by setting the ball’s edges’ x and y coordinates to the bound’s edge should the ball pass the boundary.

In update() , add the following:

// Global object to store our game parameters
var BallWorld = {
    velocity: 8
};

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, '', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {

    // Load our image assets
    game.load.image('ball', 'img/ball.png');
}

// Called after preload
function create() {

    // Center game canvas on page
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    game.scale.pageAlignHorizontally = true;
    game.scale.pageAlignVertically = true;
    
    // Change background color
    game.stage.backgroundColor = '#87CEEB';

    // Add the ball to the middle of the game area
    this.ball = game.add.sprite(game.world.centerX, game.world.centerY, 'ball');
    this.ball.anchor.set(0.5, 0.5);

    // Add key input to the game
    this.keys = game.input.keyboard.createCursorKeys();
}

// Called once every frame, ideally 60 times per second
function update() {

    // Poll the arrow keys to move the ball
    if (this.keys.left.isDown) {
        this.ball.x -= BallWorld.velocity;
    }
    if (this.keys.right.isDown) {
        this.ball.x += BallWorld.velocity;
    }
    if (this.keys.up.isDown) {
        this.ball.y -= BallWorld.velocity;
    }
    if (this.keys.down.isDown) {
        this.ball.y += BallWorld.velocity;
    }

    // Prevent ball from escaping outside the stage's boundaries
    var halfWidth = this.ball.width / 2;
    var halfHeight = this.ball.height / 2;
    if ((this.ball.x - halfWidth) < 0) {
        this.ball.x = halfWidth;
    }
    if ((this.ball.x + halfWidth) > game.width) {
        this.ball.x = game.width - halfWidth;
    }
    if ((this.ball.y - halfHeight) < 0) {
        this.ball.y = halfHeight;
    }
    if ((this.ball.y + halfHeight) > game.height) {
        this.ball.y = game.height - halfHeight;
    }
}

Try refreshing the page one more time, and you should notice that the ball is unable to move outside the game’s boundaries.

Checking game boundaries with Phaser

Conclusion

At this point, you should have the basics for drawing sprites and moving them around the screen. While this is a seemingly simple step, it is an important one for creating the basics of arcade and sprite-based games.

 

 

My first Phaser game!

Getting Started with Phaser Part 2: Drawing Text

In the first part, we created a simple web server and page. We didn’t even touch Phaser! However, that is about to change. In the second part of this series, we create a game area in an HTML div and draw some simple text on it using Phaser.

Directory Structure

In your Games directory, create another folder named HelloPhaser. Much like HelloWorld in the previous example, this will house our HTML and JavaScript files for serving the web page and game. Within HelloPhaser, create directory named js. This folder will hold all of our JavaScript.

Directory structure for HelloPhaser

Install Phaser

To install Phaser, we are going to download the library and simply copy it to our js directory. Start by navigating to Phaser’s GitHub page, and click Clone or download followed by Download ZIP.

Download the Phaser library

Once downloaded, unzip the file. Find the unzipped directory, and navigate to phaser-master/phaser-master/build. There, copy the file phaser.min.js. Go back to your Projects directory and paste the file in Games/HelloPhaser/js.

Create the Web Page

Create a new text document and copy in the following (note: I recommend manually typing each line so you get a feel for writing HTML and JavaScript. I’ll talk about what the code does after the code block).

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8" />
    <title>Hello</title>
    <style>
        body {
            background: #FFFFFF;
        }
    </style>
    <script src="js/phaser.min.js"></script>
</head>
<body>
    <div id="area"></div>
    <script src="js/start.js"></script>
</body>
</html>

Save the document as index.html in Games/HelloPhaser.

This file acts as our basic web page. Its primary purpose is to set up a game area (div) on the page and load in JavaScript. The JavaScript handles the bulk of the drawing in the game area.

In the <head> section, we use some simple CSS via the background property to set the web page’s background color to white (#FFFFFF). See this table for colors and their hexadecimal codes. We also load in the Phaser library using the <script> tag.

In <body>, we define a <div> and name it “area.” We will reference this div later in our JavaScript code and draw Phaser objects in it. Finally, we load in another script, named “start.js,” which is where our main game code will live. We have not written start.js yet; that comes next.

Write Some JavaScript

Create a file and copy in:

// Create a new Phaser game object with a single state that has 3 functions
var game = new Phaser.Game(500, 500, Phaser.AUTO, 'area', {
    preload: preload,
    create: create,
    update: update
});

// Called first
function preload() {
}

// Called after preload
function create() {
    
    // Create some text in the middle of the game area
    var helloText = game.add.text(250, 250, 'Hello, Phaser!', { 
        fontSize: '32px', 
        fill: '#00F' 
    });
    helloText.anchor.set(0.5, 0.5);
}

// Called once every frame, ideally 60 times per second
function update() {
}

Save the file as start.js in Games/HelloPhaser/js.

At this point, you should have index.html in your page’s directory (HelloPhaser). Under the js directory in HelloPhaser, you should have phaser.min.js and start.js.

Files in HelloPhaser

Let’s look at what the code is doing. In the very first line (after the //… comment), we create a Phaser.Game  object and assign it to the the variable game . Phaser.Game is predefined in the Phaser library (documentation on it can be found here), and it is the core of the Phaser framework.

The first two parameters for Game  define the resolution of the game area. In this case, we set it to 500 pixels wide and 500 pixels high. I’m a big fan of square game areas, as it works well on desktop and mobile devices without needing to skew the graphics when switching between portrait and landscape modes. Feel free to change it for your application, though.

The next parameter, Phaser.AUTO, sets the renderer for the game area. As of the time of this blog post, there are three types available:

  • Phaser.CANVAS – Canvas element for drawing 2D graphics. Canvas is supported on most modern browsers.
  • Phaser.WEBGL – Use hardware-accelerated graphics to draw on the canvas. Some browsers support WebGL, and the user’s device must have the requisite hardware. 3D graphics are possible with WebGL.
  • Phaser.HEADLESS – Do not use any renderer. This is useful when you don’t want any graphics (such as running a game server).

In general, Phaser.AUTO is advisable, as it initially tries to use WEBGL and if the browser does not support it, the renderer reverts back to CANVAS.

The fourth parameter, ‘area’, tells the Game object where to draw. In this case, it is creating a canvas inside the div named ‘area’ (remember how we created a <div> element with the id “area” in our HTML?). If you leave this parameter blank, Phaser will simply append the Game object to the page.

The fifth parameter is the initial game state. If this parameter is set, Phaser will immediately start running the functions in this state. Note that Phaser supports multiple states in a game, and these can be things like start screen, game play, game over screen, menus, etc. For now, we will only use one state. Examining this state object, we see:

{
    preload: preload,
    create: create,
    update: update
}

Phaser states have a number of reserved names for functions. We are using preload , create , and update . We assign the functions (similarly named preload, create, and update) to the specially named keys, which are defined by Phaser.

The state will first run preload() , which is generally where assets like sprites and sounds are loaded. Since we don’t have any assets, the function is left blank. The function is still explicitly written here for the sake of clarity; we will add code to it later.

Second, the state will automatically run the create()  function once the preload has finished. This is where you can draw sprites, text, add key handlers, and so on. We add a single line of text, “Hello, Phaser!” to the game area, set at (250, 250), which is the middle of the area. We set the text’s anchor to (0.5, 0.5), which changes the origin point for the text to its center. For anchors, (0, 0) is the top left, and (1, 1) is the bottom right.

Finally, we define the update()  function. This function is automatically called every frame, and it is where we would put things like input polling, checking for collisions, etc. Because our “game” is just static text right now, there is no need to have anything happen in the update function.

Run It!

Open up a command prompt, navigate to your Games directory, and run the server (note that we need to specify HelloPhaser as our web page directory):

cd <PATH_TO_PROJECTS>/Games
node SimpleServer.js HelloPhaser/

Open up a web browser and navigate to http://localhost:4242. You should see your game (albeit a rather boring game):

My first Phaser game!

You can’t do much with this game, as we have not added any type of input handling or graphics updating. That will come next.

Conclusion

While it was not much of a game, we did use the Phaser framework to create some text in a canvas element, which is a huge step! This template (index.html, phaser.min.js, and start.js) will form the basis for future tutorials. You can simply copy phaser.min.js into your other games, although I recommend checking Phaser’s GitHub page for updates regularly.

If you are new to JavaScript, I highly recommend working through some chapters in the book Eloquent JavaScript (it is the book I used to teach myself JavaScript). The book is available online for free as well as in paperback copy on Amazon.

Continue to Part 3 to learn how to create sprites and add movement with key presses.

Phaser logo

Getting Started with Phaser Part 1: Web Server

As I learn to use the Phaser framework to make simple browser-based games, I figured I would chronicle my adventures and hopefully help others out.

“Why a web web server?” As it turns out, when most browsers run a page as a local file, it locks down access to many other files, which we need for our games. To read more about this, see this article.

To properly serve these files, we can use any number of existing web server software, but we will write a simple one using the Express framework in Node.js. In the future, we can modify this simple server to receive information back from our game to do things like control hardware and *gasp* make multiplayer games.

Install Node.js

Navigate to the Node.js download page and choose the installer for your operating system. Run it, and accept all the defaults to install Node.js on your computer.

If you are using Linux, most package managers can install it for your. For Debian, try apt-get install nodejs npm . For other distros, see this page.

If you are weird like me and enjoy the Linux command line but work in Windows, I highly recommend installing Git Bash through the Windows git installer. We’ll need to use git later, as GitHub allows us to host our projects for free. All of my command line screenshots will be from Git Bash.

Install a Text Editor

For these simple programs, we’ll use a basic text editor to write our code. If you haven’t already, install the text editor of your choice. You can use Notepad, but I’ll make a few recommendations for programming-focused editors:

Directory Structure

Create a folder named Games in a place where you like to keep your projects (e.g. My Documents/Projects). In Games, create another folder named HelloWorld.

Directory structure for our game server

The goal is to create a web server that lives in Games. Whenever we want to test a game, we run the server with Node.js and pass it the folder (as an argument) of the desired web site (e.g. “HelloWorld”).

A web site, in a practical sense, is just a collection of files on a computer that get served to a client upon request. For us, each project folder under Games will be its own site, and we just point our simple server to that folder in order to host the site.

Install Express.js

Express.js is a web application framework made for doing, well, lots of web stuff in Node.js. For our purposes, we are going to use it to make a simple web server that just serves files when asked (via HTTP requests). We could write our own server using the http module, but Express.js just makes things easier.

Open up a command prompt (e.g. Git Bash), navigate to your Games directory, and install Express.

cd <PATH_TO_PROJECTS>/Games
npm install express

You might notice that this creates a directory named node_modules in Games. This is where Node.js modules, like Express, are stored.

When you execute node and it attempts to load a module (i.e. through the require() instruction), Node.js first looks in the current directory for a folder named node_modules. If a module with the name in require() is not found, it begins to work its way up directories looking for node_modules. If the module is not found at all, the require() command will throw an error, and your program will fail.

Write the Server Code

Open up your text editor and copy in the code:

/**
 * Simple web server based on 
 * http://expressjs.com/en/starter/hello-world.html
 *
 * Prerequisites:
 *  - Node
 *  - Express (npm install express)
 * 
 * To use, save as a file (e.g. SimpleServer.js) and run with:
 *  node SimpleServer.js /PATH/TO/WWW/
 */
 
// Parameters
var sitePath = process.argv[2] || ".";
var port = 4242;

// Libraries
var express = require('express');
var app = express();

// Request logging
app.use(function(req, res, next) {
    console.log(req.url);
    next();
});

// Start server
console.log(sitePath);
console.log("Starting server in: " + __dirname + '/' + sitePath);
app.use(express.static(__dirname + '/' + sitePath));
app.listen(port, function() { 
    console.log("Server running at: http://localhost:" + port)
});

That’s right, in about 15 lines of actual code, we have a functioning web server. Neat. In all honesty, though, Express is doing most of the heavy lifting for us.

Save the file as SimpleServer.js in the Games directory.

Create a Simple Web Site

Our site will be a single page with a title and some text in the body. In later parts, we will add a Canvas element and begin using Phaser to create games.

Create a new text document in your editor and copy in the following:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Page</title>
</head>
<body>
    <h1>Hello, world</h1>
    <p>This is my page. There are many like it, but this one is mine.</p>
</body>
</html>

Save it as index.html in Games/HelloWorld. At this point, your directory structure in <PATH_TO_PROJECTS>/Games should look like this:

Games directory tree

 

Run the Server

In your command prompt, navigate to the Games directory and run the server, specifying the HelloWorld directory as the root for your web site.

cd <PATH_TO_PROJECTS>/Games
node SimpleServer.js HelloWorld/

If all goes well, you should see a note appear in the console that the server is running at http://localhost:4242.

Running a simple server

Open up a web browser and navigate to http://localhost:4242. You should see your page.

My first page

If you look at the console, you’ll see that a ‘/’ has appeared.

Console showing HTTP request

This means that a client requested the website’s root directory (‘/’). The server responded by sending index.html as a result, which is the default file for most websites. In this case, the root directory is HelloWorld, as we specified when we started the server.

Conclusion

We did not even touch Phaser in this part. Crazy, I know, but we needed to create a basic structure for hosting our games before we can even make them. Such are the joys of browser-based games.

If you aren’t familiar with HTML, now is a good time to play with the web page, index.html. We won’t actually do too much in HTML, but it’s good to be familiar with how tags, loading files from source, and a little bit of CSS work. Geek Champ has a great getting started with HTML tutorial.

When you are ready, continue to Part 2.

Virtual Gamepad Phaser Plugin

Virtual Gamepad Plugin for Phaser

Virtual Gamepad Phaser Plugin

I am currently working on a simple arcade game intended for smartphones, and after some research, I decided to develop it using JavaScript and Phaser. Getting an arcade-style controller on a mobile app requires a specialized “joystick” (the accompanying buttons are fairly straightforward). The basic concept is to have an area where a player can touch that determines the direction and distance of the joystick. The “joystick” should also be limited in how far it moves. The main game loop polls the joystick for information like angle and distance.

I found a few existing options in Phaser. The first is the beautiful and well-designed Virtual Joystick Plugin, but it costs $16. The next is an implementation of a Virtual Gamecontroller that creates a d-pad using buttons, which is useful, but lacks the analog nature of a true joystick. Finally, I found Eugenio Fage’s Touch Control Plugin.

The Touch Control Plugin worked almost exactly how I expected a virtual joystick to function, but instead of being in a static location on the screen, the user had to touch somewhere in the canvas to make the “joystick” appear. By examining how Eugenio performed the joystick calculations, I was able to make a static joystick overlay. The main difference is that Eugenio’s code uses events to determine presses on the joystick, and I found it to be sluggish when paired with a button. Like a bad JavaScript programmer, I changed it to polling (which Phaser does anyway in its update loop).

VirtualGamepad in action

To use the joystick, press down with your finger/thumb/mouse over the joystick area, and the “pad” should follow your pointer (out to a certain distance from the joystick’s center). The direction, rectangular, and polar properties should update accordingly. The button on the right should be fairly self-explanatory. A game using the Virtual Gamepad plugin just needs to poll the joystick and button’s properties on every update.

The most recent source code for the Virtual Gamepad plugin can be found on GitHub: https://github.com/ShawnHymel/phaser-plugin-virtual-gamepad/

A playable demo of the Virtual Gamepad in action can also be found on GitHub: http://shawnhymel.github.io/phaser-plugin-virtual-gamepad/

Edison Base Block

Run a Script on Edison Boot

Edison Base Block

Image courtesy of sparkfun.com

This one took me forever to figure out, and thanks to some posts over at the Intel Edison forums, I finally managed to get a JavaScript program to run as soon as the Edison starts. I know that the XDK also runs a service to execute JavaScript programs on boot, but I wanted a more general solution. One could configure the systemd service file to run any program/script on boot (assuming the Edison has the right interpreter).

Continue Reading

Writing Your Own UPM Module: Getting Started

Intel-IoT_LogoImage courtesy of Intel iot-devkit GitHub account

UPM (Useful Packages and Modules) is a high-level library that relies on MRAA to talk to hardware peripherals over GPIO, SPI, UART, etc. Both libraries were created by Intel and come packaged with the Galileo and Edison boards. MRAA has support for other single board computers, like the Raspberry Pi and Beaglebone Black, according to the MRAA documentation.

MRAA is the low-level driver that controls the individual bits for the GPIO. UPM is a collection of libraries (modules) that provides the necessary software for various sensors, motor drivers, etc.

Continue Reading
Edison with wires!

Bluetooth Low Energy Peripherals with JavaScript

Edison with wires!

Previously, I’ve shown how to enable Bluetooth Low Energy (BLE) connections using Python. In the past few months, I have been furiously learning JavaScript for an upcoming set of tutorials dealing with the Intel® Edison. Along the way, I needed to make a demo using BLE and JavaScript, which invariably led me to the bleno module.

Bleno is a great tool, but I found some of the examples a little confusing to follow (I get easily lost when a program is split into more than 2 files without a well-documented API). As a result, I constructed a simple echo server demo program that illustrates how characteristics work in BLE.

Continue Reading