Outils pour utilisateurs

Outils du site


wiki:projets:crowd

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
wiki:projets:crowd [2019/05/10 21:37]
daphne [Mémoire]
wiki:projets:crowd [2020/10/05 14:39] (Version actuelle)
Ligne 2: Ligne 2:
  
  
-**Daphné Chamot-Rooke** (contact : [[daphne.chamot-rooke@etu.upmc.fr|daphne.chamot-rooke@etu.upmc.fr]])\\ +  **Daphné Chamot-Rooke** (contact : [[daphne.chamot-rooke@etu.upmc.fr|daphne.chamot-rooke@etu.upmc.fr]])\\ 
-**Himany Seri** (contact : [[himany.seri@etu.upmc.fr|himany.seri@etu.upmc.fr]])+  **Himany Seri** (contact : [[himany.seri@etu.upmc.fr|himany.seri@etu.upmc.fr]])
  
 Début : Février 2019\\ Début : Février 2019\\
 Fin : mai 2019 Fin : mai 2019
  
-**Objectif :** créer un dispositif qui modifie la perception d'autrui+  **Objectif :** créer un dispositif qui modifie la perception d'autrui
  
-**Matériel :** +  **Matériel :** 
   * plusieurs PC avec souris   * plusieurs PC avec souris
   * une connexion internet   * une connexion internet
-  * logiciel Processing installé+  * Javascript, Node.js, P5.js 
 +  * un serveur avec node js 
  
 ===== Cahier des charges ===== ===== Cahier des charges =====
Ligne 25: Ligne 27:
 ==== Description et évolution du projet ==== ==== Description et évolution du projet ====
  
-Nous avions d'abord pensé à travailler sur les émotions, les émotions dans la foule. Nous avions eu l'idée d'un bracelet retranscrivant l'émotion globale de la foule. Puis nous nous sommes orientées vers des applications, car cela nous semblait plus réalisable pour travailler avec de nombreuses personnes. Nous avons choisi de créer un programme pour ordinateur, un jeu multijoueur qui permettrait de retranscrire des mouvements de foule. \\+Nous avions d'abord pensé à travailler sur les émotions, les émotions dans la foule. Nous avions eu l'idée d'un bracelet retranscrivant l'émotion globale de la foule. Puis nous nous sommes orientées vers des applications, car cela nous semblait plus réalisable pour travailler avec de nombreuses personnes.  
 + 
 +La deuxième idée que nous avons eue sur la foule était de créer une application qui nous permettait de cartographier la densité de personnes se trouvant à un endroit. Si dans le lieu ou l’on se trouve la densité de personnes est plus importante à droite alors les feuilles sont plus denses sur la partie droite. Chaque feuille représentait un groupe de quatre personnes, et en fonction des mouvements des gens les feuilles bougeraient.  
 + 
 +{{:wiki:projets:foule2.png?600|}} 
 + 
 + 
 +Nous avons choisi de créer un programme pour ordinateur car sur smartphone se posait un problème : le joueur joue avec son doigt et de ce fait ne rencontre aucun obstacle. Il peut très bien passer par-dessus un autre joueur pour le devancer. Le professeur Charles Lenay nous a alors fait remarquer qu’il était difficile voire impossible de créer des obstructions alors qu’avec une souris cela était possible. Nous avons alors choisi de créer un programme pour ordinateur, qui est un jeu multijoueur qui permet de retranscrire des mouvements de foule.  \\
 Notre jeu se compose d'un avatar représentant soi-même à la 3e personne, vu du dessus. Un "monstre" invisible "mange" les avatars lorsqu'il croise leur chemin. Il faut donc faire attention à son entourage, suivre les autres. \\ Notre jeu se compose d'un avatar représentant soi-même à la 3e personne, vu du dessus. Un "monstre" invisible "mange" les avatars lorsqu'il croise leur chemin. Il faut donc faire attention à son entourage, suivre les autres. \\
 Nous voulons faire plusieurs "salles" avec plusieurs consignes, peut-être en faire une où l'on se voit à la première personne, et une autre avec des consignes différentes pour chaque individu afin de créer un tout avec l'action de chaque individu. Nous voulons faire plusieurs "salles" avec plusieurs consignes, peut-être en faire une où l'on se voit à la première personne, et une autre avec des consignes différentes pour chaque individu afin de créer un tout avec l'action de chaque individu.
 +
 +{{:wiki:projets:foule.png?600|}}
 +
  
 ==== Expression fonctionnelle du besoin ==== ==== Expression fonctionnelle du besoin ====
