Open6

つぶやきprocessing置き場

leviosa42leviosa42

よく使うテンプレート

f=0
draw=_=>{
    f++||
        /* 本来setup関数で行う処理.末尾に+をつける */
    /* 本来draw関数で行う処理 */
}

少し解説

line 1
f=0

p5.jsのビルトイン引数frameCountの代わりに扱う変数.
毎フレーム呼ばれるdraw関数で1増加させるとframeCountの代わりになる.

line 2-6
draw=_=>{
    /* ... */
}

普通はfunctionキーワードを使うけど,今回はアロー関数を使って関数を宣言しdraw変数に代入する.
今回のケースは,

  1. 引数はいらない
  2. 変数drawに代入する

なので,functionを使った書き方を含め3種類の書き方を比較すると,

function draw(){/* 文 */} // (1) 17bytes
draw=()=>{/* 文 */}       // (2) 11bytes
draw=_=>{/* 文 /*}        // (3) 10bytes

ということで,(3)の書き方が短く書ける.ただし,この書き方だと**_は引数として使われているので,本処理では使わないように(もしくは使っていない変数を1文字割り当てる)**

line 3-4
    f++||
        /* 本来setup関数で行う処理.末尾に+をつける */

短絡評価と後置インクリメントを使う.

leviosa42leviosa42

クリックした高さを振幅に減衰運動する点群

code
02-damped-vibration-a.min
f=Y=T=t=0
F=(A,t)=>A*exp(-5e-4*t)*cos(0.1*t)
draw=_=>{
f++||createCanvas(W=600,W)
background(250)
translate(0,W/2)
t=f-T
line(0,Y,W,Y)
push()
strokeWeight(5)
for(i=50;i--;point((t-i)*4%W,F(Y,t-i)));pop()}
mouseClicked=_=>{Y=mouseY-W/2;T=f}//つぶやきprocessing
code (つぶやきprocessing向けに字数を削減してない)
02-damped-vibration-a
/* 録画用
P5Capture.setDefaultOptions({
  format: "gif",
  framerate: 30,
  quality: 0.8,
  width: 320,
});
/*

/**
 * @param A 振幅
 * @param b 減衰定数
 * @param m 質量
 * @param k ばね定数
 * @param p 初期位相
 * @return function
 */
const F = (A, b, m, k, p) => (A, t) => {
  // @param w_ 減衰振動子の角振動定数
  const w_ = sqrt(k / m - b ** 2 / (4 * m ** 2));
  return A * exp((-b * t) / (2 * m)) * cos(w_ * t - p);
};

// X(A, t) ... 振幅A, 時間tを引数にとる座標
const X = F(100, 1e2, 1e5, 1e2, 0);

// const W = 600;
// const H = 600;
let W, H;

// translate()基準のマウス座標
let mX;
let mY;

// mouseClickedが発火した時のマウス座標や時間
let mXs = 0;
let mYs = 0;
let clickedT = 0;

function setup() {
  createCanvas((W = windowWidth), (H = windowHeight));
  strokeWeight(10);
}

function draw() {
  /* 録画用
  if (frameCount === 1) {
    const capture = P5Capture.getInstance();
    capture.start();
  }
  */
  background(220);
  translate(0, H / 2);

  push();
  {
    stroke(200);
    strokeWeight(1);
    line(-W, 0, W, 0);
    line(0, -H, 0, H);
  }
  pop();

  push();
  {
    strokeWeight(5);
    point(mXs, mYs);
    strokeWeight(1);
    line(-W, mYs, W, mYs);
  }
  pop();
  mX = mouseX;
  mY = mouseY - H / 2;

  let t = (frameCount - clickedT) * 4;

  push();
  {
    stroke(200);
    strokeWeight(1);
    line(-mX, 0, mX, 0);
    line(0, -mY, 0, mY);
  }
  pop();

  text(
    `mX, mY = ${mX}, ${mY}\nmXs, mY = ${mXs}, ${mYs}\nt = ${t}`,
    20,
    20 - H / 2,
    W,
    H
  );

  for (let i = 0, N = 100; i <= N; i++) {
    push();
    stroke(0 + (i / N) * 220);
    point((t - i) % W, X(mYs, t - i));
    pop();
  }
}

function mouseClicked() {
  mXs = mX;
  mYs = mY;
  clickedT = frameCount;
}

leviosa42leviosa42

跳ねる物体

code (not minified)
03-bouncing-masses
class Mass {
  constructor(opts) {
    Object.assign(this, opts);
  }

  update() {
    // this.acc.add(this.gravity);
    this.acc.add(this.acc);
    const accel = p5.Vector.add(this.acc, this.gravity);

    this.vel.add(accel);
    // this.vel.limit(this.topspeed);
    this.loc.add(this.vel);

    if (this.isReachEdgeW()) {
      this.acc.mult(this.e);
      this.vel.mult(this.e, 1);
      this.loc.x = this.loc.x < this.edgeW[0] ? this.edgeW[0] : this.edgeW[1];
    }
    if (this.isReachEdgeH()) {
      this.acc.mult(this.e);
      this.vel.mult(1, this.e);
      this.loc.y = this.loc.y < this.edgeH[0] ? this.edgeH[0] : this.edgeH[1];
    }
  }

  isReachEdgeW() {
    return this.loc.x <= this.edgeW[0] || this.loc.x >= this.edgeW[1];
  }

  isReachEdgeH() {
    return this.loc.y <= this.edgeH[0] || this.loc.y >= this.edgeH[1];
  }

  display() {
    push();
    strokeWeight(1);
    // text(
    //   `(${this.loc.x.toFixed(1)}, ${this.loc.y.toFixed(1)})`,
    //   this.loc.x + 5,
    //   this.loc.y + 5
    // );
    const relVel = p5.Vector.add(this.loc, p5.Vector.mult(this.vel, -4));
    stroke(this.massColor);
    line(this.loc.x, this.loc.y, relVel.x, relVel.y);
    pop();

    push();
    fill(this.massColor);
    ellipse(this.loc.x, this.loc.y, 10, 10);
    pop();

    push();
    const relA = p5.Vector.add(this.loc, this.acc);
    const relV = p5.Vector.add(this.loc, this.vel);

    strokeWeight(1);
    line(this.loc.x, this.loc.y, relA.x, relA.y);
    pop();
  }
}

let W, H;

let masses = [];
let MASS_N = 100;

function generateRandomMass() {
  const edgeW = [0 + 30, width - 30];
  const edgeH = [0 + 30, height - 30];
  const massColor = color(random(255));
  const vel = createVector(
    random(-0.01,0.01)*width,
    random(-0.01,0.01)*height
  )
  return new Mass({
    massColor: massColor,
    edgeW: edgeW,
    edgeH: edgeH,
    acc: createVector(0, 0),
    vel: vel,
    loc: createVector(random(edgeW[1]), random(edgeH[1])),
    gravity: createVector(0, 0.6),
    e: -random(0.8),
  });
}
function setup() {
  createCanvas((W = 600), (H = 600));

  // for (let i = 0; i < MASS_N; i++) {
  //   let m = generateRandomMass();
  //   masses.push(m);
  // }
}

// P5Capture.setDefaultOptions({
//   format: "gif",
//   framerate: 60,
//   quality: 0.5,
//   width: 320,
// });

function draw() {
  // if (frameCount === 1) {
  //   const capture = P5Capture.getInstance();
  //   capture.start({
  //     duration: 150,
  //   });
  // }
  background(220);
  // translate(width / 2, height / 2);

  text(
    [`frameCount = ${frameCount}`,
     `n = ${masses.length}`
    ].join("\n"),
    20,
    20
  );

  push();
  for (let i = 0; i < masses.length; i++) {
    masses[i].update();
    masses[i].display();
  }
  
  frameCount % 1 || masses.push(generateRandomMass())
  masses.length > MASS_N && masses.shift();
  pop();
}

leviosa42leviosa42

メキシカンハット

code(mnified)
setup=_=>{
createCanvas(350,250)
stroke(127);
d=Array(160).fill(100)
R=3.14/180
for(Y=-180;Y<181;Y+=6){for(X=-180;X<181;X+=4){
r=R*sqrt(X*X+Y*Y)
Z=100*cos(r)-30*cos(3*r)
x=~~(80+X/3-Y/6)
y=~~(40-Y/6-Z/4)
if(x<0|x>160|d[x]<y)continue
point(x*2,y*2)
d[x]=y
}}}//#つぶやきprocessing

code (not minified)
function mexicanHat() {
  const result = [];

  let d = new Array(160);
  for (let i = 0; i < 160; i++) d[i] = 100;
  let dr = 3.14 / 180;

  for (let y = -180; y <= 180; y += 6) {
    for (let x = -180; x <= 180; x += 4) {
      let r = dr * sqrt(x * x + y * y);
      let z = 100 * cos(r) - 30 * cos(3 * r);
      let sx = int(80 + x / 3 - y / 6);
      let sy = int(40 - y / 6 - z / 4);
      if (sx < 0 || sx >= d.length) continue;
      if (d[sx] <= sy) continue;
      let zz = int((z + 100) * 0.035 + 1);
      // point(sx *2, sy * 2);
      result.push([sx, sy]);
      d[sx] = sy;
    }
  }
  return result;
}

let hatsmap;
let idx = 0;

function setup() {
  createCanvas(330, 220);
  background(0);
  noFill();
  strokeWeight(1);
  stroke("wheat");
  hatsmap = mexicanHat();
}

function draw() {
  // if (frameCount === 1) {
  //   const capture = P5Capture.getInstance();
  //   capture.start({
  //     format: "gif",
  //   });
  // }

  background(0);
  for (i = 0; i <= frameCount * 10; i++) {
    if(i == hatsmap.length) break;
    let [sx, sy] = hatsmap[i];
    point(sx*2, sy*2);
  }
  text(`${i} / ${hatsmap.length}`, 10, height - 10);
}