https://editor.p5js.org/cassiescheirer/sketches/SknMGG_O7
I don't know why but my computer was having an incredibly hard time exporting my frames -- some were being skipped, and everything was patchy. I had Char help me export and the GIF still ended up being way too slow. Click the link above it or here (https://editor.p5js.org/cassiescheirer/sketches/SknMGG_O7) to see it in the p5.js editor. Sorry about this.
Anyway, I am mostly happy with this project. I wish I had had more time to make it more fancy, and a better laptop so that I wouldn't have gotten so frustrated at the lag, but overall I am proud. It took a little while to come up with the idea, but once I knew what I wanted to do, I had to make it happen. Again I had Char talk through the syntax I didn't know, but a lot of it I figured out myself this time. For the easing function, I knew that I was probably going to need one to simulate the "bouncing" of the ball, so I looked for one that matched that motion the most. I went through a couple of them before concluding that the doubleExponentialSigmoid, which Golan had already used in the template, was actually the best one. Having that as a guide was helpful.
I'm proud of myself for having a set idea in mind and then putting in the effort to execute it, even though it was hard. I also really like the simplicity of my GIF. At one point I was about to add some flashing circles in the background, but Char told me that the minimalist-ness of it was what made it so nice. However, I think it is only that way because I hadn't allotted enough time to make it super grand. If I had more time and had known more of the p5.js syntax, I definitely would have made it more complicated. As you can see in my sketch (bottom left), I started an idea that branched off of the flipping square -- a skillet flipping a pancake. I stopped myself there though, as I knew I probably didn't know enough to do that. I hope I can come back to this project when I have time and make the pancake idea.
//=================================================== // User-modifiable global variables. var myNickname = "Cassie"; var nFramesInLoop = 120; var bEnableExport = true; // Other global variables you don't need to touch. var nElapsedFrames; var bRecording; var theCanvas; var canvaswidth = 645; var canvasheight = 645; var flipper = false; //=================================================== function setup() { theCanvas = createCanvas(canvaswidth, canvasheight); bRecording = false; nElapsedFrames = 0; rectMode(CENTER); } //=================================================== 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! //---------------------- // here, I set the background and some other graphical properties var x = abs(cos(percent*TWO_PI)) var y = doubleExponentialSigmoid(x, 0.25); var squish = map(y, 0, 1, 10, 30); background(0); rectMode(CENTER); strokeWeight(2); stroke(255); // flipping base push(); translate(width / 2 + 20*sin(TWO_PI*percent), height-250); rotate(sin(TWO_PI*percent)); var flipx = map(-cos(frameCount/9.5), -1, 1, 0, 200); if (frameCount % 120 >= 60) { fill(200, 100, 200); } else { fill(200,200,100); } rect(0, 20, flipx, 200); pop(); translate(width / 2, height / 2); // ball shadow push(); var shadowbounce = map(y, 0, 1, 100, 40); fill(0); noStroke(); rotate(-abs(cos(TWO_PI*percent))); ellipse(0, shadowbounce, cos(frameCount/20)*20, cos(frameCount/20)*15); pop(); // ball push(); fill(255); var ballbounce = map(-y,0,1,100,360); distance = height - ballbounce; ellipse(0, ballbounce, 30, squish); pop(); // Symmetric double-element sigmoid function ('_a' is the 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); } } |