//Surfing on sine waves //(C) Haruka Kataoka 2004 WaveBuf wb; Surfer sf; int surfX = 20;//サーファーの位置 int vx = 1;//ループごとに波を進める量 void setup() { size(200, 200); wb = new WaveBuf(100, 100, 2); sf = new Surfer(wb.peek(surfX), surfX, 2); stroke(255,255,255); framerate(60); } void loop() { background(0,0,0); wb.forward(vx); sf.move(vx, wb.peek(surfX), wb.peekv(surfX)); int dispY = sf.height(); wb.display(100-dispY); sf.display(100-dispY); } //class Wave buffer class WaveBuf { float buf[]; int bufSize; //バッファサイズ int rightBound, leftBound;//バッファ内の波の左右の境界位置 int displayRange; int resolution;//解像度 //波を発生する振動子の速度と、速度に影響する定数 //speed -= kst * 振幅; float speed=5.0, kst=0.1; //波の状態を保持する長さ int duration; //Constructor //aSize: wave bufferの大きさ //aResolution: 表示解像度 WaveBuf(int aSize, int aDispRange, int aResolution) { buf = new float[aSize]; bufSize = aSize; displayRange = aDispRange; resolution = aResolution; leftBound = 0; rightBound = aDispRange - 1; resetParameter(0); fillData_(leftBound, rightBound, -speed); duration = 200; } //kst, speedを再設定して波の状態を変える void resetParameter(float x) { float a = random(10.0, 100.0);//次の最大振幅 float v = random(0.2, 5.0);//次の最大速度 kst = (v*v) / (a*a); float t = 2*a*a - x*x; if (t > 0.0) { speed = ((speed>0.0)? 1: -1) * sqrt(kst*t); }else{ speed = 0.0; } } //buf[from..to] の中の波データを埋める void fillData(int from, int to) { if (from <= to) { if (from == 0) { fillData_(from, to, buf[bufSize-1]); }else{ fillData_(from, to, buf[from-1]); } }else{ fillData_(from, bufSize-1, buf[from-1]); fillData_( 0, to, buf[bufSize-1]); } } void fillData_(int from, int to, float preData) { for (int i=from; i<=to; i++){ preData += speed; buf[i] = preData; speed += - kst * preData; if (--duration <= 0) { duration = int(random(bufSize/2, bufSize*2)); resetParameter((float)preData); } } } //波を val 進める void forward(int val) { int reFillStart = rightBound + 1; if (reFillStart >= bufSize) reFillStart -= bufSize; rightBound += val; if (rightBound >= bufSize) rightBound -= bufSize; leftBound += val; if (leftBound >= bufSize) leftBound -= bufSize; fillData(reFillStart, rightBound); } //表示 void display(int zeroY) { if (leftBound <= rightBound) { display_(leftBound, rightBound, 0, zeroY); }else{ int x = display_(leftBound, bufSize-1, 0, zeroY); line( x, zeroY + buf[bufSize-1], x+resolution, zeroY + buf[0]); x += resolution; display_( 0, rightBound, x, zeroY); } } int display_(int from, int to, int x, int y) { for(int i=from; i= bufSize) x -= bufSize; return buf[x]; } //位置 x の波の傾きを返す //x: leftBoundからの位置 float peekv(int x) { int f, b; f = leftBound + x + 1; b = leftBound + x - 1; if (f >= bufSize) f -= bufSize; if (b >= bufSize) b -= bufSize; return (buf[f] - buf[b]) / 2.0; } } class Surfer { float height; //サーファーの高さ float vy; //Y方向の速度 float g=0.2; //重力(vyを増加させる) float r=0.04; //空気抵抗(vyの大きさを規制する) int x, resolution;//X 位置, 解像度 //Constractor //aHeight: サーファーの初期高さ //aX: サーファーの位置 (WaveBuffer での leftBoundからの位置) //aResolution: 表示解像度 Surfer(float aHeight, int aX, int aResolution) { height = aHeight; vy = 0.0; x = aX*aResolution; resolution = aResolution; } //dX サーファーを進める //aHeight, wbv : 進んだ先の波の高さと傾き void move(int dX, float aHeight, float wbv) { height += vy * dX; if (height > aHeight) { vy = wbv; height = aHeight; }else{ vy = vy + g - r*vy; } } //表示 void display(int zeroY) { float rad = atan2(-vy, 1); int cs = (int)(resolution*2*cos(rad)); int sn = (int)(resolution*2*sin(rad)); //board int lx, ly, rx, ry; lx = x - cs; ly = zeroY+(int)height + sn; rx = x + cs; ry = zeroY+(int)height - sn; line(lx, ly, rx, ry); //legs int ax, ay; ax = x - (int)(resolution * rad); ay = zeroY+(int)height - resolution*4; line(lx, ly, ax, ay); line(rx, ry, ax, ay); //body int ny = ay - resolution*3; line(ax, ay, x, ny); //head line(x, ny, x, ny - resolution); //arms line(x, ny, x-cs*2, ny + resolution*2); line(x, ny, x+cs*2, ny + resolution*2); } //サーファーの高さを返す int height() { return (int)height; } }