Ligne 42: Ligne 54:
  
 ==== Veille des dispositifs ==== ==== Veille des dispositifs ====
 +
 +Il existe de nombreux programmes pour simuler l'émergence de comportements et de structures chez les animaux. Par exemple, "Boids", qui simule les regroupements des oiseaux selon trois critères : 
 +    * la cohésion : pour former un groupe, les boids se rapprochent les uns des autres ;
 +    * la séparation : deux boids ne peuvent pas se trouver au même endroit au même moment ;
 +    * l'alignement : pour rester groupés, les boids essayent de suivre un même chemin.
 +
 +{{:wiki:projets:boids.png?600|}}
 +
 +[[https://jumpoff.io/blog/implementing-boids-in-javascript-canvas|Boids]]
 +
 +Dans le même genre, il y a par exemple la synchronisation des lucioles.
 +
 +{{:wiki:projets:fireflies.png?600|}}
 +
 +[[https://ncase.me/fireflies/|Fireflies]]
 +
 +Humanity est un jeu imaginé par le collectif japonais Tha Ltd, il s’agit d’un jeu de réflexion à mi-chemin entre la simulation de foule et l’expérience SF qui met en scène une foule aveugle qui fonce droit devant sans s’arrêter. Chaque niveau comporte des obstacles, des pièges, et autres difficultés. Le but est de sauver le plus d’êtres humains possible à chaque niveau.  
 + Pour le moment, on sait simplement qu’"Humanity" est prévu pour 2018.
 +
 +{{:wiki:projets:humanity.jpg?600|}}
 +
 +Liens pour voir le jeu :
 +[[http://www.tic-time.fr/article/humanity-le-jeu-qui-vous-permet-de-controler-la-foule_a23057/1|Humanity]]
 +[[http://tha.jp/7714|Humanity WIP]]
 +
 +Crowd city\\
 +Le but du jeu est de vous déplacer pour recruter de nouveaux membres et former une foule. Lorsque vous croisez un autre joueur, si vous avez plus de bonhommes que lui, foncez-lui dessus. Sinon, fuyez.
 +
 +{{:wiki:projets:crowdcity.png?600|}}
 +
 +Source : [[https://jeuxvideomobile.com/iphone/crowd-city-iphone.html|Crowd City]]
 +
 +
  
 ==== Veille graphique ==== ==== Veille graphique ====
Ligne 59: Ligne 104:
 {{:wiki:projets:cong3.png?600|}} {{:wiki:projets:cong3.png?600|}}
  
 +===== Posters =====
 +
 +{{:wiki:projets:postercrowd1.png?800|}}
 +{{:wiki:projets:postercrowd2.png?800|}}
 +{{:wiki:projets:postercrowd3.png?800|}}
 ===== Réalisation ===== ===== Réalisation =====
  
 +==== Aspects techniques ====
 +
 +Nous avons installé [[https://nodejs.org/fr/|Node.js]] pour permettre de se connecter à plusieurs sur le même serveur.\\
 +On suit ensuite les instructions de [[https://socket.io/|Socket.io]]. On doit créer un package.json, un serveur en javascript, et un code client en javascript et un index en html dans un dossier public. \\
 +Nous avons été confrontées à plusieurs problèmes. En effet, nous avions commencé à coder en Java sur Processing, mais cela ne permet pas de créer un code multijoueur en ligne. Nous devions donc réecrire ce code en javascript en utilisant [[https://p5js.org/|P5.js]]. Il a été difficile de comprendre le fonctionnement des sockets et les échanges entre le client et le serveur. Ensuite se posait la question de l'hébergement car il faut un serveur qui prend en compte le node js, qui coûte plus cher qu'un site basique. Finalement, nous serons hébergées provisoirement par une âme charitable.\\
 +C'est par les limites de notre savoir informatique que nous avons simplifié au maximum notre jeu mais les bases sont posées pour complexifier le principe.
 ==== Code ==== ==== Code ====
  
-Code Java (Processing) :+Code JavaScript pour le serveur : 
 + 
 +<code> 
 +//this code is based on https://github.com/CodingTrain/website/tree/master/CodingChallenges/CC_032.2_agar.io_sockets/Node 
 + 
 +var blobs = []; //liste pour stocker les blobs 
 + 
 +function Blob(id, x, y, vx, vy
 +  //définit l'objet blob 
 +  this.id = id; 
 +  this.x = x; 
 +  this.y = y; 
 +  this.vx = vx; 
 +  this.vy = vy; 
 +
 + 
 +var monstres = []; //liste pour stocker les monstres 
 + 
 +function Monster(xm, ym) { 
 +  //définit l'objet monstre 
 +  this.xm = xm; 
 +  this.ym = ym; 
 +
 + 
 +// Using express: http://expressjs.com/ 
 +var express = require("express"); 
 +// Create the app 
 +var app = express(); 
 + 
 +// Set up the server 
 +// process.env.PORT is related to deploying on heroku 
 +var server = app.listen(process.env.PORT || 3000, listen); 
 + 
 +// This call back just tells us that the server has started 
 +function listen() { 
 +  var host = server.address().address; 
 +  var port = server.address().port; 
 +  console.log("Example app listening at http://" + host + ":" + port); 
 +
 + 
 +app.use(express.static("public")); 
 + 
 +// WebSocket Portion 
 +// WebSockets work with the HTTP server 
 +var io = require("socket.io")(server); 
 + 
 +setInterval(heartbeat, 33); 
 + 
 +function heartbeat() { 
 +  io.sockets.emit("heartbeat_blobs", blobs); 
 +  io.sockets.emit("heartbeat_monstre", monstres); 
 +
 + 
 +// Register a callback function to run when we have an individual connection 
 +// This is run for each individual user that connects 
 +io.sockets.on( 
 +  "connection", 
 +  // We are given a websocket object in our function 
 +  function(socket) { 
 +    console.log("We have a new client: " + socket.id); 
 + 
 +    socket.on("start_blobs", function(data) { 
 +      console.log(socket.id + " " + data.x + " " + data.y); 
 +      socket.broadcast.emit("start_blobs", data); 
 +      var blob = new Blob(socket.id, data.x, data.y, data.vx, data.vy); 
 +      blobs.push(blob); 
 +    }); 
 + 
 +    socket.on("start_monstres", function(datam) { 
 +      console.log(datam.xm + " " + datam.ym); 
 +      socket.broadcast.emit("start_monstres", datam); 
 +      var monstre = new Monster(datam.xm, datam.ym); 
 +      monstres.push(monstre); 
 +    }); 
 + 
 +    socket.on("update", function(data) { 
 +      //console.log(blobs); 
 +      for (var i = 0; i < blobs.length; i++) { 
 +        if (socket.id == blobs[i].id) { 
 +          //console.log(blobs[i].id); 
 +          blobs[i].x = data.x; 
 +          blobs[i].y = data.y; 
 +        } 
 +      } 
 +    }); 
 + 
 +    socket.on("collide", function(data) { 
 +      //console.log(blobs); 
 +      for (var i = 0; i < blobs.length; i++) { 
 +        if (socket.id == blobs[i].id) { 
 +          //console.log(blobs[i].id); 
 +          blobs[i].vx = data.vx; 
 +          blobs[i].vy = data.vy; 
 +        } 
 +      } 
 +    }); 
 + 
 +    socket.on("move", function(datam) { 
 +      //console.log(blobs); 
 +      for (var i = 0; i < monstres.length; i++) { 
 +        monstres[i].xm = datam.xm; 
 +        monstres[i].ym = datam.ym; 
 +      } 
 +    }); 
 + 
 +    socket.on("eaten", function(data) { 
 +      // remove the eaten blob 
 +      // set array of blobs excluding the eaten blob 
 + 
 +      var eaten = { 
 +        id: "" 
 +      }; 
 + 
 +      var newblob = blobs.filter(function(blobs) { 
 +        if (blobs.id === data.eatenId) { 
 +          eaten.id = blobs.id; 
 +        } 
 + 
 +        return blobs.id !== data.eatenId; 
 +      }); 
 +      blobs = newblob; 
 + 
 +      io.sockets.emit("", blobs); 
 +    }); 
 + 
 +    socket.on("disconnect", function() { 
 +      console.log("Client has disconnected" + " " + socket.id); 
 +      blobs = blobs.filter(function(blobs) { 
 +        return blobs.id !== socket.id; 
 +      }); 
 +    }); 
 +  } 
 +); 
 + 
 +</code> 
 + 
 +Code JavaScript pour le client :
  
 <code> <code>
 //déclaration de variables //déclaration de variables
-Blob blob;                  //personnage +var socket; 
-Monster monstre;            //monstre +var blob; //personnage 
-boolean jeu = false;        //bool pour le jeu +var blobs = []; //liste de blobs 
-boolean intro = true;       //bool pour l'intro +var monstres = []; //liste de monstres 
-String temps, score       //string pour stocker le temps et le temps final +var monstre; //monstre 
-Timer timer               //timer+var timer; //bool pour le timer 
 +var jeu = false; //bool pour le jeu 
 +var intro = true; //bool pour l'intro 
 +const radius = 30; //rayon du monstre 
 +var alive = true; 
 +let spring = 0.05;
  
-void setup() {+function setup() { 
 +  createCanvas(900, 600); 
 +  if (alive) { 
 +    socket = io.connect("http://localhost:3000"); 
 +  }
  
-  fullScreen();             //s'affiche en plein écran +  //nouveaux blob, monstre et timer 
-  timer = new Timer();      //nouveaux blob, monstre et timer +  timer = new Timer(); 
-  blob = new Blob(); +  blob = new Blob(random(width), random(height)); 
-  monstre = new Monster();+  monstre = new Monster(random(width), random(height)); 
 + 
 +  //data pour la position du blob 
 +  var data = { 
 +    x: blob.pos.x, 
 +    y: blob.pos.y, 
 +    vx: blob.vel.x, 
 +    vy: blob.vel.y 
 +  }; 
 + 
 +  //data pour la position du monstre 
 +  var datam = { 
 +    xm: monstre.pos.x, 
 +    ym: monstre.pos.y 
 +  }; 
 + 
 +  socket.emit("start_blobs", data); //partage les data 
 +  socket.emit("start_monstres", datam); 
 +  alive = true; 
 + 
 +  socket.on("heartbeat_blobs", function(data) { 
 +    var stillAlive = false; 
 +    for (var i = 0; i < data.length; i++) { 
 +      if (socket.id == data[i].id) { 
 +        stillAlive = true; 
 +      } 
 +    } 
 +    alive = stillAlive; 
 +    blobs = data; 
 +  }); 
 + 
 +  socket.on("heartbeat_monstre", function(datam) { 
 +    monstres = datam; 
 +  });
 } }
  
-void draw() { +function draw() { 
-  background(0);            //fond noir, taille du texte 30 et écrit en blanc+  background(0); //fond noir, taille du texte 30 et écrit en blanc
   textSize(30);   textSize(30);
   fill(255);   fill(255);
-  temps = timer.minute() + ":"timer.second();    //on stocke les secondes et les minutes dans un string+  = timer.minute()
 +  b = timer.second(); 
 +  temps = a + ":" + b; //on stocke les secondes et les minutes dans un string
  
-  if (jeu) { +  if (socket.connected && alive && jeu) { 
-    timer.stop();          //démarre le timer +    timer.stop(); //démarre le timer 
-    blob.show();           //dessine le blob +    blob.show(); //dessine le blob 
-    blob.update();          +    blob.update(); 
-    monstre.show();        //dessine le monstre +    monstre.deflect(); //empêche que le monstre sorte des bords 
-    monstre.deflect();     //empêche que le monstre sorte des bords +    monstre.move(); //le monstre bouge
-    monstre.move();        //le monstre bouge +
-    monstre.manger(blob);  //mange le blob si ils se rencontrent +
-    text(temps, width/2 - 50, 50);  //affiche le temps en haut de l'écran+
     score = temps;     score = temps;
-  } else {                +    text(temps, width / 2 - 40, 50); //affiche le temps en haut de l'écran 
 + 
 +    for (var i = blobs.length - 1; i >= 0; i--) { 
 +      blob.collide(blobs[i]); 
 +      if (socket.id !== blobs[i].id) { 
 +        fill(255); 
 +        stroke(255); 
 +        circle(blobs[i].x, blobs[i].y, 20); 
 +      } else { 
 +        var newblob = new Blob(blobs[i].x, blobs[i].y, 20); 
 +        if (mange(newblob)) { 
 +          var data = { 
 +            eatenId: blobs[i].id 
 +          }; 
 +          socket.emit("eaten", data); 
 +        } 
 +      } 
 +    } 
 + 
 +    for (var i = monstres.length - 1; i >= 0; i--) { 
 +      noFill(); 
 +      noStroke(); 
 +      circle(monstres[i].xm, monstres[i].ym, radius * 2); 
 +    } 
 + 
 +    var data = { 
 +      x: blob.pos.x, 
 +      y: blob.pos.y, 
 +      vx: blob.vel.x, 
 +      vy: blob.vel.y 
 +    }; 
 + 
 +    var datam = { 
 +      xm: monstre.pos.x, 
 +      ym: monstre.pos.y 
 +    }; 
 + 
 +    socket.emit("update", data); 
 +    socket.emit("collide", data); 
 +    socket.emit("move", datam); 
 +  } 
 +  if (!jeu) {
     timer.start();     timer.start();
     fill(255);     fill(255);
Ligne 105: Ligne 379:
  
     if (intro) {     if (intro) {
-      text("Foule", width/2 - 170, height/2 - 100);          //si c'est l'intro : titre du jeu et démarrer +      //si c'est l'intro : titre du jeu et démarrer 
-      text("Cliquer pour jouer", width/2 - 300, height/2);+      text("Foule", width / 2 - 70, height / 2 - 100); 
 +      text("Cliquer pour jouer", width / 2 - 200, height / 2);
     } else {     } else {
-      text("Game Over", width/2 - 170, height/2 - 100);      //si c'est la fin du jeu : Game Over et le temps final s'affichent +      //si c'est la fin du jeu : Game Over et le temps final s'affichent 
-      text("Temps : " + score, width/2 - 180, height/2);+      text("Game Over", width / 2 - 140, height / 2 - 100); 
 +      text("Score : " + score, width / 2 - 150, height / 2); 
 +      text("Appuyer sur F5 pour redémarrer", width / 20, height / 2 + 100);
     }     }
   }   }
 } }
  
-void reset() {          //quand c'est la fin du jeu, permet de redémarrer une partie juste en clickant +function reset() { 
-  jeu=true; +  //quand c'est la fin du jeu, permet de redémarrer une partie juste en cliquant 
-  blob.pos.x = random(width);      //réinitialise les positions du blob et du monstre aléatoirement +  console.log("allez"); 
-  blob.pos.y random(height)+  alive true
-  monstre.x random(width)+  stillAlive true
-  monstre.y random(height); +  jeu true
-  blob.c = color((int) (Math.random() * 266), (int) (Math.random() * 266), (int) (Math.random() * 266), 170);   //réinitialise la couleur aléatoire +  timer.stop(); //redémarre le timer à 0
-  timer.stop();        //redémarre le timer à 0+
 } }
  
-void mousePressed() {    //on passe l'intro et la fin du jeu en cliquant  +function mousePressed() { 
-  intro=false; +  //on passe l'intro et la fin du jeu en cliquant 
-  if (jeu==false) {+  intro = false
 +  alive = true
 +  if (jeu == false) {
     reset();     reset();
   }   }
 } }
  
-class Blob {               //classe du blob  +//Classe Blob 
-  PVector pos, vel, acc  //avec une positionune vitesse et une accélaration +class Blob { 
-  color c;                 //couleur du blob +  constructor(x, y) { 
-  float topspeed;          //valeur limite de la vitesse+    this.pos = createVector(xy); 
 +    this.vel = createVector(00); 
 +    this.acc = createVector(00); 
 +    this.topspeed = 2; 
 +    this.r = 20; 
 +    this.= color( 
 +      int(50 + Math.random() * (220 - 50)), 
 +      int(50 + Math.random() * (220 - 50)), 
 +      int(50 + Math.random() * (220 - 50)) 
 +    ); 
 +    //couleur ni trop sombre ni trop claire 
 +  }
  
-  Blob() { +  collide(other) { 
-    pos = new PVector(width/2, height/2)  +    let dx = other.x - this.pos.x; 
-    vel new PVector(0, 0); +    let dy other.y - this.pos.y
-    topspeed 5+    let distance sqrt(dx * dx + dy * dy); 
-    color((int(Math.random() * 266)(int) (Math.random() * 266), (int) (Math.random() * 266), 170);+ 
 +    if (distance < this.r / 2) { 
 +      let angle atan2(dy, dx)
 +      let targetX this.pos.x + (cos(angle* this.r) / 2; 
 +      let targetY = this.pos.y + (sin(angle) * this.r/ 2; 
 +      let ax = (targetX - other.x) * spring; 
 +      let ay = (targetY - other.y) * spring; 
 +      this.vel.x -= ax; 
 +      this.vel.y -= ay; 
 +      other.vx += ax; 
 +      other.vy += ay; 
 +    }
   }   }
  
-  void update() { +  update() { 
-    PVector mouse = new PVector(mouseX, mouseY);      //position en fonction du curseur +    this.mouse = createVector(mouseX, mouseY); //position du curseur 
-    PVector acc = PVector.sub(mousepos);            //on définit le vecteur accélération +    this.acc.add(this.mouse); 
-    acc.setMag(0.2);                                  //magnitude de l'accélération à 0.2 +    this.acc.sub(this.pos); 
-    vel.add(acc);                                     //on ajoute l'accélération au vecteur vitesse +    this.acc.setMag(0.2); //on définit le vecteur accélération 
-    mouse.sub(this.pos);                              // +    this.vel.add(this.acc); //on ajoute l'accélération au vecteur vitesse 
-    mouse.setMag(7);                                  //magnitude à 7, c'est le retour entre le curseur et le blob à cause de l'accélération (petite par rapport à 0.2) +    this.mouse.sub(this.pos); // 
-    this.pos.add(mouse);                               +    this.mouse.setMag(7); //magnitude force de rappel du blob vers le curseur 
-    vel.limit(topspeed);                              //valeur limite à la vitesse +    this.pos.add(this.mouse); //on ajoute à la position courante 
-    pos.add(vel);                                     //on ajoute la vitesse au vecteur position+    this.vel.limit(this.topspeed); //valeur limite à la vitesse 
 +    this.pos.add(this.vel); //on ajoute la vitesse au vecteur position 
 +    this.pos.x = Math.min(this.pos.x, width - 10); //gestion des coins de la boite 
 +    this.pos.x = Math.max(this.pos.x, 10); 
 +    this.pos.y = Math.min(this.pos.y, height - 10); 
 +    this.pos.y = Math.max(this.pos.y, 10);
   }   }
  
-  void show() {          //dessine le blob +  show() { 
-    fill(c); +    //dessine le blob 
-    stroke(c); +    fill(this.c); 
-    circle(this.pos.x, this.pos.y, 20);+    stroke(this.c); 
 +    circle(this.pos.x, this.pos.y, this.r);
   }   }
 } }
  
-class Monster {            //classe du monstre +//Classe Monster 
- +class Monster { 
-  float x, y+  constructor(x, y) { 
-  float xVel, yVel; +    this.pos createVector(xy); 
-  int radius; +    this.vel createVector(random(2, 4), random(2, 4));
- +
-  Monster() { +
-    xVel random(24); +
-    yVel = random(2, 4); +
     if (int(random(0, 2)) == 1) {     if (int(random(0, 2)) == 1) {
-      xVel *= -1;+      this.vel.x *= -1;
     }     }
     if (int(random(0, 2)) == 1) {     if (int(random(0, 2)) == 1) {
-      yVel *= -1;+      this.vel.y *= -1;
     }     }
- 
-    x = random(radius, width-radius); 
-    y = random(radius, height-radius); 
- 
-    radius = 30; 
   }   }
  
-  void move() {        //permet au monstre de bouger +  move() { 
-    x +xVel;  +    //permet au monstre de bouger (à vitesse constante si epsi=0,0) 
-    y +yVel; +    this.epsi createVector(random(-1, 1), random(-1, 1)); // Exciter la vitesse 
-  }  +    this.vel.add(this.epsi); 
- +    this.pos.add(this.vel); 
-  void manger(Blob blob{    //le monstre "mange" le blob si ils se rencontrent et le jeu est fini +    if (b % 5 == 0) { 
-    if (blob.pos.x <= this.x + radius && blob.pos.x >= this.x - radius && blob.pos.y <= this.y + radius && blob.pos.y >= this.radius) { +      this.vel createVector(random(2, 4), random(2, 4)); 
-      jeu false;+      if (int(random(0, 2)) == 1) { 
 +        this.vel.x *= -1; 
 +      } 
 +      if (int(random(0, 2)) == 1) { 
 +        this.vel.y *-1; 
 +      }
     }     }
   }   }
- +   
-  void show() {          //dessine le monstre +  //permet au monstre de ne pas sortir des bords, il "rebondit" 
-    strokeWeight(1); +  deflect() { 
-    noFill(); +    if (this.pos.x + radius > width || this.pos.x - radius < 0) { 
-    ellipse(this.x, this.y, this.radius*2, this.radius*2); +      this.vel.x *= -1; 
-  } +    } 
- +    if (this.pos.y + radius > height || this.pos.y - radius < 0) { 
-  void deflect() {      //permet au monstre de ne pas sortir des bords, il "rebondit" +      this.vel.y *= -1;
-    if (x + radius > width || x - radius < 0) { +
-      xVel *= -1; +
-    }  +
-    if (y + radius > height || y - radius < 0) { +
-      yVel *= -1;+
     }     }
   }   }
 } }
  
-class Timer {      //classe du timer +//le monstre "mange" le blob s'ils se rencontrent et le jeu est fini 
-  int startTime 0, stopTime 0; +mange function(blob) { 
-  boolean running = false;  + if ( 
 +    this.blob.pos.x <monstre.pos.x + radius && 
 +    this.blob.pos.x >= monstre.pos.x - radius && 
 +    this.blob.pos.y <= monstre.pos.y + radius && 
 +    this.blob.pos.y >= monstre.pos.y - radius 
 +  ) { 
 +    jeu = false; 
 +    return true; 
 +  
 +  return false; 
 +};
  
 +//Classe Timer
 +class Timer {
 +  constructor() {
 +    this.startTime = 0;
 +    this.stopTime = 0;
 +    this.running = false;
 +  }
  
-  void start() { +  start() { 
-    startTime = millis(); +    this.startTime = new Date(); 
-    running = true;+    this.running = true;
   }   }
-  void stop() { + 
-    stopTime = millis(); +  stop() { 
-    running = false;+    this.stopTime = new Date(); 
 +    this.running = false;
   }   }
-  int getElapsedTime() { + 
-    int elapsed; +  getElapsedTime() { 
-    if (running) { +    if (this.running) { 
-      elapsed = (millis() - startTime);+      this.elapsed = new Date() - this.startTime;
     } else {     } else {
-      elapsed = (stopTime - startTime);+      this.elapsed = this.stopTime - this.startTime;
     }     }
-    return elapsed;+    return this.elapsed;
   }   }
-  int second() { + 
-    return (getElapsedTime() / 1000) % 60;+  second() { 
 +    this.sec = int((this.getElapsedTime() / 1000) % 60); 
 +    if (this.sec < 10) { 
 +      this.sec = "0" + this.sec; 
 +    } else { 
 +      this.sec = "" + this.sec; 
 +    } 
 +    return this.sec;
   }   }
-  int minute() { + 
-    return (getElapsedTime() / (1000*60)) % 60;+  minute() { 
 +    this.min = int((this.getElapsedTime() / (1000 * 60)) % 60); 
 +    if (this.min < 10) { 
 +      this.min = "0" + this.min; 
 +    } else { 
 +      this.min = "" + this.min; 
 +    } 
 +    return this.min;
   }   }
 } }
 +
 </code> </code>
-===== Mémoire ===== 
  
-{{ :wiki:projets:cronewd.pdf |}}+Code html pour l'index : 
 + 
 +<code> 
 +<!DOCTYPE html> 
 +<html> 
 +    <head> 
 +        <meta charset="UTF-8"> 
 +     <script type="text/javascript" src="https://cdn.socket.io/socket.io-1.4.5.js"></script> 
 +            <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script> 
 +     <script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/addons/p5.dom.min.js"></script> 
 +            <script type="text/javascript" src="crowd.js"></script> 
 +         </head> 
 +    <body> 
 +    </body> 
 +</html> 
 +</code> 
 +===== Expérimentation ===== 
 + 
 +Nous avons testé notre [[http://demo.sld.ovh/|jeu]]. Nous avons réuni une dizaine de personnes afin de réaliser notre expérience. 
 + 
 +Nous avons rencontré certains problèmes, l’application buggue sur certains ordinateurs et smartphones et les utilisateurs sont obligés de rafraîchir la page de ce fait ils n’ont pas pu jouer correctement. 
 + 
 +Une seconde remarque nous a été faite : le manque d’explications (car ils n’avaient pas les posters devant eux). Pour résoudre ce problème nous avons décidé de rajouter un texte expliquant plus en détails ce que doivent faire les joueurs et pourquoi ils ont perdu. 
 + 
 +Certains joueurs se cachent dans les recoins pour éviter de se faire manger par le monstre on a alors l’impression que les chances de survies sont plus importantes aux niveaux des bords. Pour résoudre ce problème on voudrait ajouter des interdictions ou des complications au niveau des coins.  
 +Toutefois le monstre a déjà un mouvement imprévisible et une vitesse qui varie, ce qui rend le jeu plus difficile. 
 + 
 +Notre dernier problème et que nous n'avons pas réussi à faire rebondir les joueurs entre eux, ce qui fait qu'ils peuvent se superposer. Toutefois on observe qu'en pratique, les joueurs ne le font pas trop. 
 + 
 +L’idée de rajouter des recoins dans l’aire du jeu nous a été suggérée, néanmoins après ce premier test nous trouvons que notre jeu remplit assez bien nos attentes. 
 + 
 +Nous avons filmé une partie : on observe effectivement quelques joueurs dans les recoins, et sinon des mouvements de poursuite et d'exploration en file. Certains autres joueurs sont immobiles mais nous ne savons pas si c'est de l'ordre de la stratégie ou si les joueurs ne sont pas vraiment derrière leur écran. 
 + 
 +{{ :wiki:projets:video-projet1.mp4 |}} 
 + 
 +=== Idées de développement === 
 + 
 +Pour améliorer notre projet nous aurions pu rajouter des recoins pour permettre aux joueurs de se cacher. Cependant, cela n’aurait pas permis de voir la foule en mouvement car on aurait observé un amas derrière un mur. De plus, le cercle ayant la possibilité de passer à proximité, les individus ont autant de chances de se faire manger que s’il n’y avait pas d’obstacles. Coder les obstacles est difficile : les faire apparaître est simple mais interdire au monstre de s’en approcher et permettre aux joueurs de se cacher est plus difficile. Combien de joueurs peuvent se cacher derrière ? Il suffit que quelqu’un s'y cache dès le début de la partie et décide de ne pas bouger pour gagner (dans l'optique où les blobs ne pouvaient pas se superposer). L’idée a donc été abandonnée. 
 + 
 +Nous aurions aimé allez plus loin et créer différents univers de salles ou du moins changer quelques paramètres afin de voir si le comportement des gens change en fonction des circonstances. Observons-nous la même chose si le but est de survivre ou si c'est de faire une chorégraphie  ? Est-ce qu'on aurait vu des phénomènes de ségrégation en sélectionnant seulement deux couleurs visibles de blobs ? Est-ce que le comportement avec une vue "à la première personne" est différent ? 
 + 
 +Pour voir l’incidence du monstre nous pensons réaliser une partie avec le monstre visible cette fois-ci. 
 + 
 +  
 + 
 +=== Problèmes rencontrés === 
 + 
 +Il a été compliqué de créer une interface permettant à tous les joueurs de jouer simultanément. De plus la vitesse des joueurs dépend de leur machine et les monstres ne semblent pas totalement synchronisés. Impossible de faire rebondir les blobs entre eux. 
 + 
 +===== Mémoire =====
  
-à télécharger ici (jusqu'au 17/05/19) https://we.tl/t-cNHGPTQB55+{{ :wiki:projets:3hd42.pdf | Mémoire}}
  
  
wiki/projets/crowd.1557524232.txt.gz · Dernière modification: 2019/05/10 21:37 de daphne