Skip to content

Instantly share code, notes, and snippets.

@bruce55
Last active November 3, 2017 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bruce55/92d3c3d3268133c13cf57e88f64310f5 to your computer and use it in GitHub Desktop.
Save bruce55/92d3c3d3268133c13cf57e88f64310f5 to your computer and use it in GitHub Desktop.
Bruce's NOC midterm
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Midterm by Bruce</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.min.js" integrity="sha256-bXPU+HvtR3tP1IYHZVEFHzEZ9p5zkY8GLPnOnJXW67k=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.5/dat.gui.min.js" integrity="sha256-S4/QjoXe4IOpU0f0Sj5jEQLTWPoX9uRl1ohB91jyhuw=" crossorigin="anonymous"></script>
<script src="sketch.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
</body>
</html>
let gui;
var BLOCK_COUNT = 2000;
var RIPPLE_SPEED = 0.5;
var EXTRA_PADDING = 10;
var BLOCK_MOVE_RANGE = 50;
var FORCE_SCALE = 0.2;
var STRENGTH_FACTOR = 60000;
var BLOCK_INCREASE = 1;
var BASE_BLOCK_SIZE = 2;
var BLOCK_SIZE_VARIATION = 4;
var IDLE_MOTION = 0.2;
var ENHANCED_MOTION = 0.4;
var MOVE_SCALE = 0.08;
var DRAG_SCALE = 0.2;
var RESISTENCE_FACTOR = 0.995;
var show_ripples = false;
var show_info = false;
let mouse_vec = new p5.Vector();
let mouse_speed, mouse_heading;
let fps, avg_fps = 0;
let prev_frame = 0;
let prev_time = 0;
let fps_interval = 1000;
/**
* @type {Block[]}
*/
let blocks;
/**
* @type {Ripple[]}
*/
let ripples = [];
function onSizeChange() {
blocks.forEach((block, i) => block.mass = (BASE_BLOCK_SIZE + random(0, BLOCK_SIZE_VARIATION * BASE_BLOCK_SIZE)) * 0.025);
}
function onCountChange() {
if (blocks.length >= BLOCK_COUNT) {
blocks.splice(BLOCK_COUNT - blocks.length, blocks.length - BLOCK_COUNT);
} else {
const prev_length = blocks.length;
blocks.push(...Array.from({ length: BLOCK_COUNT - prev_length }, (v, k) =>
new Block(random(width), random(height), (BASE_BLOCK_SIZE + random(0, BLOCK_SIZE_VARIATION * BASE_BLOCK_SIZE)) * 0.025, prev_length + k)));
}
}
function setup() {
createCanvas(1000, 1000);
noStroke();
fill(233, 230);
rectMode(CENTER);
noSmooth();
blocks = Array.from({ length: 2000 }, (v, k) =>
new Block(random(width), random(height), (BASE_BLOCK_SIZE + random(0, BLOCK_SIZE_VARIATION * BASE_BLOCK_SIZE)) * 0.025, k));
gui = new dat.GUI();
gui.remember(window);
gui.add(window, 'BLOCK_COUNT', 0, 10000).onChange(onCountChange);
gui.add(window, 'BASE_BLOCK_SIZE', 0, 20).onChange(onSizeChange);
gui.add(window, 'BLOCK_SIZE_VARIATION', 0, 6).onChange(onSizeChange);
gui.add(window, 'BLOCK_INCREASE');
gui.add(window, 'FORCE_SCALE');
gui.add(window, 'RESISTENCE_FACTOR', 0,1);
const ripple_folder = gui.addFolder('Ripple');
ripple_folder.add(window, 'RIPPLE_SPEED', 0, 2);
ripple_folder.add(window, 'STRENGTH_FACTOR');
ripple_folder.add(window, 'BLOCK_MOVE_RANGE');
ripple_folder.add(window, 'IDLE_MOTION', 0, 1);
ripple_folder.add(window, 'ENHANCED_MOTION', 0, 1);
ripple_folder.add(window, 'MOVE_SCALE', 0, 1);
ripple_folder.add(window, 'DRAG_SCALE', 0, 1);
const display_folder = gui.addFolder('Display');
display_folder.add(window, 'show_info');
display_folder.add(window, 'show_ripples');
}
function draw() {
if (keyIsDown(32)) {
if (random() < pow(fps / 60, 3)) {
ripples.push(new Ripple(random(width), random(height), ENHANCED_MOTION, random()*PI*2));
}
} else {
if (random() < pow(fps / 60, 3) / 16) {
ripples.push(new Ripple(random(width), random(height), IDLE_MOTION, random() * PI * 2));
}
}
fps = frameRate();
if (millis() - prev_time > fps_interval) {
avg_fps = (frameCount - prev_frame) / fps_interval * 1000;
prev_frame = frameCount;
prev_time = millis();
}
mouse_vec.set(mouseX - pmouseX, mouseY - pmouseY);
mouse_speed = mouse_vec.mag();
mouse_heading = mouse_vec.heading();
background(100, 140);
ripples.forEach((ripple, i) => {
ripple.updateRadius();
ripple.checkKill();
});
if (show_ripples) {
strokeWeight(2);
ripples.forEach((ripple, i) => {
ripple.draw();
})
}
noStroke();
blocks.forEach((block, i) => {
block.calcDiff(ripples);
block.update();
block.checkEdges();
block.render();
});
if (show_info) {
rectMode(CORNER);
fill(20, 200);
rect(0, 0, 120, 64);
fill(220);
textFont('monospace', 16);
text('Ripples: ' + ripples.length, 10, 24);
text('FPS: ' + avg_fps, 10, 48);
}
}
//function mousePressed() {
// ripples.push(new Ripple(mouseX, mouseY, 1));
//}
function mouseMoved() {
if (random() < pow(fps / 60, 3) * mouse_speed / 30) {
ripples.push(new Ripple(mouseX, mouseY, MOVE_SCALE * mouse_speed / 40, mouse_heading));
}
}
function mouseDragged() {
if (random() < pow(fps / 60, 3) * mouse_speed / 20) {
ripples.push(new Ripple(mouseX, mouseY, DRAG_SCALE * mouse_speed / 40, mouse_heading));
}
}
class Block {
constructor(x, y, m, id) {
this.pos = new p5.Vector(x, y);
this.vel = new p5.Vector();
this.acc = new p5.Vector();
this.mass = m;
this.id = id;
}
render() {
fill(255, 128);
rectMode(CENTER);
rect(this.pos.x + this.diff.x, this.pos.y + this.diff.y, this.mass * 15 * 2* this.amp * BLOCK_INCREASE, this.mass * 15 * 2 * this.amp * BLOCK_INCREASE);
}
update() {
this.vel.add(this.acc);
this.pos.add(this.vel);
this.acc.mult(0);
this.vel.mult(RESISTENCE_FACTOR);
}
applyForce(force) {
force.div(this.mass);
this.acc.add(force);
}
checkEdges() {
if (this.pos.x > width + EXTRA_PADDING) {
this.pos.x = 0;
}
if (this.pos.y > height + EXTRA_PADDING) {
this.pos.y = 0;
}
if (this.pos.x < -EXTRA_PADDING) {
this.pos.x = width;
}
if (this.pos.y < -EXTRA_PADDING) {
this.pos.y = height;
}
}
/**
* @param {Ripple[]} ripples
*/
calcDiff(ripples) {
this.diff = new p5.Vector(0, 0);
this.amp = 0;
ripples.forEach((ripple, i) => {
if (!ripple.dists[this.id]) {
ripple.dists[this.id] = dist(this.pos.x, this.pos.y, ripple.pos.x, ripple.pos.y);
};
let distance = ripple.dists[this.id] - ripple.currRadius;
if (distance < 0 && distance > -BLOCK_MOVE_RANGE * 2) {
if (!ripple.angles[this.id]) {
ripple.angles[this.id] = p5.Vector.sub(this.pos, ripple.pos).heading();
};
const angle = ripple.angles[this.id];
const localAmp = cubicInOut(-abs(BLOCK_MOVE_RANGE + distance) + BLOCK_MOVE_RANGE, 0, FORCE_SCALE, BLOCK_MOVE_RANGE);
const forceAmp = localAmp * ripple.strength;
const waveAmp = localAmp * ripple.scale + constrain(this.vel.magSq()/100, 0, 0.01);
const force = p5.Vector.fromAngle(ripple.heading).mult(forceAmp);
this.applyForce(force);
this.amp += waveAmp;
const movement = p5.Vector.fromAngle(angle).mult(waveAmp);
this.diff.add(movement);
}
});
}
}
class Ripple {
constructor(x, y, scale, heading) {
this.pos = new p5.Vector(x, y);
this.initTime = millis();
this.currRadius = 0;
this.endRadius = max(dist(this.pos.x, this.pos.y, 0, 0), dist(this.pos.x, this.pos.y, 0, height), dist(this.pos.x, this.pos.y, width, 0), dist(this.pos.x, this.pos.y, height, width)) + BLOCK_MOVE_RANGE;
this.scale = scale;
this.heading = heading;
this.strength = scale;
this.dists = [];
this.angles = [];
}
checkKill() {
if (this.endRadius < this.currRadius) {
ripples.splice(ripples.indexOf(this), 1);
}
}
updateRadius() {
this.currRadius = (millis() - this.initTime) * RIPPLE_SPEED;
this.strength = this.scale*STRENGTH_FACTOR*pow(1 / (millis() - this.initTime),2);
//this.currRadius = 200;
}
draw() {
stroke(255, cubicInOut(this.strength, 30, 120, 1));
noFill();
ellipse(this.pos.x, this.pos.y, this.currRadius*2, this.currRadius*2);
}
}
function cubicInOut(t, b, c, d) {
if (t <= 0) return b;
else if (t >= d) return b + c;
else {
t /= d / 2;
if (t < 1) return c / 2 * t * t * t + b;
t -= 2;
return c / 2 * (t * t * t + 2) + b;
}
}
html, body {
overflow: hidden;
margin: 0;
padding: 0;
}
canvas {
margin-top: auto;
margin-bottom: auto;
margin-left: auto;
margin-right:auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment