Initial Commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Bounce.
|
||||
*
|
||||
* When the shape hits the edge of the window, it reverses its direction.
|
||||
*/
|
||||
|
||||
int rad = 60; // Width of the shape
|
||||
float xpos, ypos; // Starting position of shape
|
||||
|
||||
float xspeed = 2.8; // Speed of the shape
|
||||
float yspeed = 2.2; // Speed of the shape
|
||||
|
||||
int xdirection = 1; // Left or Right
|
||||
int ydirection = 1; // Top to Bottom
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(640, 360);
|
||||
noStroke();
|
||||
frameRate(30);
|
||||
ellipseMode(RADIUS);
|
||||
// Set the starting position of the shape
|
||||
xpos = width/2;
|
||||
ypos = height/2;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(102);
|
||||
|
||||
// Update the position of the shape
|
||||
xpos = xpos + ( xspeed * xdirection );
|
||||
ypos = ypos + ( yspeed * ydirection );
|
||||
|
||||
// Test to see if the shape exceeds the boundaries of the screen
|
||||
// If it does, reverse its direction by multiplying by -1
|
||||
if (xpos > width-rad || xpos < rad) {
|
||||
xdirection *= -1;
|
||||
}
|
||||
if (ypos > height-rad || ypos < rad) {
|
||||
ydirection *= -1;
|
||||
}
|
||||
|
||||
// Draw the shape
|
||||
ellipse(xpos, ypos, rad, rad);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Bouncy Bubbles
|
||||
* based on code from Keith Peters.
|
||||
*
|
||||
* Multiple-object collision.
|
||||
*/
|
||||
|
||||
|
||||
int numBalls = 12;
|
||||
float spring = 0.05;
|
||||
float gravity = 0.03;
|
||||
float friction = -0.9;
|
||||
Ball[] balls = new Ball[numBalls];
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
balls[i] = new Ball(random(width), random(height), random(30, 70), i, balls);
|
||||
}
|
||||
noStroke();
|
||||
fill(255, 204);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
for (Ball ball : balls) {
|
||||
ball.collide();
|
||||
ball.move();
|
||||
ball.display();
|
||||
}
|
||||
}
|
||||
|
||||
class Ball {
|
||||
|
||||
float x, y;
|
||||
float diameter;
|
||||
float vx = 0;
|
||||
float vy = 0;
|
||||
int id;
|
||||
Ball[] others;
|
||||
|
||||
Ball(float xin, float yin, float din, int idin, Ball[] oin) {
|
||||
x = xin;
|
||||
y = yin;
|
||||
diameter = din;
|
||||
id = idin;
|
||||
others = oin;
|
||||
}
|
||||
|
||||
void collide() {
|
||||
for (int i = id + 1; i < numBalls; i++) {
|
||||
float dx = others[i].x - x;
|
||||
float dy = others[i].y - y;
|
||||
float distance = sqrt(dx*dx + dy*dy);
|
||||
float minDist = others[i].diameter/2 + diameter/2;
|
||||
if (distance < minDist) {
|
||||
float angle = atan2(dy, dx);
|
||||
float targetX = x + cos(angle) * minDist;
|
||||
float targetY = y + sin(angle) * minDist;
|
||||
float ax = (targetX - others[i].x) * spring;
|
||||
float ay = (targetY - others[i].y) * spring;
|
||||
vx -= ax;
|
||||
vy -= ay;
|
||||
others[i].vx += ax;
|
||||
others[i].vy += ay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void move() {
|
||||
vy += gravity;
|
||||
x += vx;
|
||||
y += vy;
|
||||
if (x + diameter/2 > width) {
|
||||
x = width - diameter/2;
|
||||
vx *= friction;
|
||||
}
|
||||
else if (x - diameter/2 < 0) {
|
||||
x = diameter/2;
|
||||
vx *= friction;
|
||||
}
|
||||
if (y + diameter/2 > height) {
|
||||
y = height - diameter/2;
|
||||
vy *= friction;
|
||||
}
|
||||
else if (y - diameter/2 < 0) {
|
||||
y = diameter/2;
|
||||
vy *= friction;
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
ellipse(x, y, diameter, diameter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Brownian motion.
|
||||
*
|
||||
* Recording random movement as a continuous line.
|
||||
*/
|
||||
|
||||
int num = 2000;
|
||||
int range = 6;
|
||||
|
||||
float[] ax = new float[num];
|
||||
float[] ay = new float[num];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(640, 360);
|
||||
for(int i = 0; i < num; i++) {
|
||||
ax[i] = width/2;
|
||||
ay[i] = height/2;
|
||||
}
|
||||
frameRate(30);
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(51);
|
||||
|
||||
// Shift all elements 1 place to the left
|
||||
for(int i = 1; i < num; i++) {
|
||||
ax[i-1] = ax[i];
|
||||
ay[i-1] = ay[i];
|
||||
}
|
||||
|
||||
// Put a new value at the end of the array
|
||||
ax[num-1] += random(-range, range);
|
||||
ay[num-1] += random(-range, range);
|
||||
|
||||
// Constrain all points to the screen
|
||||
ax[num-1] = constrain(ax[num-1], 0, width);
|
||||
ay[num-1] = constrain(ay[num-1], 0, height);
|
||||
|
||||
// Draw a line connecting the points
|
||||
for(int i=1; i<num; i++) {
|
||||
float val = float(i)/num * 204.0 + 51;
|
||||
stroke(val);
|
||||
line(ax[i-1], ay[i-1], ax[i], ay[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
class Ball {
|
||||
PVector position;
|
||||
PVector velocity;
|
||||
|
||||
float radius, m;
|
||||
|
||||
Ball(float x, float y, float r_) {
|
||||
position = new PVector(x, y);
|
||||
velocity = PVector.random2D();
|
||||
velocity.mult(3);
|
||||
radius = r_;
|
||||
m = radius*.1;
|
||||
}
|
||||
|
||||
void update() {
|
||||
position.add(velocity);
|
||||
}
|
||||
|
||||
void checkBoundaryCollision() {
|
||||
if (position.x > width-radius) {
|
||||
position.x = width-radius;
|
||||
velocity.x *= -1;
|
||||
} else if (position.x < radius) {
|
||||
position.x = radius;
|
||||
velocity.x *= -1;
|
||||
} else if (position.y > height-radius) {
|
||||
position.y = height-radius;
|
||||
velocity.y *= -1;
|
||||
} else if (position.y < radius) {
|
||||
position.y = radius;
|
||||
velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
void checkCollision(Ball other) {
|
||||
|
||||
// Get distances between the balls components
|
||||
PVector distanceVect = PVector.sub(other.position, position);
|
||||
|
||||
// Calculate magnitude of the vector separating the balls
|
||||
float distanceVectMag = distanceVect.mag();
|
||||
|
||||
// Minimum distance before they are touching
|
||||
float minDistance = radius + other.radius;
|
||||
|
||||
if (distanceVectMag < minDistance) {
|
||||
float distanceCorrection = (minDistance-distanceVectMag)/2.0;
|
||||
PVector d = distanceVect.copy();
|
||||
PVector correctionVector = d.normalize().mult(distanceCorrection);
|
||||
other.position.add(correctionVector);
|
||||
position.sub(correctionVector);
|
||||
|
||||
// get angle of distanceVect
|
||||
float theta = distanceVect.heading();
|
||||
// precalculate trig values
|
||||
float sine = sin(theta);
|
||||
float cosine = cos(theta);
|
||||
|
||||
/* bTemp will hold rotated ball positions. You
|
||||
just need to worry about bTemp[1] position*/
|
||||
PVector[] bTemp = {
|
||||
new PVector(), new PVector()
|
||||
};
|
||||
|
||||
/* this ball's position is relative to the other
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].position.x and bTemp[0].position.y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
PVector[] vTemp = {
|
||||
new PVector(), new PVector()
|
||||
};
|
||||
|
||||
vTemp[0].x = cosine * velocity.x + sine * velocity.y;
|
||||
vTemp[0].y = cosine * velocity.y - sine * velocity.x;
|
||||
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||
|
||||
/* Now that velocities are rotated, you can use 1D
|
||||
conservation of momentum equations to calculate
|
||||
the final velocity along the x-axis. */
|
||||
PVector[] vFinal = {
|
||||
new PVector(), new PVector()
|
||||
};
|
||||
|
||||
// final rotated velocity for b[0]
|
||||
vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
|
||||
// final rotated velocity for b[0]
|
||||
vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
|
||||
vFinal[1].y = vTemp[1].y;
|
||||
|
||||
// hack to avoid clumping
|
||||
bTemp[0].x += vFinal[0].x;
|
||||
bTemp[1].x += vFinal[1].x;
|
||||
|
||||
/* Rotate ball positions and velocities back
|
||||
Reverse signs in trig expressions to rotate
|
||||
in the opposite direction */
|
||||
// rotate balls
|
||||
PVector[] bFinal = {
|
||||
new PVector(), new PVector()
|
||||
};
|
||||
|
||||
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||
|
||||
// update balls to screen position
|
||||
other.position.x = position.x + bFinal[1].x;
|
||||
other.position.y = position.y + bFinal[1].y;
|
||||
|
||||
position.add(bFinal[0]);
|
||||
|
||||
// update velocities
|
||||
velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
noStroke();
|
||||
fill(204);
|
||||
ellipse(position.x, position.y, radius*2, radius*2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Circle Collision with Swapping Velocities
|
||||
* by Ira Greenberg.
|
||||
*
|
||||
* Based on Keith Peter's Solution in
|
||||
* Foundation Actionscript Animation: Making Things Move!
|
||||
*/
|
||||
|
||||
Ball[] balls = {
|
||||
new Ball(100, 400, 20),
|
||||
new Ball(700, 400, 80)
|
||||
};
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(51);
|
||||
|
||||
for (Ball b : balls) {
|
||||
b.update();
|
||||
b.display();
|
||||
b.checkBoundaryCollision();
|
||||
}
|
||||
|
||||
balls[0].checkCollision(balls[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
// Custom Cube Class
|
||||
|
||||
class Cube {
|
||||
// Position, velocity vectors
|
||||
PVector position;
|
||||
PVector velocity;
|
||||
// Also using PVector to hold rotation values for 3 axes
|
||||
PVector rotation;
|
||||
|
||||
// Vertices of the cube
|
||||
PVector[] vertices = new PVector[24];
|
||||
// width, height, depth
|
||||
float w, h, d;
|
||||
|
||||
// colors for faces of cube
|
||||
color[] quadBG = new color[6];
|
||||
|
||||
Cube(float w, float h, float d) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.d = d;
|
||||
|
||||
// Colors are hardcoded
|
||||
quadBG[0] = color(0);
|
||||
quadBG[1] = color(51);
|
||||
quadBG[2] = color(102);
|
||||
quadBG[3] = color(153);
|
||||
quadBG[4] = color(204);
|
||||
quadBG[5] = color(255);
|
||||
|
||||
// Start in center
|
||||
position = new PVector();
|
||||
// Random velocity vector
|
||||
velocity = PVector.random3D();
|
||||
// Random rotation
|
||||
rotation = new PVector(random(40, 100), random(40, 100), random(40, 100));
|
||||
|
||||
// cube composed of 6 quads
|
||||
//front
|
||||
vertices[0] = new PVector(-w/2, -h/2, d/2);
|
||||
vertices[1] = new PVector(w/2, -h/2, d/2);
|
||||
vertices[2] = new PVector(w/2, h/2, d/2);
|
||||
vertices[3] = new PVector(-w/2, h/2, d/2);
|
||||
//left
|
||||
vertices[4] = new PVector(-w/2, -h/2, d/2);
|
||||
vertices[5] = new PVector(-w/2, -h/2, -d/2);
|
||||
vertices[6] = new PVector(-w/2, h/2, -d/2);
|
||||
vertices[7] = new PVector(-w/2, h/2, d/2);
|
||||
//right
|
||||
vertices[8] = new PVector(w/2, -h/2, d/2);
|
||||
vertices[9] = new PVector(w/2, -h/2, -d/2);
|
||||
vertices[10] = new PVector(w/2, h/2, -d/2);
|
||||
vertices[11] = new PVector(w/2, h/2, d/2);
|
||||
//back
|
||||
vertices[12] = new PVector(-w/2, -h/2, -d/2);
|
||||
vertices[13] = new PVector(w/2, -h/2, -d/2);
|
||||
vertices[14] = new PVector(w/2, h/2, -d/2);
|
||||
vertices[15] = new PVector(-w/2, h/2, -d/2);
|
||||
//top
|
||||
vertices[16] = new PVector(-w/2, -h/2, d/2);
|
||||
vertices[17] = new PVector(-w/2, -h/2, -d/2);
|
||||
vertices[18] = new PVector(w/2, -h/2, -d/2);
|
||||
vertices[19] = new PVector(w/2, -h/2, d/2);
|
||||
//bottom
|
||||
vertices[20] = new PVector(-w/2, h/2, d/2);
|
||||
vertices[21] = new PVector(-w/2, h/2, -d/2);
|
||||
vertices[22] = new PVector(w/2, h/2, -d/2);
|
||||
vertices[23] = new PVector(w/2, h/2, d/2);
|
||||
}
|
||||
|
||||
// Cube shape itself
|
||||
void drawCube() {
|
||||
// Draw cube
|
||||
for (int i=0; i<6; i++) {
|
||||
fill(quadBG[i]);
|
||||
beginShape(QUADS);
|
||||
for (int j=0; j<4; j++) {
|
||||
vertex(vertices[j+4*i].x, vertices[j+4*i].y, vertices[j+4*i].z);
|
||||
}
|
||||
endShape();
|
||||
}
|
||||
}
|
||||
|
||||
// Update location
|
||||
void update() {
|
||||
position.add(velocity);
|
||||
|
||||
// Check wall collisions
|
||||
if (position.x > bounds/2 || position.x < -bounds/2) {
|
||||
velocity.x*=-1;
|
||||
}
|
||||
if (position.y > bounds/2 || position.y < -bounds/2) {
|
||||
velocity.y*=-1;
|
||||
}
|
||||
if (position.z > bounds/2 || position.z < -bounds/2) {
|
||||
velocity.z*=-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Display method
|
||||
void display() {
|
||||
pushMatrix();
|
||||
translate(position.x, position.y, position.z);
|
||||
rotateX(frameCount*PI/rotation.x);
|
||||
rotateY(frameCount*PI/rotation.y);
|
||||
rotateZ(frameCount*PI/rotation.z);
|
||||
noStroke();
|
||||
drawCube(); // Farm out shape to another method
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Cubes Contained Within a Cube
|
||||
* by Ira Greenberg.
|
||||
*
|
||||
* Collision detection against all
|
||||
* outer cube's surfaces.
|
||||
*/
|
||||
|
||||
// 20 little internal cubes
|
||||
Cube[] cubies = new Cube[20];
|
||||
|
||||
// Size of outer cube
|
||||
float bounds = 300;
|
||||
|
||||
void setup() {
|
||||
size(640, 360, P3D);
|
||||
|
||||
for (int i = 0; i < cubies.length; i++) {
|
||||
// Cubies are randomly sized
|
||||
float cubieSize = random(5, 15);
|
||||
cubies[i] = new Cube(cubieSize, cubieSize, cubieSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(50);
|
||||
lights();
|
||||
|
||||
// Center in display window
|
||||
translate(width/2, height/2, -130);
|
||||
|
||||
// Rotate everything, including external large cube
|
||||
rotateX(frameCount * 0.001);
|
||||
rotateY(frameCount * 0.002);
|
||||
rotateZ(frameCount * 0.001);
|
||||
stroke(255);
|
||||
|
||||
|
||||
// Outer transparent cube, just using box() method
|
||||
noFill();
|
||||
box(bounds);
|
||||
|
||||
// Move and rotate cubies
|
||||
for (Cube c : cubies) {
|
||||
c.update();
|
||||
c.display();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Linear Motion.
|
||||
*
|
||||
* Changing a variable to create a moving line.
|
||||
* When the line moves off the edge of the window,
|
||||
* the variable is set to 0, which places the line
|
||||
* back at the bottom of the screen.
|
||||
*/
|
||||
|
||||
float a;
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
stroke(255);
|
||||
a = height/2;
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(51);
|
||||
line(0, a, width, a);
|
||||
a = a - 0.5;
|
||||
if (a < 0) {
|
||||
a = height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Morph.
|
||||
*
|
||||
* Changing one shape into another by interpolating
|
||||
* vertices from one to another
|
||||
*/
|
||||
|
||||
// Two ArrayLists to store the vertices for two shapes
|
||||
// This example assumes that each shape will have the same
|
||||
// number of vertices, i.e. the size of each ArrayList will be the same
|
||||
ArrayList<PVector> circle = new ArrayList<PVector>();
|
||||
ArrayList<PVector> square = new ArrayList<PVector>();
|
||||
|
||||
// An ArrayList for a third set of vertices, the ones we will be drawing
|
||||
// in the window
|
||||
ArrayList<PVector> morph = new ArrayList<PVector>();
|
||||
|
||||
// This boolean variable will control if we are morphing to a circle or square
|
||||
boolean state = false;
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
|
||||
// Create a circle using vectors pointing from center
|
||||
for (int angle = 0; angle < 360; angle += 9) {
|
||||
// Note we are not starting from 0 in order to match the
|
||||
// path of a circle.
|
||||
PVector v = PVector.fromAngle(radians(angle-135));
|
||||
v.mult(100);
|
||||
circle.add(v);
|
||||
// Let's fill out morph ArrayList with blank PVectors while we are at it
|
||||
morph.add(new PVector());
|
||||
}
|
||||
|
||||
// A square is a bunch of vertices along straight lines
|
||||
// Top of square
|
||||
for (int x = -50; x < 50; x += 10) {
|
||||
square.add(new PVector(x, -50));
|
||||
}
|
||||
// Right side
|
||||
for (int y = -50; y < 50; y += 10) {
|
||||
square.add(new PVector(50, y));
|
||||
}
|
||||
// Bottom
|
||||
for (int x = 50; x > -50; x -= 10) {
|
||||
square.add(new PVector(x, 50));
|
||||
}
|
||||
// Left side
|
||||
for (int y = 50; y > -50; y -= 10) {
|
||||
square.add(new PVector(-50, y));
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(51);
|
||||
|
||||
// We will keep how far the vertices are from their target
|
||||
float totalDistance = 0;
|
||||
|
||||
// Look at each vertex
|
||||
for (int i = 0; i < circle.size(); i++) {
|
||||
PVector v1;
|
||||
// Are we lerping to the circle or square?
|
||||
if (state) {
|
||||
v1 = circle.get(i);
|
||||
}
|
||||
else {
|
||||
v1 = square.get(i);
|
||||
}
|
||||
// Get the vertex we will draw
|
||||
PVector v2 = morph.get(i);
|
||||
// Lerp to the target
|
||||
v2.lerp(v1, 0.1);
|
||||
// Check how far we are from target
|
||||
totalDistance += PVector.dist(v1, v2);
|
||||
}
|
||||
|
||||
// If all the vertices are close, switch shape
|
||||
if (totalDistance < 0.1) {
|
||||
state = !state;
|
||||
}
|
||||
|
||||
// Draw relative to center
|
||||
translate(width/2, height/2);
|
||||
strokeWeight(4);
|
||||
// Draw a polygon that makes up all the vertices
|
||||
beginShape();
|
||||
noFill();
|
||||
stroke(255);
|
||||
for (PVector v : morph) {
|
||||
vertex(v.x, v.y);
|
||||
}
|
||||
endShape(CLOSE);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Moving On Curves.
|
||||
*
|
||||
* In this example, the circles moves along the curve y = x^4.
|
||||
* Click the mouse to have it move to a new position.
|
||||
*/
|
||||
|
||||
float beginX = 20.0; // Initial x-coordinate
|
||||
float beginY = 10.0; // Initial y-coordinate
|
||||
float endX = 570.0; // Final x-coordinate
|
||||
float endY = 320.0; // Final y-coordinate
|
||||
float distX; // X-axis distance to move
|
||||
float distY; // Y-axis distance to move
|
||||
float exponent = 4; // Determines the curve
|
||||
float x = 0.0; // Current x-coordinate
|
||||
float y = 0.0; // Current y-coordinate
|
||||
float step = 0.01; // Size of each step along the path
|
||||
float pct = 0.0; // Percentage traveled (0.0 to 1.0)
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
noStroke();
|
||||
distX = endX - beginX;
|
||||
distY = endY - beginY;
|
||||
}
|
||||
|
||||
void draw() {
|
||||
fill(0, 2);
|
||||
rect(0, 0, width, height);
|
||||
pct += step;
|
||||
if (pct < 1.0) {
|
||||
x = beginX + (pct * distX);
|
||||
y = beginY + (pow(pct, exponent) * distY);
|
||||
}
|
||||
fill(255);
|
||||
ellipse(x, y, 20, 20);
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
pct = 0.0;
|
||||
beginX = x;
|
||||
beginY = y;
|
||||
endX = mouseX;
|
||||
endY = mouseY;
|
||||
distX = endX - beginX;
|
||||
distY = endY - beginY;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Non-orthogonal Reflection
|
||||
* by Ira Greenberg.
|
||||
*
|
||||
* Based on the equation (R = 2N(N*L)-L) where R is the
|
||||
* reflection vector, N is the normal, and L is the incident
|
||||
* vector.
|
||||
*/
|
||||
|
||||
// Position of left hand side of floor
|
||||
PVector base1;
|
||||
// Position of right hand side of floor
|
||||
PVector base2;
|
||||
// Length of floor
|
||||
float baseLength;
|
||||
|
||||
// An array of subpoints along the floor path
|
||||
PVector[] coords;
|
||||
|
||||
// Variables related to moving ball
|
||||
PVector position;
|
||||
PVector velocity;
|
||||
float r = 6;
|
||||
float speed = 3.5;
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
|
||||
fill(128);
|
||||
base1 = new PVector(0, height-150);
|
||||
base2 = new PVector(width, height);
|
||||
createGround();
|
||||
|
||||
// start ellipse at middle top of screen
|
||||
position = new PVector(width/2, 0);
|
||||
|
||||
// calculate initial random velocity
|
||||
velocity = PVector.random2D();
|
||||
velocity.mult(speed);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// draw background
|
||||
fill(0, 12);
|
||||
noStroke();
|
||||
rect(0, 0, width, height);
|
||||
|
||||
// draw base
|
||||
fill(200);
|
||||
quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height);
|
||||
|
||||
// calculate base top normal
|
||||
PVector baseDelta = PVector.sub(base2, base1);
|
||||
baseDelta.normalize();
|
||||
PVector normal = new PVector(-baseDelta.y, baseDelta.x);
|
||||
|
||||
// draw ellipse
|
||||
noStroke();
|
||||
fill(255);
|
||||
ellipse(position.x, position.y, r*2, r*2);
|
||||
|
||||
// move elipse
|
||||
position.add(velocity);
|
||||
|
||||
// normalized incidence vector
|
||||
PVector incidence = PVector.mult(velocity, -1);
|
||||
incidence.normalize();
|
||||
|
||||
// detect and handle collision
|
||||
for (int i=0; i<coords.length; i++) {
|
||||
// check distance between ellipse and base top coordinates
|
||||
if (PVector.dist(position, coords[i]) < r) {
|
||||
|
||||
// calculate dot product of incident vector and base top normal
|
||||
float dot = incidence.dot(normal);
|
||||
|
||||
// calculate reflection vector
|
||||
// assign reflection vector to direction vector
|
||||
velocity.set(2*normal.x*dot - incidence.x, 2*normal.y*dot - incidence.y, 0);
|
||||
velocity.mult(speed);
|
||||
|
||||
// draw base top normal at collision point
|
||||
stroke(255, 128, 0);
|
||||
line(position.x, position.y, position.x-normal.x*100, position.y-normal.y*100);
|
||||
}
|
||||
}
|
||||
|
||||
// detect boundary collision
|
||||
// right
|
||||
if (position.x > width-r) {
|
||||
position.x = width-r;
|
||||
velocity.x *= -1;
|
||||
}
|
||||
// left
|
||||
if (position.x < r) {
|
||||
position.x = r;
|
||||
velocity.x *= -1;
|
||||
}
|
||||
// top
|
||||
if (position.y < r) {
|
||||
position.y = r;
|
||||
velocity.y *= -1;
|
||||
// randomize base top
|
||||
base1.y = random(height-100, height);
|
||||
base2.y = random(height-100, height);
|
||||
createGround();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate variables for the ground
|
||||
void createGround() {
|
||||
// calculate length of base top
|
||||
baseLength = PVector.dist(base1, base2);
|
||||
|
||||
// fill base top coordinate array
|
||||
coords = new PVector[ceil(baseLength)];
|
||||
for (int i=0; i<coords.length; i++) {
|
||||
coords[i] = new PVector();
|
||||
coords[i].x = base1.x + ((base2.x-base1.x)/baseLength)*i;
|
||||
coords[i].y = base1.y + ((base2.y-base1.y)/baseLength)*i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
class Ground {
|
||||
float x1, y1, x2, y2;
|
||||
float x, y, len, rot;
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
class Orb {
|
||||
// Orb has positio and velocity
|
||||
PVector position;
|
||||
PVector velocity;
|
||||
float r;
|
||||
// A damping of 80% slows it down when it hits the ground
|
||||
float damping = 0.8;
|
||||
|
||||
Orb(float x, float y, float r_) {
|
||||
position = new PVector(x, y);
|
||||
velocity = new PVector(.5, 0);
|
||||
r = r_;
|
||||
}
|
||||
|
||||
void move() {
|
||||
// Move orb
|
||||
velocity.add(gravity);
|
||||
position.add(velocity);
|
||||
}
|
||||
|
||||
void display() {
|
||||
// Draw orb
|
||||
noStroke();
|
||||
fill(200);
|
||||
ellipse(position.x, position.y, r*2, r*2);
|
||||
}
|
||||
|
||||
// Check boundaries of window
|
||||
void checkWallCollision() {
|
||||
if (position.x > width-r) {
|
||||
position.x = width-r;
|
||||
velocity.x *= -damping;
|
||||
}
|
||||
else if (position.x < r) {
|
||||
position.x = r;
|
||||
velocity.x *= -damping;
|
||||
}
|
||||
}
|
||||
|
||||
void checkGroundCollision(Ground groundSegment) {
|
||||
|
||||
// Get difference between orb and ground
|
||||
float deltaX = position.x - groundSegment.x;
|
||||
float deltaY = position.y - groundSegment.y;
|
||||
|
||||
// Precalculate trig values
|
||||
float cosine = cos(groundSegment.rot);
|
||||
float sine = sin(groundSegment.rot);
|
||||
|
||||
/* Rotate ground and velocity to allow
|
||||
orthogonal collision calculations */
|
||||
float groundXTemp = cosine * deltaX + sine * deltaY;
|
||||
float groundYTemp = cosine * deltaY - sine * deltaX;
|
||||
float velocityXTemp = cosine * velocity.x + sine * velocity.y;
|
||||
float velocityYTemp = cosine * velocity.y - sine * velocity.x;
|
||||
|
||||
/* Ground collision - check for surface
|
||||
collision and also that orb is within
|
||||
left/rights bounds of ground segment */
|
||||
if (groundYTemp > -r &&
|
||||
position.x > groundSegment.x1 &&
|
||||
position.x < groundSegment.x2 ) {
|
||||
// keep orb from going into ground
|
||||
groundYTemp = -r;
|
||||
// bounce and slow down orb
|
||||
velocityYTemp *= -1.0;
|
||||
velocityYTemp *= damping;
|
||||
}
|
||||
|
||||
// Reset ground, velocity and orb
|
||||
deltaX = cosine * groundXTemp - sine * groundYTemp;
|
||||
deltaY = cosine * groundYTemp + sine * groundXTemp;
|
||||
velocity.x = cosine * velocityXTemp - sine * velocityYTemp;
|
||||
velocity.y = cosine * velocityYTemp + sine * velocityXTemp;
|
||||
position.x = groundSegment.x + deltaX;
|
||||
position.y = groundSegment.y + deltaY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Non-orthogonal Collision with Multiple Ground Segments
|
||||
* by Ira Greenberg.
|
||||
*
|
||||
* Based on Keith Peter's Solution in
|
||||
* Foundation Actionscript Animation: Making Things Move!
|
||||
*/
|
||||
|
||||
Orb orb;
|
||||
|
||||
PVector gravity = new PVector(0,0.05);
|
||||
// The ground is an array of "Ground" objects
|
||||
int segments = 40;
|
||||
Ground[] ground = new Ground[segments];
|
||||
|
||||
void setup(){
|
||||
size(640, 360);
|
||||
// An orb object that will fall and bounce around
|
||||
orb = new Orb(50, 50, 3);
|
||||
|
||||
// Calculate ground peak heights
|
||||
float[] peakHeights = new float[segments+1];
|
||||
for (int i=0; i<peakHeights.length; i++){
|
||||
peakHeights[i] = random(height-40, height-30);
|
||||
}
|
||||
|
||||
/* Float value required for segment width (segs)
|
||||
calculations so the ground spans the entire
|
||||
display window, regardless of segment number. */
|
||||
float segs = segments;
|
||||
for (int i=0; i<segments; i++){
|
||||
ground[i] = new Ground(width/segs*i, peakHeights[i], width/segs*(i+1), peakHeights[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void draw(){
|
||||
// Background
|
||||
noStroke();
|
||||
fill(0, 15);
|
||||
rect(0, 0, width, height);
|
||||
|
||||
// Move and display the orb
|
||||
orb.move();
|
||||
orb.display();
|
||||
// Check walls
|
||||
orb.checkWallCollision();
|
||||
|
||||
// Check against all the ground segments
|
||||
for (int i=0; i<segments; i++){
|
||||
orb.checkGroundCollision(ground[i]);
|
||||
}
|
||||
|
||||
|
||||
// Draw ground
|
||||
fill(127);
|
||||
beginShape();
|
||||
for (int i=0; i<segments; i++){
|
||||
vertex(ground[i].x1, ground[i].y1);
|
||||
vertex(ground[i].x2, ground[i].y2);
|
||||
}
|
||||
vertex(ground[segments-1].x2, height);
|
||||
vertex(ground[0].x1, height);
|
||||
endShape(CLOSE);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user