Remote Pad

Imagine poder controlar um jogo em seu computador usando seu smartphone como gamepad?

racepad

Remote Pad - Ideia

architecture

Agenda

  • html5 - events, hardware access
  • nodejs - event driven, assynchronous I/O
  • mqtt - real time communication
  • robotjs - envios de tecla através de software
  • vuejs - unobtrusive reactivity system

html5

Device Orientation Events

Eventos no DOM para obter informações sobre a orientação e movimentação física do dispositivo móvel.

  • Giroscópio
  • Acelerômetro
  • Compasso

Device Orientation Events

device-events

Eventos:

  • deviceorientation
  • devicemotion
  • compassneedscalibration

DeviceMotion suporte

Touch Events suporte

Outras APIs

  • Ambient Light API
  • Geolocation API
  • Battery Status API
  • getUserMedia API
  • Vibration API
  • Web Notification API
  • Web Speech API

NodeJS

NodeJS usa um modelo orientado a eventos, com E/S não bloqueante que o torna leve e eficiente.

Como o Javascript é restrito ao browser foi necessário criar outros módulos como:

  • Buffer
  • Child Process
  • File System
  • OS
  • Stream, etc.

NodeJS

Node é projetado para construir aplicações escaláveis de rede. A seguir um exemplo de servidor que pode atender a várias conexões concorrentemente:

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello World\n')
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

Benchmark

$ pm2 start index.js

nodejs-server

Benchmark

$ locust --host=http://localhost:3003

locustio

NodeJS Event Loop

threading_node

NodeJS Event Loop

robotjs

RobotJS

Exemplo

var robot = require('robotjs')

// Press enter.
robot.keyTap('enter')

// hold the shift key
robot.keyToggle('shift', 'down')

RobotJS

Usa node-gyp ou Node.js native addon build tool

Ferramenta de linha de comando multi plataforma escrita em NodeJS para compilação de módulos nativos (C/C++) para NodeJS

Requisição de teclas do teclado é escrita em C/C++ e há um binding para NodeJS

MQTT

Message Queue Telemetry Transport

É um protocolo de mensagens baseado em publish/subscribe, extremamente simples e leve, projetado para redes com pouca banda, alta latência ou não confiáveis.

Princípios: minimizar o uso da banda de rede e recursos do dispositivo enquanto tenta maximinizar a confiabilidade e oferecer algum grau de garantia de entrega das mensagens.

Também usado nos chamados M2M (Machine-to-machine) ou Internet of Things

Quality of service

mqtt-qos

Mosca

MQTT broker as a module

var mosca = require('mosca')
var settings = {
    port: 1883
}
var server = new mosca.Server(settings)
server.on('published', function(packet, client) {
    console.log('Published', packet.topic, packet.payload)
})
server.on('ready', function setup() {
    console.log('Mosca server is up and running')
})

Mosca

Exemplo Cliente

var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://localhost:1883')

client.on('connect', function() {
    client.subscribe('presence')
    client.publish('presence', 'Hello mqtt')
})

client.on('message', function(topic, message) {
    // message is Buffer
    console.log(message.toString())
    client.end()
})

MQTT no browser

MQTT no browser

var btnSend = document.getElementById('mqtt_send')
var message = document.getElementById('mqtt_message')
var result = document.getElementById('mqtt_result')
var client = mqtt.connect('ws://test.mosquitto.org:8080/mqtt')
client.subscribe('mqtt/demo')

client.on('message', function(topic, payload) {
    result.innerHTML = [topic, payload].join(': ')
})

btnSend.onclick = function (e) {
    e.preventDefault()
    client.publish('mqtt/demo', message.value)
}

https://github.com/mqttjs/MQTT.js#browser

WebSockets suporte

VueJS

Progressive Framework para construção de interfaces de usuário

vuejs-render

Reactive System

Trecho para inicialização da variável que indica mudanças no eixo Y:

export default {
    data () {
        acceleration: {
            y: 0
        }
    },
    mounted () {
        if (window.DeviceMotionEvent !== undefined) {
            window.ondevicemotion = (e) => {
                this.acceleration.y = e.accelerationIncludingGravity.y || 0
            }
        }
    }
}

Reactive System

Trecho para indicar que o usuário está virando para a esquerda ou direita:

export default {
    computed: {
        isTurningLeft () {
            const { accelerationSensibility } = this.$store.state
            this.keypress.left =
                this.acceleration.y < accelerationSensibility * -1
            return this.keypress.left
        },
        isTurningRight () {
            const { accelerationSensibility } = this.$store.state
            this.keypress.right =
                this.acceleration.y > accelerationSensibility
            return this.keypress.right
        }
    }
}

Remote Pad

Remote Pad

Remote Pad

Protocolo de envio de comandos - Cliente

Todos os jogadores

{
    "keypress": {
      "Y": false,
      "X": false,
      "B": false,
      "A": false,
      "left": false,
      "right": false,
      "up": false,
      "down": false
    }
}

Remote Pad

Protocolo de envio de comandos - Servidor

Jogador 1

{
    "left": "left",
    "right": "right",
    "up": "up",
    "down": "down",
    "B": "shift",
    "A": "z",
    "Y": "control",
    "X": "space"
}

Remote Pad

Protocolo de envio de comandos - Servidor

Jogador 2

{
    "left": "a",
    "right": "d",
    "up": "w",
    "down": "s",
    "B": "e",
    "A": "x",
    "Y": "q",
    "X": "r"
}

Remote Pad

Servidor

const topics = ['alice', 'bob', 'carol', 'david']

server.on('published', function(packet, client) {
    const [ type, player ] = packet.topic.split('/')
    if (type.lastIndexOf('pad', 0) == 0) {
        const commands = JSON.parse(packet.payload.toString())
        pad(commands, clients[player])
    }
})

Remote Pad

Servidor

var robot = require('robotjs')

module.exports = function (commands, player) {
    for (let prop in commands) {
        let key = player.keys[prop]
        if (key) {
            let toggle = (commands[prop] ? 'down' : 'up')
            robot.keyToggle(player.keys[prop], toggle)
        }
    }
}

Remote Pad

architecture

Funcionamento

funcionamento

Tipos de controles

race-pad

directional-pad

Controles específicos para outros jogos

Mario Party

Controles adaptativos

Referências

Referências

Referências

<Obrigado pela atenção!>

Qualquer dúvida entre em contato.