mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Re-adding Topics to SVN
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Bounce.
|
||||
*
|
||||
* When the shape hits the edge of the window, it reverses its direction.
|
||||
*/
|
||||
|
||||
int size = 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, 200);
|
||||
noStroke();
|
||||
frameRate(30);
|
||||
smooth();
|
||||
// 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-size || xpos < 0) {
|
||||
xdirection *= -1;
|
||||
}
|
||||
if (ypos > height-size || ypos < 0) {
|
||||
ydirection *= -1;
|
||||
}
|
||||
|
||||
// Draw the shape
|
||||
ellipse(xpos+size/2, ypos+size/2, size, size);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Bouncy Bubbles.
|
||||
* Based on code from Keith Peters (www.bit-101.com).
|
||||
*
|
||||
* 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, 200);
|
||||
noStroke();
|
||||
smooth();
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
balls[i] = new Ball(random(width), random(height), random(20, 40), i, balls);
|
||||
}
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(0);
|
||||
for (int i = 0; i < numBalls; i++) {
|
||||
balls[i].collide();
|
||||
balls[i].move();
|
||||
balls[i].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() {
|
||||
fill(255, 204);
|
||||
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,16 @@
|
||||
class Ball{
|
||||
float x, y, r, m;
|
||||
|
||||
// default constructor
|
||||
Ball() {
|
||||
}
|
||||
|
||||
Ball(float x, float y, float r) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
m = r*.1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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)
|
||||
};
|
||||
|
||||
PVector[] vels = {
|
||||
new PVector(2.15, -1.35),
|
||||
new PVector(-1.65, .42)
|
||||
};
|
||||
|
||||
void setup() {
|
||||
size(640, 360);
|
||||
smooth();
|
||||
noStroke();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(51);
|
||||
fill(204);
|
||||
for (int i=0; i< 2; i++){
|
||||
balls[i].x += vels[i].x;
|
||||
balls[i].y += vels[i].y;
|
||||
ellipse(balls[i].x, balls[i].y, balls[i].r*2, balls[i].r*2);
|
||||
checkBoundaryCollision(balls[i], vels[i]);
|
||||
}
|
||||
checkObjectCollision(balls, vels);
|
||||
}
|
||||
|
||||
void checkObjectCollision(Ball[] b, PVector[] v){
|
||||
|
||||
// get distances between the balls components
|
||||
PVector bVect = new PVector();
|
||||
bVect.x = b[1].x - b[0].x;
|
||||
bVect.y = b[1].y - b[0].y;
|
||||
|
||||
// calculate magnitude of the vector separating the balls
|
||||
float bVectMag = sqrt(bVect.x * bVect.x + bVect.y * bVect.y);
|
||||
if (bVectMag < b[0].r + b[1].r){
|
||||
// get angle of bVect
|
||||
float theta = atan2(bVect.y, bVect.x);
|
||||
// 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*/
|
||||
Ball[] bTemp = {
|
||||
new Ball(), new Ball() };
|
||||
|
||||
/* b[1]'s position is relative to b[0]'s
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].x and bTemp[0].y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * bVect.x + sine * bVect.y;
|
||||
bTemp[1].y = cosine * bVect.y - sine * bVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
PVector[] vTemp = {
|
||||
new PVector(), new PVector() };
|
||||
vTemp[0].x = cosine * v[0].x + sine * v[0].y;
|
||||
vTemp[0].y = cosine * v[0].y - sine * v[0].x;
|
||||
vTemp[1].x = cosine * v[1].x + sine * v[1].y;
|
||||
vTemp[1].y = cosine * v[1].y - sine * v[1].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 = ((b[0].m - b[1].m) * vTemp[0].x + 2 * b[1].m *
|
||||
vTemp[1].x) / (b[0].m + b[1].m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
// final rotated velocity for b[0]
|
||||
vFinal[1].x = ((b[1].m - b[0].m) * vTemp[1].x + 2 * b[0].m *
|
||||
vTemp[0].x) / (b[0].m + b[1].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
|
||||
Ball[] bFinal = {
|
||||
new Ball(), new Ball() };
|
||||
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
|
||||
b[1].x = b[0].x + bFinal[1].x;
|
||||
b[1].y = b[0].y + bFinal[1].y;
|
||||
b[0].x = b[0].x + bFinal[0].x;
|
||||
b[0].y = b[0].y + bFinal[0].y;
|
||||
|
||||
// update velocities
|
||||
v[0].x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
v[0].y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
v[1].x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
v[1].y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
void checkBoundaryCollision(Ball ball, PVector vel) {
|
||||
if (ball.x > width-ball.r) {
|
||||
ball.x = width-ball.r;
|
||||
vel.x *= -1;
|
||||
}
|
||||
else if (ball.x < ball.r) {
|
||||
ball.x = ball.r;
|
||||
vel.x *= -1;
|
||||
}
|
||||
else if (ball.y > height-ball.r) {
|
||||
ball.y = height-ball.r;
|
||||
vel.y *= -1;
|
||||
}
|
||||
else if (ball.y < ball.r) {
|
||||
ball.y = ball.r;
|
||||
vel.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Collision (Pong).
|
||||
*
|
||||
* Move the mouse up and down to move the paddle.
|
||||
*/
|
||||
|
||||
// Global variables for the ball
|
||||
float ball_x;
|
||||
float ball_y;
|
||||
float ball_dir = 1;
|
||||
float ball_size = 15; // Radius
|
||||
float dy = 0; // Direction
|
||||
|
||||
// Global variables for the paddle
|
||||
int paddle_width = 10;
|
||||
int paddle_height = 60;
|
||||
|
||||
int dist_wall = 15;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(640, 360);
|
||||
rectMode(RADIUS);
|
||||
ellipseMode(RADIUS);
|
||||
noStroke();
|
||||
smooth();
|
||||
ball_y = height/2;
|
||||
ball_x = 1;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(51);
|
||||
|
||||
ball_x += ball_dir * 1.0;
|
||||
ball_y += dy;
|
||||
if(ball_x > width+ball_size) {
|
||||
ball_x = -width/2 - ball_size;
|
||||
ball_y = random(0, height);
|
||||
dy = 0;
|
||||
}
|
||||
|
||||
// Constrain paddle to screen
|
||||
float paddle_y = constrain(mouseY, paddle_height, height-paddle_height);
|
||||
|
||||
// Test to see if the ball is touching the paddle
|
||||
float py = width-dist_wall-paddle_width-ball_size;
|
||||
if(ball_x == py
|
||||
&& ball_y > paddle_y - paddle_height - ball_size
|
||||
&& ball_y < paddle_y + paddle_height + ball_size) {
|
||||
ball_dir *= -1;
|
||||
if(mouseY != pmouseY) {
|
||||
dy = (mouseY-pmouseY)/2.0;
|
||||
if(dy > 5) { dy = 5; }
|
||||
if(dy < -5) { dy = -5; }
|
||||
}
|
||||
}
|
||||
|
||||
// If ball hits paddle or back wall, reverse direction
|
||||
if(ball_x < ball_size && ball_dir == -1) {
|
||||
ball_dir *= -1;
|
||||
}
|
||||
|
||||
// If the ball is touching top or bottom edge, reverse direction
|
||||
if(ball_y > height-ball_size) {
|
||||
dy = dy * -1;
|
||||
}
|
||||
if(ball_y < ball_size) {
|
||||
dy = dy * -1;
|
||||
}
|
||||
|
||||
// Draw ball
|
||||
fill(255);
|
||||
ellipse(ball_x, ball_y, ball_size, ball_size);
|
||||
|
||||
// Draw the paddle
|
||||
fill(153);
|
||||
rect(width-dist_wall, paddle_y, paddle_width, paddle_height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 = 100;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(640, 200);
|
||||
stroke(255);
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(51);
|
||||
a = a - 0.5;
|
||||
if (a < 0) {
|
||||
a = height;
|
||||
}
|
||||
line(0, a, width, a);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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();
|
||||
smooth();
|
||||
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,91 @@
|
||||
/**
|
||||
* Puff
|
||||
* by Ira Greenberg.
|
||||
*
|
||||
* Series of ellipses simulating a multi-segmented
|
||||
* organism, utilizing a follow the leader algorithm.
|
||||
* Collision detection occurs on the organism's head,
|
||||
* controlling overall direction, and on the individual
|
||||
* body segments, controlling body shape and jitter.
|
||||
*/
|
||||
|
||||
// For puff head
|
||||
float headX;
|
||||
float headY;
|
||||
float speedX = .7;
|
||||
float speedY = .9;
|
||||
|
||||
// For puff body
|
||||
int cells = 1000;
|
||||
float[]px= new float[cells];
|
||||
float[]py= new float[cells];
|
||||
float[]radiiX = new float[cells];
|
||||
float[]radiiY = new float[cells];
|
||||
float[]angle = new float[cells];
|
||||
float[]frequency = new float[cells];
|
||||
float[]cellRadius = new float[cells];
|
||||
|
||||
void setup(){
|
||||
|
||||
size(640, 360);
|
||||
|
||||
// Begin in the center
|
||||
headX = width/2;
|
||||
headY = height/2;
|
||||
|
||||
// Fill body arrays
|
||||
for (int i=0; i< cells; i++){
|
||||
radiiX[i] = random(-7, 7);
|
||||
radiiY[i] = random(-4, 4);
|
||||
frequency[i]= random(-9, 9);
|
||||
cellRadius[i] = random(16, 30);
|
||||
}
|
||||
frameRate(30);
|
||||
}
|
||||
|
||||
void draw(){
|
||||
background(0);
|
||||
noStroke();
|
||||
fill(255, 255, 255, 5);
|
||||
|
||||
// Follow the leader
|
||||
for (int i =0; i< cells; i++){
|
||||
if (i==0){
|
||||
px[i] = headX+sin(radians(angle[i]))*radiiX[i];
|
||||
py[i] = headY+cos(radians(angle[i]))*radiiY[i];
|
||||
}
|
||||
else{
|
||||
px[i] = px[i-1]+cos(radians(angle[i]))*radiiX[i];
|
||||
py[i] = py[i-1]+sin(radians(angle[i]))*radiiY[i];
|
||||
|
||||
// Check collision of body
|
||||
if (px[i] >= width-cellRadius[i]/2 || px[i] <= cellRadius[i]/2){
|
||||
radiiX[i]*=-1;
|
||||
cellRadius[i] = random(1, 40);
|
||||
frequency[i]= random(-13, 13);
|
||||
}
|
||||
if (py[i] >= height-cellRadius[i]/2 || py[i] <= cellRadius[i]/2){
|
||||
radiiY[i]*=-1;
|
||||
cellRadius[i] = random(1, 40);
|
||||
frequency[i]= random(-9, 9);
|
||||
}
|
||||
}
|
||||
// Draw puff
|
||||
ellipse(px[i], py[i], cellRadius[i], cellRadius[i]);
|
||||
// Set speed of body
|
||||
angle[i]+=frequency[i];
|
||||
}
|
||||
|
||||
// Set velocity of head
|
||||
headX+=speedX;
|
||||
headY+=speedY;
|
||||
|
||||
// Check boundary collision of head
|
||||
if (headX >= width-cellRadius[0]/2 || headX <=cellRadius[0]/2){
|
||||
speedX*=-1;
|
||||
}
|
||||
if (headY >= height-cellRadius[0]/2 || headY <= cellRadius[0]/2){
|
||||
speedY*=-1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
float baseX1, baseY1, baseX2, baseY2;
|
||||
float baseLength;
|
||||
float[] xCoords, yCoords;
|
||||
float ellipseX, ellipseY, ellipseRadius = 6;
|
||||
float directionX, directionY;
|
||||
float ellipseSpeed = 3.5;
|
||||
float velocityX, velocityY;
|
||||
|
||||
void setup(){
|
||||
size(640, 240);
|
||||
frameRate(30);
|
||||
fill(128);
|
||||
smooth();
|
||||
baseX1 = 0;
|
||||
baseY1 = height-150;
|
||||
baseX2 = width;
|
||||
baseY2 = height;
|
||||
|
||||
// start ellipse at middle top of screen
|
||||
ellipseX = width/2;
|
||||
|
||||
// calculate initial random direction
|
||||
directionX = random(0.1, 0.99);
|
||||
directionY = random(0.1, 0.99);
|
||||
|
||||
// normalize direction vector
|
||||
float directionVectLength = sqrt(directionX*directionX +
|
||||
directionY*directionY);
|
||||
directionX /= directionVectLength;
|
||||
directionY /= directionVectLength;
|
||||
}
|
||||
|
||||
void draw(){
|
||||
// draw background
|
||||
fill(0, 12);
|
||||
noStroke();
|
||||
rect(0, 0, width, height);
|
||||
|
||||
// calculate length of base top
|
||||
baseLength = dist(baseX1, baseY1, baseX2, baseY2);
|
||||
xCoords = new float[ceil(baseLength)];
|
||||
yCoords = new float[ceil(baseLength)];
|
||||
|
||||
// fill base top coordinate array
|
||||
for (int i=0; i<xCoords.length; i++){
|
||||
xCoords[i] = baseX1 + ((baseX2-baseX1)/baseLength)*i;
|
||||
yCoords[i] = baseY1 + ((baseY2-baseY1)/baseLength)*i;
|
||||
}
|
||||
|
||||
// draw base
|
||||
fill(200);
|
||||
quad(baseX1, baseY1, baseX2, baseY2, baseX2, height, 0, height);
|
||||
|
||||
// calculate base top normal
|
||||
float baseDeltaX = (baseX2-baseX1)/baseLength;
|
||||
float baseDeltaY = (baseY2-baseY1)/baseLength;
|
||||
float normalX = -baseDeltaY;
|
||||
float normalY = baseDeltaX;
|
||||
|
||||
// draw ellipse
|
||||
noStroke();
|
||||
fill(255);
|
||||
ellipse(ellipseX, ellipseY, ellipseRadius*2, ellipseRadius*2);
|
||||
|
||||
// calculate ellipse velocity
|
||||
velocityX = directionX * ellipseSpeed;
|
||||
velocityY = directionY * ellipseSpeed;
|
||||
|
||||
// move elipse
|
||||
ellipseX += velocityX;
|
||||
ellipseY += velocityY;
|
||||
|
||||
// normalized incidence vector
|
||||
float incidenceVectorX = -directionX;
|
||||
float incidenceVectorY = -directionY;
|
||||
|
||||
// detect and handle collision
|
||||
for (int i=0; i<xCoords.length; i++){
|
||||
// check distance between ellipse and base top coordinates
|
||||
if (dist(ellipseX, ellipseY, xCoords[i], yCoords[i]) < ellipseRadius){
|
||||
|
||||
// calculate dot product of incident vector and base top normal
|
||||
float dot = incidenceVectorX*normalX + incidenceVectorY*normalY;
|
||||
|
||||
// calculate reflection vector
|
||||
float reflectionVectorX = 2*normalX*dot - incidenceVectorX;
|
||||
float reflectionVectorY = 2*normalY*dot - incidenceVectorY;
|
||||
|
||||
// assign reflection vector to direction vector
|
||||
directionX = reflectionVectorX;
|
||||
directionY = reflectionVectorY;
|
||||
|
||||
// draw base top normal at collision point
|
||||
stroke(255, 128, 0);
|
||||
line(ellipseX, ellipseY, ellipseX-normalX*100,
|
||||
ellipseY-normalY*100);
|
||||
}
|
||||
}
|
||||
|
||||
// detect boundary collision
|
||||
// right
|
||||
if (ellipseX > width-ellipseRadius){
|
||||
ellipseX = width-ellipseRadius;
|
||||
directionX *= -1;
|
||||
}
|
||||
// left
|
||||
if (ellipseX < ellipseRadius){
|
||||
ellipseX = ellipseRadius;
|
||||
directionX *= -1;
|
||||
}
|
||||
// top
|
||||
if (ellipseY < ellipseRadius){
|
||||
ellipseY = ellipseRadius;
|
||||
directionY *= -1;
|
||||
// randomize base top
|
||||
baseY1 = random(height-100, height);
|
||||
baseY2 = random(height-100, height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class Orb{
|
||||
float x, y, r;
|
||||
|
||||
// Default constructor
|
||||
Orb() {
|
||||
}
|
||||
|
||||
Orb(float x, float y, float r) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 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 velocity;
|
||||
float gravity = .05, damping = 0.8;
|
||||
int segments = 40;
|
||||
Ground[] ground = new Ground[segments];
|
||||
float[] peakHeights = new float[segments+1];
|
||||
|
||||
void setup(){
|
||||
size(640, 200);
|
||||
smooth();
|
||||
orb = new Orb(50, 50, 3);
|
||||
velocity = new PVector(.5, 0);
|
||||
|
||||
// Calculate ground peak heights
|
||||
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 orb
|
||||
orb.x += velocity.x;
|
||||
velocity.y += gravity;
|
||||
orb.y += velocity.y;
|
||||
|
||||
// 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);
|
||||
|
||||
// Draw orb
|
||||
noStroke();
|
||||
fill(200);
|
||||
ellipse(orb.x, orb.y, orb.r*2, orb.r*2);
|
||||
|
||||
// Collision detection
|
||||
checkWallCollision();
|
||||
for (int i=0; i<segments; i++){
|
||||
checkGroundCollision(ground[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void checkWallCollision(){
|
||||
if (orb.x > width-orb.r){
|
||||
orb.x = width-orb.r;
|
||||
velocity.x *= -1;
|
||||
velocity.x *= damping;
|
||||
}
|
||||
else if (orb.x < orb.r){
|
||||
orb.x = orb.r;
|
||||
velocity.x *= -1;
|
||||
velocity.x *= damping;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void checkGroundCollision(Ground groundSegment) {
|
||||
|
||||
// Get difference between orb and ground
|
||||
float deltaX = orb.x - groundSegment.x;
|
||||
float deltaY = orb.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 > -orb.r &&
|
||||
orb.x > groundSegment.x1 &&
|
||||
orb.x < groundSegment.x2 ){
|
||||
// keep orb from going into ground
|
||||
groundYTemp = -orb.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;
|
||||
orb.x = groundSegment.x + deltaX;
|
||||
orb.y = groundSegment.y + deltaY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user