/** * MeanderN moves a point along a wandering path. * Uses noise function to generate varying directions. * Motion is constrained to the given x,y area. * Original class by Robert Hodgin - flight404.com * Tweaked by naper at potatoland.org * * MeanderN m; * * void setup() { * size(200,200); * m = new MeanderN(width/2, height/2, 3, 0,0,width,height); * } * * void loop() { * ellipse(m.getX(), m.getY(), 6, 6); * m.exist(); * } */ class MeanderN { float x, prevx; // current and previous position float y, prevy; float v; // velocity: how many pixels to move each step float xv; float yv; float theta; // for calculating motion based on noise values float angle; float noiseVal; float noiseCount; float noiseScale = 0.007f; float minX, minY, maxX, maxY; // meander will stay in these bounds float targetX, targetY; // if target is true, meander will move towards this point boolean target = false; boolean checkBounds = true; // if true, stay inside meander area int direction = 1; // 1 or -1: used to reverse direction float smoothing = .3f; // 1 to .01: smaller values smooth out the path float meanderishness = 4f; // 1 to 100: larger numbers increase the amount of meandering MeanderN(float xStart, float yStart, float vStart, float aMinX, float aMinY, float aMaxX, float aMaxY){ x = prevx = xStart; y = prevy = yStart; v = vStart; minX = aMinX; maxX = aMaxX; minY = aMinY; maxY = aMaxY; } void exist(){ findVelocity(); move(); } void findVelocity(){ // get the next noise value, convert to a direction, tune it, break into x and y components noiseCount += noiseScale; noiseVal = (float) PerlinNoise.noise( (double) (x + noiseCount) * noiseScale, (double) (y + noiseCount) * noiseScale, (double) noiseCount); angle -= (angle - noiseVal * 1440.0f) * .3f; theta = - (float)Math.toRadians(angle); xv = (float)Math.cos(theta) * v; yv = (float)Math.sin(theta) * v; } void move(){ // hold onto previous position prevx = x; prevy = y; // If target is enabled, move towards it, otherwise move in meander direction if (target) { x -= (x - targetX) * .1f; y -= (y - targetY) * .1f; } else { x -= xv; y -= yv; } // if out of bounds, reverse direction and move back if (checkBounds && (x < minX || x > maxX || y < minY || y > maxY)){ direction = -direction; x += 2*xv; y += 2*yv; } } void setTarget(int tx, int ty) { target = true; targetX = tx; targetY = ty; } void setTargetOff() { target = false; } float getX() { return x; } float getY() { return y; } float getAngle() { return (float)Math.atan2(prevy-y, prevx-x); } } /***** class Meander { float[] x; float[] y; float v; float xv; float yv; float theta; float angle; float angleDelta; float noiseVal; float noiseCount; float noiseScale = 0.007f; int width, height; Meander (float xSent, float ySent, float vSent, int w, int h) { x = new float[2]; y = new float[2]; for (int i=0; i<=1; i++){ //print(i); x[i] = xSent; y[i] = ySent; } v = vSent; width = w; height = h; } void exist() { findVelocity(); move(); } void findVelocity() { noiseCount += noiseScale; noiseVal = (float) PerlinNoise.noise( (double) (x[0] + noiseCount) * noiseScale, (double) (y[0] + noiseCount) * noiseScale, (double) noiseCount); angle -= (angle - noiseVal * 1440.0f) * .3f; theta = - (float)Math.toRadians(angle); xv = (float)Math.cos(theta) * v; yv = (float)Math.sin(theta) * v; } void move() { x[1] = x[0]; y[1] = y[0]; //if (mousePressed){ // x[0] -= (x[0] - mouseX) * .1; // y[0] -= (y[0] - mouseY) * .1; //} else { x[0] -= xv; y[0] -= yv; //} int limit=0; if (x[0] < -limit || x[0] > width + limit || y[0] < -limit || y[0] > height + limit){ x[0] = width/2; x[1] = width/2; y[0] = height/2; y[1] = height/2; } } } ****/