Commit 06562663 authored by Jens-Christian Fischer's avatar Jens-Christian Fischer
Browse files

Adding / Removing of Boids works

The "/conductor" page shows the current connected players as boids.
Joining / Leaving is handled correctly throught eh Phoenix Presence
frameworks
parent ee06fe79
......@@ -29,7 +29,7 @@ SliderPanel.init(socket, "sliderPanel", ["s1", "s2", "s3"]);
OrientationPanel.init(socket, "orientationPanel");
AccelerationPanel.init(socket, "accelerationPanel");
BpmPanel.init(socket, "bpmPanel");
PresenceSketch.init("sketch");
PresenceSketch.init(socket, "sketch");
// Presence
......@@ -45,14 +45,23 @@ let listBy = (user, {metas: metas}) => {
return {
user: user,
onlineAt: formatTimestamp(metas[0].online_at)
}
};
}
let userList = document.getElementById("UserList")
let userCounter = document.getElementById("UserCount")
let userList = document.getElementById("UserList");
let userCounter = document.getElementById("UserCount");
let render = (presences, diff) => {
if (diff) {
PresenceSketch.addBoids(diff.joins);
PresenceSketch.removeBoids(diff.leaves);
} else {
PresenceSketch.syncBoids(presences);
}
let render = (presences) => {
if (userList) {
userList.innerHTML = Presence.list(presences, listBy)
.map(presence => `
......@@ -71,17 +80,18 @@ let render = (presences) => {
let room = socket.channel("presence:lobby", {})
console.log(room);
room.on("presence_state", state => {
console.log("p_s");
presences = Presence.syncState(presences, state)
render(presences)
})
room.on("presence_diff", diff => {
console.log("p_d");
presences = Presence.syncDiff(presences, diff)
render(presences)
console.log(diff);
presences = Presence.syncDiff(presences, diff);
render(presences, diff)
})
console.log("joining presence");
......
import p5 from "p5";
import _ from "underscore";
import {Socket, Presence} from "phoenix";
// Boid class
// Methods for Separation, Cohesion, Alignment added
function Boid(p, x, y) {
this.p = p;
this.acceleration = this.p.createVector(0, 0);
this.velocity = p5.Vector.random2D();
this.position = this.p.createVector(x, y);
this.r = 3.0;
this.maxspeed = 3; // Maximum speed
this.maxforce = 0.05; // Maximum steering force
};
Boid.prototype.run = function(boids) {
this.flock(boids);
this.update();
this.borders();
this.render();
};
// Forces go into acceleration
Boid.prototype.applyForce = function(force) {
this.acceleration.add(force);
};
// We accumulate a new acceleration each time based on three rules
Boid.prototype.flock = function(boids) {
var sep = this.separate(boids); // Separation
var ali = this.align(boids); // Alignment
var coh = this.cohesion(boids); // Cohesion
// Arbitrarily weight these forces
sep.mult(4.5);
ali.mult(1.0);
coh.mult(1.0);
// Add the force vectors to acceleration
this.applyForce(sep);
// this.applyForce(ali);
this.applyForce(coh);
};
// Method to update location
Boid.prototype.update = function() { // Update velocity
this.velocity.add(this.acceleration);
// Limit speed
this.velocity.limit(this.maxspeed);
this.position.add(this.velocity);
// Reset acceleration to 0 each cycle
this.acceleration.mult(0);
};
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
Boid.prototype.seek = function(target) {
var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
// Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(this.maxspeed);
// Steering = Desired minus Velocity
var steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxforce); // Limit to maximum steering force
return steer;
};
// Draw boid as a circle
Boid.prototype.render = function() {
this.p.fill(127, 127);
this.p.stroke(200);
this.p.ellipse(this.position.x, this.position.y, 16, 16);
};
// Wraparound
Boid.prototype.borders = function() {
if (this.position.x < -this.r) this.position.x = PresenceSketch.width + this.r;
if (this.position.y < -this.r) this.position.y = PresenceSketch.height + this.r;
if (this.position.x > PresenceSketch.width + this.r) this.position.x = -this.r;
if (this.position.y > PresenceSketch.height + this.r) this.position.y = -this.r;
};
// Separation
// Method checks for nearby boids and steers away
Boid.prototype.separate = function(boids) {
var desiredseparation = 25.0;
var steer = this.p.createVector(0, 0);
var count = 0;
// For every boid in the system, check if it's too close
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position, boids[i].position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
var diff = p5.Vector.sub(this.position, boids[i].position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div(count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(this.maxspeed);
steer.sub(this.velocity);
steer.limit(this.maxforce);
}
return steer;
};
// Alignment
// For every nearby boid in the system, calculate the average velocity
Boid.prototype.align = function(boids) {
var neighbordist = 50;
var sum = this.p.createVector(0, 0);
var count = 0;
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position, boids[i].position);
if ((d > 0) && (d < neighbordist)) {
sum.add(boids[i].velocity);
count++;
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxspeed);
var steer = p5.Vector.sub(sum, this.velocity);
steer.limit(this.maxforce);
return steer;
} else {
return this.p.createVector(0, 0);
}
};
// Cohesion
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
Boid.prototype.cohesion = function(boids) {
var neighbordist = 50;
var sum = this.p.createVector(0, 0); // Start with empty vector to accumulate all locations
var count = 0;
for (var i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position, boids[i].position);
if ((d > 0) && (d < neighbordist)) {
sum.add(boids[i].position); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum); // Steer towards the location
} else {
return this.p.createVector(0, 0);
}
};
let PresenceSketch = {
width: 720,
height: 400,
boids: [],
boids: {},
p5: {},
presences: {},
addBoids(joins) {
_.each(joins, function(val, name) {
console.log("adding " + name);
PresenceSketch.boids[name] = new Boid(PresenceSketch.p5,
Math.random() * PresenceSketch.width,
Math.random() * PresenceSketch.height);
});
},
removeBoids(leaves) {
_.each(leaves, function(val, name) {
console.log("removing " + name);
delete PresenceSketch.boids[name];
});
},
syncBoids(currentActive) {
console.log("sync");
_.each(currentActive, function(p) {
console.log(p.user);
if (PresenceSketch.boids[p.user]) {
console.log("have boid");
} else
{
console.log("adding boid");
PresenceSketch.boids[p.user] = new Boid(PresenceSketch.p5,
Math.random() * PresenceSketch.width,
Math.random() * PresenceSketch.height);
}
});
},
sketch(s) {
PresenceSketch.p5 = s;
s.setup = function() {
s.createCanvas(this.width, this.height);
s.background(10)
s.createCanvas(PresenceSketch.width, PresenceSketch.height);
s.background(150, 60, 70);
// Add an initial set of boids into the system
// for (var i = 0; i < 2; i++) {
// PresenceSketch.boids["foo" + i] = new Boid(s, Math.random() * PresenceSketch.width,
// Math.random() * PresenceSketch.height);
// }
};
s.draw = function() {
s.background(51, 66, 240);
// Run all the boids
_.each(PresenceSketch.boids, function(boid, key, list) {
boid.run(list);
});
// for (var i = 0; i < PresenceSketch.boids.length; i++) {
// PresenceSketch.boids[i].run(PresenceSketch.boids);
// }
};
s.draw = function() {};
},
init(domId) {
listBy(user, {metas: metas}) {
return {
user: user,
onlineAt: metas[0].online_at
};
},
init(socket, domId) {
if (!document.getElementById(domId)) {
return;
}
// if (userList) {
// userList.innerHTML = Presence.list(presences, listBy)
// .map(presence => `
// <li>
// <b>${presence.user}</b>
// <br><small>online since ${presence.onlineAt}</small>
// </li>
// `)
// .join("");
// }
// socket.connect();
// let room = socket.channel("presence:lobby", {});
// console.log(room);
// room.on("presence_state", state => {
// console.log("presence_state");
// PresenceSketch.presences = Presence.syncState(PresenceSketch.presences, state);
// PresenceSketch.render_sketch(PresenceSketch.presences);
// });
// room.on("presence_diff", diff => {
// console.log("presence_diff");
// PresenceSketch.presences = Presence.syncDiff(PresenceSketch.presences, diff);
// PresenceSketch.render_sketch(PresenceSketch.presences);
// });
// console.log("joining presence sketch");
// room.join().receive("ok", resp => {
// console.log("presencesketch joined");
// })
// .receive("error", reason => console.log("presence join failed", reason));
new p5(this.sketch, domId);
}
}
......
<h1>Grains Conductor</h1>
<div id="bpmPanel" class="bpmPanel"></div>
<div id="sketch"></div>
<div class="row">
<div class="col-md-8">
<ul id="UserList" class="list-unstyled">
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment