-
-
Save bruce55/92d3c3d3268133c13cf57e88f64310f5 to your computer and use it in GitHub Desktop.
Bruce's NOC midterm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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