Non-orthogonal Collision with Multiple Ground Segments

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
  fill(0, 15);
  rect(0, 0, width, height);
  // Move and display the orb
  // Check walls

  // Check against all the ground segments
  for (int i=0; i<segments; i++){

  // Draw ground
  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);


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

  void display() {
    // Draw orb
    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;

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));

Functions Used


Draws an ellipse (oval) to the screen

Learn More

Sets the color used to fill shapes

Learn More

Defines the dimension of the display window width and height in units of pixels

Learn More

Draws a rectangle to the screen

Learn More

Calculates the cosine of an angle

Learn More

Generates random numbers

Learn More

All shapes are constructed by connecting a series of vertices

Learn More

Calculates the sine of an angle

Learn More

Using the beginShape() and endShape() functions allow creating more complex forms

Learn More

The setup() function is run once, when the program starts

Learn More

Called directly after setup(), the draw() function continuously executes the lines of code contained inside its block until the program is stopped or noLoop() is called

Learn More

The endShape() function is the companion to beginShape() and may only be called after beginShape()

Learn More

Calculates the angle (in radians) from a specified point to the coordinate origin as measured from the positive x-axis

Learn More

Disables drawing the stroke (outline)

Learn More

A class to describe a two or three dimensional vector, specifically a Euclidean (also known as geometric) vector

Learn More

Calculates the distance between two points

Learn More