Overall I am pretty satisfied with how this turned out, and it looks very close to what I had on my sketch. For the background switch I decided to use the EaseInOutElastic function after trying out a hand full of different easing functions because this one looks almost exactly like what I imagined the transition to be when I made my sketch. I believe the bounciness really suites the style of the visuals that I created here and defiantly adds to the overall quality of the piece. The hardest part about this assignment was defiantly the fact that I had to think and calculate everything based on the percentage frame rate. It was not so easy to wrap my head around that and when I ran into a glitch I have to really sit down and think about where the problem is. Did I lose count on the frame somewhere or was it something else. For example this one:
I also wish that I can spend more time to make the movement of the boat more natural. Maybe with some tilt at appropriate time.s
My Sketch:
The Code:
// INSTRUCTIONS FOR EXPORTING FRAMES (from which to make a GIF): // 1. Run a local server, using instructions from here: // https://github.com/processing/p5.js/wiki/Local-server // 2. Set the bEnableExport variable to true. // 3. Set the myNickname variable to your name. // 4. Run the program from Chrome, press 'f'. // Look in your 'Downloads' folder for the generated frames. // 5. Note: Retina screens may export frames at twice the resolution. //=================================================== // User-modifiable global variables. var myNickname = "shuann"; var nFramesInLoop = 120; var bEnableExport = true; var myScale = 0.006; var myLoopingNoiseArray0 = []; var myLoopingNoiseArray1 = []; var myLoopingNoiseArray2 = []; var myLoopingNoiseArray3 = []; var myLoopingNoiseArray4 = []; var myLoopingNoiseArray5 = []; var myLoopingNoiseArray6 = []; var myLoopingNoiseArray7 = []; var myLoopingNoiseArray8 = []; var myLoopingNoiseArray9 = []; // Other global variables you don't need to touch. var nElapsedFrames; var bRecording; var theCanvas; //=================================================== function setup() { theCanvas = createCanvas(640, 640); bRecording = false; nElapsedFrames = 0; var radius = 60; noiseSeed(40); //waves at the bottom //sorry the style is horrible for (var i = 0; i < nFramesInLoop; i++){ var rotatingArmAngle = map(i, 0 ,120, 0, TWO_PI); var px = width/2 + radius * cos(rotatingArmAngle); var py = height/2 + radius * sin(rotatingArmAngle); var noiseAtLoc0 = height - 50 * noise(myScale * px, myScale * py); var noiseAtLoc1 = height - 80 * noise(myScale * px, myScale * py); var noiseAtLoc2 = height - 150 * noise(myScale * px, myScale * py); var noiseAtLoc3 = height - 200 * noise(myScale * px, myScale * py); var noiseAtLoc4 = height - 300 * noise(myScale * px, myScale * py); myLoopingNoiseArray0[i] = round(noiseAtLoc0); myLoopingNoiseArray1[i] = round(noiseAtLoc1); myLoopingNoiseArray2[i] = round(noiseAtLoc2); myLoopingNoiseArray3[i] = round(noiseAtLoc3); myLoopingNoiseArray4[i] = round(noiseAtLoc4); var px1 = width/2 + radius * 0.7 * cos(rotatingArmAngle); var py1 = height/2 + radius * 0.7 * sin(rotatingArmAngle); var noiseAtLoc5 = height - 60 * noise(myScale * px1, myScale * py1); var noiseAtLoc6 = height - 130 * noise(myScale * px1, myScale * py1); var noiseAtLoc7 = height - 230 * noise(myScale * px1, myScale * py1); var noiseAtLoc8 = height - 330 * noise(myScale * px1, myScale * py1); var noiseAtLoc9 = height - 450 * noise(myScale * px1, myScale * py1); myLoopingNoiseArray5[i] = round(noiseAtLoc5); myLoopingNoiseArray6[i] = round(noiseAtLoc6); myLoopingNoiseArray7[i] = round(noiseAtLoc7); myLoopingNoiseArray8[i] = round(noiseAtLoc8); myLoopingNoiseArray9[i] = round(noiseAtLoc9); } } //=================================================== function keyTyped() { if (bEnableExport) { if ((key === 'f') || (key === 'F')) { bRecording = true; nElapsedFrames = 0; } } } //=================================================== function draw() { // Compute a percentage (0...1) representing where we are in the loop. var percentCompleteFraction = 0; if (bRecording) { percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop); } else { percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop); } // Render the design, based on that percentage. // This function renderMyDesign() is the one for you to change. renderMyDesign (percentCompleteFraction); // If we're recording the output, save the frame to a file. // Note that the output images may be 2x large if you have a Retina mac. // You can compile these frames into an animated GIF using a tool like: if (bRecording && bEnableExport) { var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png"; print("Saving output image: " + frameOutputFilename); saveCanvas(theCanvas, frameOutputFilename, 'png'); nElapsedFrames++; if (nElapsedFrames >= nFramesInLoop) { bRecording = false; } } } //=================================================== function renderMyDesign (percent) { // // THIS IS WHERE YOUR ART GOES. // This is an example of a function that renders a temporally looping design. // It takes a "percent", between 0 and 1, indicating where we are in the loop. // Use, modify, or delete whatever you prefer from this example. // This example uses several different graphical techniques. // Remember to SKETCH FIRST! //---------------------- smooth(); var cx = 100; var cy = 100; push(); translate(width/2, height/2); if (percent < 0.5){ var ang = function_PennerEaseInOutElastic(percent*2)*180; rotate(radians(ang)); drawbackdrop(percent); } else { var ang = function_PennerEaseInOutElastic(map(percent, 0.5, 1, 0, 1))*180; rotate(radians(ang) + TWO_PI/2); drawbackdrop(percent); } drawbackdrop(percent); pop(); noStroke(); push(); translate(0, -100); drawboat(percent,-0.1); drawWave(percent, 88, 176, 230, myLoopingNoiseArray9, -0.1); drawWave(percent, 80, 160, 210, myLoopingNoiseArray8, 0); drawWave(percent, 22, 132, 200, myLoopingNoiseArray7, 0.6); drawWave(percent, 49, 80, 152, myLoopingNoiseArray6, 0.8); drawWave(percent, 54, 100, 160, myLoopingNoiseArray5, 0.8); pop(); drawWave(percent, 45, 183, 212, myLoopingNoiseArray4, -0.2); drawWave(percent, 45, 167, 212, myLoopingNoiseArray3, -0.2); drawWave(percent, 65, 130, 190, myLoopingNoiseArray2, -0.2); drawWave(percent, 54, 100, 160, myLoopingNoiseArray1, 0.5); drawWave(percent, 49, 80, 152, myLoopingNoiseArray0, 0.5); } function drawbackdrop(p){ fill(235,219,190); rect(-width, -height, width*3, height); fill(18,24,56); rect(-width, 0, width*3, height); //draw sun push(); strokeWeight(3); stroke(235,172, 45); fill(235,172, 45); ellipse(200, -200, 50, 50); translate(200, -200); rotate(0.2 * p * TWO_PI); push(); for (var a = 0; a < 10; a++){ rotate(TWO_PI/10); line (50, 0, 70, 0); } pop(); pop(); //draw moon push(); noStroke(); fill(255); translate(-200, 200); ellipse(0, 0, 80, 80); fill(18,24,56); ellipse(-20, -10, 50, 50); pop(); //draw star push(); translate(-100, 110); noStroke(); fill(255); star(0, 0, 5, 10, 5); star(50, 110, 5, 10, 5); star(80, 90, 3, 6, 5); star(100, 105, 3, 6, 5); pop(); } function drawboat(p, tilt){ currStep = round(p * nFramesInLoop); var nx = map(40, 0, nFramesInLoop, 0, width); var ny = myLoopingNoiseArray9[(currStep+40)%nFramesInLoop] // var newy = doubleExponentialSigmoid(map(y, 315, 370, 0, 1), 0.7);//does not look good // var y = map(newy, 0, 1, 315, 370); fill(255); beginShape(); vertex(nx - 50, ny - 10); vertex(nx + 50, ny - 10); vertex(nx + 30, ny + 20); vertex(nx - 30, ny + 20); endShape(); stroke(255); line(nx, ny, nx, ny - 50); triangle(nx, ny - 50, nx + 20, ny - 40, nx, ny - 30); } function drawWave(p, r, g, b, wave, tilt){ currStep = round(p * nFramesInLoop); fill(r, g, b); noStroke(); beginShape(); vertex(0,height+50); for (var i = 0; i < wave.length; i++) { var nx = map(i, 0, nFramesInLoop - 1, 0, width); if (i + currStep >= nFramesInLoop) { var ny = wave[(i + currStep)-nFramesInLoop] - i*tilt; } else { var ny = wave[i + currStep] - i*tilt; } vertex(nx, ny); } vertex(width,height+50); endShape(); } // symmetric double-element sigmoid function (a is slope) // See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js // From: https://idmnyu.github.io/p5.js-func/ //=================================================== function doubleExponentialSigmoid (_x, _a){ if(!_a) _a = 0.75; // default var min_param_a = 0.0 + Number.EPSILON; var max_param_a = 1.0 - Number.EPSILON; _a = constrain(_a, min_param_a, max_param_a); _a = 1-_a; var _y = 0; if (_x<=0.5){ _y = (pow(2.0*_x, 1.0/_a))/2.0; } else { _y = 1.0 - (pow(2.0*(1.0-_x), 1.0/_a))/2.0; } return(_y); } //From: https://github.com/golanlevin/Pattern_Master/blob/master/pattern_master/F00.pde //------------------------------------------------------------------ function function_PennerEaseInOutElastic (t) { if (t===0) return 0; if ((t/=0.5)==2) return 1; var p=(.3 * 1.5); var a=1; var s=p/4; if (t < 1) { var postFix = pow(2, 10*(t-=1)); // postIncrement is evil return -0.5 * (postFix* sin( (t-s)*(2*PI)/p )); } var postFix = pow(2, -10*(t-=1)); // postIncrement is evil return postFix * sin( (t-s)*(2*PI)/p )*.5 + 1; } //From: https://p5js.org/examples/form-star.html //------------------------------------------------------------------ function star(x, y, radius1, radius2, npoints) { var angle = TWO_PI / npoints; var halfAngle = angle/2.0; beginShape(); for (var a = 0; a < TWO_PI; a += angle) { var sx = x + cos(a) * radius2; var sy = y + sin(a) * radius2; vertex(sx, sy); sx = x + cos(a+halfAngle) * radius1; sy = y + sin(a+halfAngle) * radius1; vertex(sx, sy); } endShape(CLOSE); } |
.