// size int height = 700; int width = 600; // time int nbFramePerSec = 80; float drawPeriod = 1/nbFramePerSec; // ground variables ------------------------------------------- int nbSegment = 40; Ground[] ground = new Ground[nbSegment]; float[] groundHeight = new float[nbSegment + 1]; //physics variables float mass = 0.1; // kg float radius = 15; // 1px = 1cm <<-------- float bounceFactor = -0.95; // dimensionless float Cd = 0.47; // drag coef, dimensionless float rho = 1.22; // density, kg / m^3 float ag = 9.81; // acceleration, m/s^2 float Fx, Fy, ax, ay; // build ball ------------------------------------------- // top left corner is (x, y) = (0, 0) // bottom right corner is (width, height) = (0, 0) // x (cm), y (cm), vx (cm/s), vy (cm/s) int xinit = round(width * 0.0); int yinit = round(width * 0.95); int vxinit = 8; // cm/s int vyinit = -18; // cm/s Ball ball = new Ball(xinit, yinit, vxinit, vyinit, radius, mass, bounceFactor); float A = PI * (ball.r/100) * (ball.r/100); // surface, m^2 // setup(), executed once at inception ----------------------------------- void setup() { size(width, height); background(255); smooth(); frameRate(nbFramePerSec); // frames per sec // calculate ground height for each nbSegment+1 points for (int i = 0; i < groundHeight.length; i++) { groundHeight[i] = random(height - 45, height - 30); } // build ground over width of canvas, regardless of segment number float nbSegmentFloat = nbSegment; for (int i = 0; i < nbSegment; i++) { ground[i] = new Ground(i*width/nbSegmentFloat, groundHeight[i], (i+1)*width/nbSegmentFloat, groundHeight[i + 1]); } } void draw() { // display white background with opacity noStroke(); fill(255, 999); // first arg is white=255, second arg is opacity 999=opaque and 0=transparent rect(0, 0, width, height); // draw ground fill(153); beginShape(); for (int i = 0; i < nbSegment; i++) { vertex(ground[i].x1, ground[i].y1); } vertex(ground[nbSegment-1].x2, ground[nbSegment-1].y2); vertex(ground[nbSegment - 1].x2, height); vertex(ground[0].x1, height); endShape(CLOSE); // ball physics // drag force: Fd = -1/2 * Cd * A * rho * v * v Fx = -0.5 * Cd * A * rho * pow(ball.vx, 3) / abs(ball.vx); Fy = -0.5 * Cd * A * rho * pow(ball.vy, 3) / abs(ball.vy); //Fx = 0; //Fy = 0; // acceleration ( sum of forces = mass * acceleration ) ax = Fx / ball.m; ay = ag + (Fy / ball.m); // Integrate to get velocity ball.vx += ax * drawPeriod; ball.vy += ay * drawPeriod; // Integrate to get position ball.x += ball.vx * drawPeriod * 100; // factor 100 due to x and vx defined in cm ball.y += ball.vy * drawPeriod * 100; // factor 100 due to x and vx defined in cm // draw ball stroke(0); fill(200,0,0); ellipse(ball.x, ball.y, ball.r * 2, ball.r * 2); // collision checkWallCollision(); for (int i = 0; i < nbSegment; i++) { checkGroundCollision(ground[i]); // print out variable in console //println("ball.vy="+ball.vy); } } // wall collision void checkWallCollision() { // right wall if (ball.x > width - ball.r) { ball.x = width - ball.r; ball.vx *= ball.bounce; } else /* left wall */ if (ball.x < ball.r) { ball.x = ball.r; ball.vx *= ball.bounce; } } // ground collision void checkGroundCollision(Ground groundSegment) { // distance ball and ground float deltaX = ball.x - groundSegment.x; float deltaY = ball.y - groundSegment.y; // trig values float cosRot = cos(groundSegment.rot); float sinRot = sin(groundSegment.rot); // rotate to ground referential float deltaXRefGround = cosRot * deltaX + sinRot * deltaY; float deltaYRefGround = cosRot * deltaY - sinRot * deltaX; float vxRefGround = cosRot * ball.vx + sinRot * ball.vy; float vyRefGround = cosRot * ball.vy - sinRot * ball.vx; // ground collision segment check if (deltaYRefGround > -ball.r && ball.x > groundSegment.x1 && ball.x < groundSegment.x2) { deltaYRefGround = -ball.r; vyRefGround *= ball.bounce; } // reset ground, velocity and orb deltaX = cosRot * deltaXRefGround - sinRot * deltaYRefGround; deltaY = cosRot * deltaYRefGround + sinRot * deltaXRefGround; ball.vx = cosRot * vxRefGround - sinRot * vyRefGround; ball.vy = cosRot * vyRefGround + sinRot * vxRefGround; ball.x = groundSegment.x + deltaX; ball.y = groundSegment.y + deltaY; } // Classes ---------------------------------------------------- class Ground { float x1, y1, x2, y2; float x, y, len, rot; // default constructor Ground() {} // constructor Ground(float x1, float y1, float x2, float y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; x = (x1 + x2) / 2; y = (y1 + y2) / 2; len = dist(x1, y1, x2, y2); rot = atan2((y2 - y1), (x2 - x1)); } } class Ball { float x, y, vx, vy, r, m, bounce; // default constructor Ball() {} Ball(float x, float y, float vx, float vy, float r, float m, float bounce) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.r = r; this.m = m; this.bounce = bounce; } }
<canvas width="600px" height="700px"></canvas>
canvas { display:block; margin:20px; border:1px solid #666; } </style> <script type="text/javascript"> window.addEventListener('load', function() { var scripts=document.body.getElementsByTagName('script'); var canvases=document.body.getElementsByTagName('canvas'); new Processing(canvases[0], scripts[0].text); } , false); // Here prevents javascript in body from throwing error </script> <style>