xxxxxxxxxx
// Happy Place
// j.tarbell March, 2004
// Albuquerque, New Mexico
// complexification.net
// Processing 0085 Beta syntax update
// j.tarbell April, 2005
// ported to p5.js by TradeMark Gunderson September, 2022
var dim = 900;
var num = 128;
// var time = 0;
var friends = [];
var maxpal = 512;
var numpal = 0;
var goodcolor = [];
var preloadedImage;
function preload() {
preloadedImage = loadImage("longStickhorse.gif");
}
function setup() {
var res = min(displayWidth, displayHeight);
// createCanvas(res,res,P2D);
createCanvas(900,900,P2D); // P3D was in the original code, but it runs VERY slow here on openprocessing
// (unfortunate, since P3D looks better)
// size(dim,dim,P3D);
takecolor(preloadedImage);
// background(255);
background(155);
// frameRate(30);
// friends = new Friend[num];
resetAll();
}
function draw() {
// move friends to happy places
for (var c=0;c<num;c++) {
friends[c].move();
}
for (var c=0;c<num;c++) {
friends[c].expose();
friends[c].exposeConnections();
}
// if (time%2==0) for (var c=0;c<num;c++) {
if (frameCount%2==0) for (var c=0;c<num;c++) {
friends[c].findHappyPlace();
}
// time++;
}
function mousePressed () {
resetAll();
background(255);
}
function resetAll() {
// make some friend entities
for (var x=0;x<num;x++) {
var fx = dim/2 + 0.4*dim*cos(TWO_PI*x/num);
var fy = dim/2 + 0.4*dim*sin(TWO_PI*x/num);
friends[x] = new Friend(fx,fy,x);
}
// make some random friend connections
for (var k=0;k<num*2.2;k++) {
var a = int(floor(random(num)));
var b = int(floor(a+random(22))%num);
if (b>=num) {
b=0;
print("+");
} else if (b<0) {
b=0;
print("+");
}
if (a!=b) {
friends[a].connectTo(b);
friends[b].connectTo(a);
// println(a+" made friends with "+b);
}
}
}
// OBJECTS ---------------------------------------------------------------
class Friend {
constructor(X, Y, Id) {
// position
this.dx = this.x = X;
this.dy = this.y = Y;
this.id = Id;
this.vx = 0;
this.vy = 0;
this.numcon = 0;
this.maxcon = 10;
this.lencon = 10+int(random(50));
// var[] connections = new var[maxcon];
this.connections = [];
// sand painters
this.numsands = 3;
// SandPainter[] sands = new SandPainter[numsands];
this.sands = [];
this.myc = somecolor();
for (var n=0;n<this.numsands;n++) {
this.sands[n] = new SandPainter();
}
}
expose() {
for (this.dx=-2;this.dx<3;this.dx++) {
var a = 0.5-abs(this.dx)/5.0;
stroke(0,256*a);
point(this.x+this.dx,this.y);
stroke(255,256*a);
point(this.x+this.dx-1,this.y-1);
}
for (this.dy=-2;this.dy<3;this.dy++) {
var a = 0.5-abs(this.dy)/5.0;
stroke(0,256*a);
point(this.x,this.y+this.dy);
stroke(255,256*a);
point(this.x-1,this.y+this.dy-1);
}
}
exposeConnections() {
// draw connection lines to all friends
for (var n=0;n<this.numcon;n++) {
// find axis distances
var ox = friends[this.connections[n]].x;
var oy = friends[this.connections[n]].y;
for (var s=0;s<this.numsands;s++) {
this.sands[s].render(this.x,this.y,ox,oy);
}
}
}
render() {
for(var xx=int(this.x-this.numcon);xx<int(this.x+this.numcon);xx++) {
for(var yy=int(this.y-this.numcon);yy<int(this.y+this.numcon);yy++) {
stroke(this.myc);
point(xx,yy);
}
}
}
renderConnections() {
for (var n=0;n<this.numcon;n++) {
var ddx = friends[this.connections[n]].x-this.x;
var ddy = friends[this.connections[n]].y-this.y;
var m = int(1 + sqrt(ddx*ddx+ddy*ddy)/6);
for (var k=0;k<m;k++) {
var t = (1 + cos(k*PI/m))/2;
var px = int(this.x + t*ddx);
var py = int(this.y + t*ddy);
stroke("#333333");
point(px,py);
}
}
}
move() {
// add velocity to position
this.x+=this.vx;
this.y+=this.vy;
//friction
this.vx*=0.92;
this.vy*=0.92;
}
connectTo(f) {
// connect to friend f
// is there room for more friends?
if (this.numcon<this.maxcon) {
// already connected to friend?
if (!this.friendOf(f)) {
this.connections[this.numcon] = f;
this.numcon++;
}
}
}
friendOf(x) {
var isFriend = false;
for (var n=0;n<this.numcon;n++) {
if (this.connections[n]==this.x) isFriend=true;
}
return isFriend;
}
findHappyPlace() {
// set destination to a happier place
// (closer to friends, further from others)
var ax = 0.0;
var ay = 0.0;
// find mean average of all friends and non-friends
for (var n=0;n<num;n++) {
if (friends[n]!=this) {
// find distance
var ddx = friends[n].x-this.x;
var ddy = friends[n].y-this.y;
var d = sqrt(ddx*ddx + ddy*ddy);
var t = atan2(ddy,ddx);
var friend = false;
for (var j=0;j<this.numcon;j++) if (this.connections[j]==n) friend=true;
if (friend) {
// attract
if (d>this.lencon) {
ax += 4.0*cos(t);
ay += 4.0*sin(t);
}
} else {
// repulse
if (d<this.lencon) {
ax += (this.lencon-d)*cos(t+PI);
ay += (this.lencon-d)*sin(t+PI);
}
}
}
}
this.vx+=ax/42.22;
this.vy+=ay/42.22;
}
}
class SandPainter {
constructor() {
this.p = random(1.0);
this.c = somecolor();
this.g = random(0.01,0.1);
}
render(x, y, ox, oy) {
// draw painting sweeps
stroke(red(this.c),green(this.c),blue(this.c),28);
point(ox+(x-ox)*sin(this.p),oy+(y-oy)*sin(this.p));
this.g+=random(-0.050,0.050);
var maxg = 0.22;
if (this.g<-maxg) this.g=-maxg;
if (this.g>maxg) this.g=maxg;
var w = this.g/10.0;
for (var i=0;i<11;i++) {
var a = 0.1-i/110;
stroke(red(this.c),green(this.c),blue(this.c),256*a);
point(ox+(x-ox)*sin(this.p+sin(i*w)),oy+(y-oy)*sin(this.p + sin(i*w)));
point(ox+(x-ox)*sin(this.p-sin(i*w)),oy+(y-oy)*sin(this.p - sin(i*w)));
}
}
}
// color routines ----------------------------------------------------------------
function somecolor() {
// pick some random good color
return goodcolor[int(random(numpal))];
}
function takecolor(img) {
var b;
// b = loadImage(fn);
b = img;
image(b,0,0);
for (var x=0;x<b.width;x++){
for (var y=0;y<b.height;y++) {
var c = get(x,y);
var exists = false;
for (var n=0;n<numpal;n++) {
if (c==goodcolor[n]) {
exists = true;
break;
}
}
if (!exists) {
// add color to pal
if (numpal<maxpal) {
goodcolor[numpal] = c;
numpal++;
}
}
}
}
// pump black and white in
for (var x=0;x<22;x++) {
goodcolor[numpal]="#000000";
numpal++;
goodcolor[numpal]="#FFFFFF";
numpal++;
}
}
// j.tarbell March, 2004
// Albuquerque, New Mexico
// complexification.net