Qui suis-je ? ➔ J’aime ◆ Développer des produits utilisés ◆ Pratiquer et transmettre l’agilité ➔ Je fais ◆ Pilotage de projets à l’Inist-CNRS (IST, doc …) ◆ Associé dans une boite de jeux en ligne ◆ Surtout du NodeJS & PHP (actuellement) @kerphi79 @ezpaarse - https://github.com/ezpaarse-project/ @istexdev - https://github.com/istex/ @bibcnrs - https://github.com/BibCnrs/ Stéphane Gully
Contexte ➔ Les jeux de Buzzville sont développés en Flash. ➔ Flash n’est pas supporté par les smartphones. ➔ Dans cette situation Buzzville est condamné à rester sur le marché des desktop.
Contexte ➔ Le marché des smartphones est aujourd’hui incontournable pour un site web : ◆ 15% de consultations sur mobiles (31% au niveau mondial !) ◆ 8% de consultations par tablettes (6,6% au niveau mondial) ➔ Le concept de buzzville encourage la fidélité et propose des jeux de type “casual game” propice à un usage en pointillé par ex sur mobile.
C’est pourquoi Buzzville doit évoluer vers une compatibilité mobiles et tablettes ! 1. Responsive web design 2. Flash → HTML5 3. App Android/iPhone native ?
Responsive web design ➔ Travail en cours avec la migration progressive des pages vers PHP. ◆ Bootstrap ◆ {less} ➔ Pages clés ◆ Page jeux (ex: fishmania) ◆ Page d’accueil
Flash → HTML5 ➔ Choix de Phaser http://phaser.io/ https://github.com/photonstorm/phaser ◆ Orienté mobile ◆ Orienté 2D, basé sur pixi.js pour le rendu → perf ◆ Fonctionnalités riches moteurs de physique, sprites, anim, particules, audio, gestion du scaling (ratio, fs), breakout, … ◆ C’est du JS KISS
Android/iPhone natif ? ➔ Pourquoi ? ◆ Une App permettrait probablement une augmentation de la fidélisation ◆ Une webapp ne peut pas passer en plein écran sur iPhone ➔ Comment ? ◆ En portant les jeux HTML5 avec CocoonJS ou PhoneGap ◆ Mais quid des autres aspects de Buzzville : micropaiements, authentification, events, boutique, autres pages … ?
Architecture actuelle ➔ La communication entre le jeu flash et Naxs se fait par une connexion socket. ➔ Le protocole est propriétaire et non documenté mais repose plus ou moins sur un système de messages JSON. Démonstration sur Froak
Architecture cible ➔ Reverse engineering sur le protocole ➔ Remplacer la connexion socket par une connexion websocket ➔ Réécrire les jeux Flash avec Phaser
Serveur web ➔ Initialisation de l’application NodeJS mkdir aperoweb-phaser && cd aperoweb-phaser/ npm init npm install express --save touch index.js ➔ Serveur web avec Express http://expressjs.com/starter/hello-world.html var express = require('express'); var app = express(); var server = require('http').Server(app); server.listen(3000, '127.0.0.1', function () {
Serveur web ➔ Page HTML5 qui permettra d’exécuter le jeu mkdir public/ touch index.html ➔ Configuration d’Express pour les pages statiques http://expressjs.com/starter/static-files.html app.use(express.static('public')); ➔ Serveur web accessible à toute la salle https://ngrok.com/ ngrok -subdomain="apero" 3000 http://apero.ngrok.com/
Canvas HTML5 ➔ Initialisation du canvas avec Phaser http://phaser.io/tutorials/making-your-first-phaser-game ◆ Format 16/9 : 1024 x 576 ◆ Phaser.AUTO ou Phaser.CANVAS ou Phaser.WEBGL ◆ preload ◆ create ◆ update
Une bière = un sprite Posons une bière sur le canvas http://www.iconarchive.com/show/farm-fresh-icons-by-fatcow/beer-icon.html ➔ assets/beer-icon-1.png (32x32) ➔ Chargement de la ressource game.load.image('beer', 'assets/beer-icon-1.png'); ➔ Création d’un sprite var beer = game.add.sprite(500, 40, 'beer'); ➔ Réglage de la couleur du fond game.stage.backgroundColor ➔ Occupe tout l’espace disponible sur l’écran game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
Une bière pour physicien http://phaser.io/tutorials/making-your-first-phaser-game/part4 ➔ Chargeons un moteur de physique dans notre jeu game.physics.startSystem(Phaser.Physics.ARCADE); ➔ Appliquons ce moteur de physique à notre bière game.physics.arcade.enable(beer); ➔ Donnons une gravité à notre bière beer.body.gravity.y = 400; ➔ Considérons que les bords du jeu sont “durs” aux yeux de la bière ... beer.body.collideWorldBounds = true; ➔ Notre bière est élastique beer.body.bounce.y = 0.4;
Bières cliquables Quand on clique sur une bière détruisons la ! ➔ La bière doit réagir au clic http://phaser.io/docs/2.4.4/Phaser.Component.InputEnabled.html#inputEnabled beer.inputEnabled = true; beer.input.useHandCursor = true; ➔ Capture l’évènement au moment du clic http://phaser.io/docs/2.4.4/Phaser.Events.html#onInputDown http://phaser.io/docs/2.4.4/Phaser.Signal.html#add beer.events.onInputDown.add(function (clickedBeer) { clickedBeer.destroy(); });
Bières buvables Quand on clique sur une bière buvons la avec un peu de mousse ! ➔ De la mousse → plein de bulles → une bulle ! ➔ assets/bubble.png (32x32) game.load.image('bubble', 'assets/bubble.png'); ➔ Générateur de mousse = Particles emitter (à créer après les sprites car ordre dans la “display list”) var emitter = game.add.emitter(0, 0, 500); emitter.makeParticles('bubble'); ➔ Activation de l’emitter au moment du clic emitter.x = clickedBeer.x + 16; emitter.y = clickedBeer.y + 16; // 50 bulles d'un coup pendant 1 sec emitter.start(true, 1000, null, 50);
Avec de la mousse un peu plus réaliste ➔ Explosion horizontale et légèrement verticale emitter.minParticleSpeed.set(-100, -50); emitter.maxParticleSpeed.set(100, 50); ➔ Disparition progressive (alpha) emitter.setAlpha(1, 0.1, 1000, Phaser.Easing.Linear.None); ➔ Réduction progressive de la taille des bulles emitter.setScale(0.7, 0.1, 0.7, 0.1, 3000, Phaser.Easing.Quintic. Out); ➔ Augmentation de la gravité des bulles emitter.gravity = 200;
Buvons ensemble ➔ Mise en place d’une websocket ◆ Coté serveur var io = require('socket.io')(server); io.on('connection', function (socket) { console.log('client connecté via la websocket ' + socket.id); }); ◆ Coté client
Buvons ensemble ➔ Deux événements ◆ Client → Serveur : want-to-drink-beer envoyé quand un client clique sur une bière ◆ Serveur → Client : beer-to-drink envoyé quand le serveur veut signaler au client qu’une bière vient d’être bue ➔ Pour la partie client on a besoin de : ◆ Mémoriser les bières dans une variable et associer un identifiant unique à chaque bière ◆ Envoyer un événement quand un client clique socket.emit('want-to-drink-beer', clickedBeer.idX);
Buvons ensemble ➔ Pour la partie serveur on va faire simple : ◆ 1 clic = une demande de boisson = automatiquement acceptée par le serveur socket.on('want-to-drink-beer', function (beerIdx) { socket.emit('beer-to-drink', beerIdx); socket.broadcast.emit('beer-to-drink', beerIdx); } ➔ Go buvez !!!
Merci de votre attention ! Résumé ➔ Un cas d’usage : jeux Flash → jeux HTML5 ➔ Besoin de rester dans les standards du web ◆ Un framework pour dev jeux HTML5 : Phaser ◆ Usage de NodeJS & Socket.io pour la communication temps réel entre les clients et le serveur publions sur