Simple example of 3d movement following a point?

with improved version now below!!!

Another approach, where the camera is on a circle around the player, with an easing when changing the angle of the camera on that circle.

Also, there is an easing on lookAt now also.

Chrisir

// new version with lookAtPVectorFollowCircle()

// 3D sketch: shows a ball that moves in the x/z plane (height = y = 500) and is followed by a camera.
// The goal of the sketch is to demonstrate the usage of a following camera.  

// cubes 
float angleCubes=45; // angle for the cubes in the scene

CameraClass cam; 

PVector ballPos = new PVector (300, 500, 300);
PVector ballPosPrev =  new PVector (300, 500-10, 310);
PVector ballVel = new PVector (
  random(1, 2), 
  0, 
  random(-2, -1));

final int heightAbovePlayer = 63; 

float angle1 = 0; // angle  
float angle2 = 0;

// when the ball is not running, we have a slight up and down movement of the camera 
boolean ballIsStopped=false; // flag tells whether the ball is stopped or not 
float angleHeight=0;   // angle for the slight up and down movement of the camera

// -----------------------------------------------------

void setup() {
  size (1400, 800, P3D);

  cam = new CameraClass ();

  cam.camPos = ballPos.copy();
  cam.camPos.x += 113;
  cam.camPos.y -= heightAbovePlayer;
  cam.camPos.z += 113;
} // func 

void draw() {
  // clear canvas 
  background(111);

  // avoid clipping : https : // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);

  // apply lights 
  lights();

  // camera follows ball
  if (! (keyPressed&&key==' ')) {
    //cam.lookAtPVectorFollow(ballPos);
    cam.lookAtPVectorFollowCircle(ballPos);
  }

  // apply the values of the class to the real camera
  cam.set();

  // move ball and draw it  
  ballPosPrev = ballPos.copy();
  if (! (keyPressed&&key=='m')) {
    ballPos.add(ballVel);
  }
  if (ballPosPrev.dist(ballPos)==0) {
    if (!ballIsStopped)
      angleHeight=0;
    ballIsStopped=true;
  } else {
    ballIsStopped=false;
  }
  angle1 = PI + atan2(ballPos.z - ballPosPrev.z, ballPos.x - ballPosPrev.x );

  fill(0, 255, 0); // green 
  noStroke();
  mySphere(ballPos.x, ballPos.y, ballPos.z, 10);

  // contain ball in a invisible box 
  contain(ballPos, ballVel);

  // make the scene with the boxes 
  scene();

  // text upper left corner
  fill(0, 255, 0); 
  cam.HUD_text("The green ball is contained in an "
    +"red field."
    +"\nHold space bar to stop camera."
    +"\nHold 'm' to stop the Movement of the ball.");
  // println(angle1+", "+angle2);
  //
} // func 

// ---------------------------------------------------

void scene () {

  // Drawing of the red field   

  fill(255, 2, 2);//RED
  noStroke(); 
  mySphere(500, 500, 500, 20);
  mySphere(100, 500, 100, 20);
  mySphere(100, 500, 500, 20);
  mySphere(500, 500, 100, 20);
  //
  // rect 
  stroke(255, 2, 2);//RED
  line(500, 500, 500, 500, 500, 100);//up
  line(500, 500, 100, 100, 500, 100); //left
  line(100, 500, 100, 100, 500, 500 ); // down 
  line(100, 500, 500, 500, 500, 500 ); // down

  stroke(0);
  float z ; 

  // one wall of boxes
  for (int x = 10; x < 600; x+= 100)
  {
    fill(x/3, 2, 2);
    for (int y = 10; y < 600; y+= 100)
    {
      z = -600;
      myBox(x, y, z, 24);
      // println ( "Box: " + x + ", "+y+ " "+z);
    }
    fill(0, 0, 254);
    z=-800;
    myBox(x, 10, z, 24);
  }
  // 
  // a few additional boxes
  fill(0, 0, 254);
  z=-400;
  myBox(220, 10, z, 24);
  myBox(600, 10, z, 24);
  z=-400;
  myBox(220, 510, z, 24);
  myBox(600, 510, z, 24);
  z=399;
  myBox(220, 510, z, 24);
  myBox(600, 510, z, 24);
  z=900;
  myBox(220, 510, z, 24);
  myBox(600, 510, z, 24);
  angleCubes++;
  //
}

void myBox(float x, float y, float z, 
  float size1) {
  // one nice wrapper for build in box-command
  pushMatrix();
  translate(x, y, z);
  rotateY(radians(angleCubes));
  rotateX(radians(45));
  box(size1);
  popMatrix();
}

void mySphere(float x, float y, float z, 
  float size1) {
  // one nice wrapper for build in sphere-command
  pushMatrix();
  translate(x, y, z);
  sphere(size1);
  popMatrix();
}

void contain(PVector ballPos, PVector ballVel) {
  // contain ball

  if (ballPos.x>500) {
    ballVel.x=abs(ballVel.x)*-1;
    println("---");
  }
  if (ballPos.z>500) { 
    ballVel.z=abs(ballVel.z)*-1;
    println("---");
  }

  if (ballPos.x<100) {
    ballVel.x=abs(ballVel.x);
    println("---");
  }
  if (ballPos.z<100) {
    ballVel.z=abs(ballVel.z);
    println("---");
  }
}

// ===============================================================

class CameraClass {

  // capsules the normal camera() command and its vectors 

  PVector camPos;     // its vectors 
  PVector camLookAt;
  PVector camUp;

  PVector camPosInitial;     // its vectors - the default (unchanged) 
  PVector camLookAtInitial;
  PVector camUpInitial; 

  // for follow
  PVector camWhereItShouldBe = new PVector(0, 0, 0);
  PVector camAdd = new PVector(0, -60, 0);
  float easing = .019; // .07; // how fast it changes

  float camCurrentAngle=0;// -90;   // for cam rotation around itself (around Y-axis)
  float camRadius;             // same situation 

  boolean firstTime=true; 

  // constructor without parameters
  CameraClass() {
    // constr
    // set vectors 
    camPos    = new PVector(width/2.0, height/2.0, 990);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.get();
    camLookAtInitial = camLookAt.get();
    camUpInitial     = camUp.get();
  }  // constr

  // ----------------------------------------

  void set() {
    // apply vectors to actual camera
    camera (camPos.x, camPos.y, camPos.z, 
      camLookAt.x, camLookAt.y, camLookAt.z, 
      camUp.x, camUp.y, camUp.z);
  }

  // ---

  void setLookAt (float x1, float y1, float z1) {
    camLookAt = new PVector(x1, y1, z1);
  }

  // ---

  void lookAtPVectorFollowOnlyLookAt(PVector followMe) {
    // Two versions of this. Without easing. 
    // Follows a player (e.g.),
    // change only look at.
    camLookAt = followMe.get();
  }

  void lookAtPVectorFollowOnlyLookAtWithEasing(PVector followMe) {
    // Version  with easing.
    // Follows a player (e.g.),
    // change only look at.
    float easing = 0.0398; 
    camLookAt.x += (followMe.x-camLookAt.x) * easing;   // followMe.get();
    //camLookAt.y += (followMe.y-camLookAt.y) * easing;
    camLookAt.y  =  followMe.y; // other principle 
    camLookAt.z += (followMe.z-camLookAt.z) * easing;
  }

  // ---

  void lookAtPVectorFollowCircle(PVector followMe) {
    // Two versions of this. 
    // One version of doing it.
    // The camera moves on a circle around the player. 

    float RadiusCam=170.0;  // dist camera from the player (radius of the cam around the player) 

    if (firstTime) {
      lookAtPVectorFollowOnlyLookAt(followMe);
      firstTime=false;
    } else {
      lookAtPVectorFollowOnlyLookAtWithEasing(followMe);
    }

    float easing = 0.0198; 
    angle2 += (angle1-angle2) * easing;

    // the camera is around the avatar/player  
    // in a distance RadiusCam from the avatar/player 
    camPos.x = followMe.x + RadiusCam*cos(angle2);

    // other principles for y, no circle calculation 
    if (ballIsStopped)
      camPos.y  = (followMe.y - heightAbovePlayer) + (sin(angleHeight) * heightAbovePlayer/2); // slight movement of the cam up and down 
    else
      camPos.y = followMe.y - heightAbovePlayer;  // other principle for y, no circle calculation 

    camPos.z = followMe.z + RadiusCam*sin(angle2);

    angleHeight+=.021;
  } //  

  void lookAtPVectorFollow (PVector followMe) {

    // second version of doing it 
    // camera is trying to get to player position, but with easing. 

    // follows a ball / player (e.g.),
    // complete following (lookAt and camPos).

    // manage Look At 
    camLookAt =  followMe.get();

    // manage position of the camera
    float easing = 0.0198; 
    // x
    camPos.x    += (followMe.x-camPos.x) * easing;

    // y
    // camPos.y    += (followMe.y-camPos.y) * easing -20;
    camPos.y    = followMe.y - heightAbovePlayer; // other principle for y ! 

    // z
    camPos.z    += (followMe.z-camPos.z) * easing;
  }

  // ---

  void printData() {
    println ( "Cam at " + camPos 
      + " looking at " + camLookAt 
      + " (angle = "
      +camCurrentAngle
      +").");
  }

  void HUD_text (String a1) {
    // HUD text upper left corner 
    // this must be called at the very end of draw()

    // this is a 2D HUD 
    camera();
    hint(DISABLE_DEPTH_TEST);
    noLights();
    // ------------------
    textSize(16);
    text (a1, 20, 20);
    // ------------------
    // reset all parameters to defaults
    textAlign(LEFT, BASELINE);
    rectMode(CORNER);
    textSize(32);
    hint(ENABLE_DEPTH_TEST); // no HUD anymore
    lights();
  } // method
  //
} // class
// ======================================

improved version



//
// new version with lookAtPVectorFollowCircle().

// 3D sketch: shows a ball that moves in the x/z plane (height = y = GENERAL_Y_HEIGHT = 500) and is followed by a camera.
// The goal of the sketch is to demonstrate the usage of a **following** camera.
// The camera moves on a circle (in x/z plane) around the ball/Player. 
// The camera Y is located HEIGHT_ABOVE_PLAYER = 63 above the ball/Player.

// How is the angle of the cam on the circle around the player calculated?

// ball.atan2FromBall() is an important function here that returns the angle between the ball and its previous position; 
// this angle makes a line from current ball pos to the previous ball pos. When you prolongue the line 
// you come to the x,z pos of the camera (y pos of the ball is "above" than the ball).

// The angle is used to place the cam on a circle with a fixed radius around the player/ball. The angle is changed with an
// constrained easing to make the cam movement smooth. 
// So the cam rotates around the ball and follows the ball.

// The cam lookAt is towards the ball but also with a 2nd easing. 

// When the ball stops, the cam slightly moves up and down (during waiting). 

// Search "debug" and "println" to find vars etc. to delete when debugging is over. 
// https://discourse.processing.org/t/simple-example-of-3d-movement-following-a-point/12361/21


// CONSTANTS: the floor / field (y value)
final int GENERAL_Y_HEIGHT = 500; 

// Classes: The camera 
CameraClass cam; 

// The ball 
Ball ball = new Ball(); 

// The scene (background, field, boxes...) 
Scene scene = new Scene(); 

// tools 
Tools tools = new Tools(); 

// angle stuff 
float angle2 = 0;   // actually used to calc cam pos 
float angleToWorkWith; // that's used to calc the delta 

// -----------------------------------------------------

void setup() {
  size (1400, 800, P3D);

  // setup camera 
  cam = new CameraClass ();
  cam.camPos = ball.ballPos.copy();
  cam.camPos.x += 113;
  cam.camPos.y -= cam.HEIGHT_ABOVE_PLAYER;
  cam.camPos.z += 113;
} // func 

void draw() {
  // set Canvas and Environment
  scene.setCanvasAndEnvironment(); 

  // camera follows ball (when Space Bar is not pressed)
  cam.lookAtPVectorFollowCircle(ball.ballPos);   // old Version: cam.lookAtPVectorFollow(ballPos);
  cam.set(); // apply the values of the class cam to the real camera

  // move ball (when m is not pressed)
  ball.move();      // move ball
  ball.checkStop(); // when the balls is stopped some adjustements are made 

  // manage angles 
  manageAngles(); 

  // ball display and constrain 
  ball.script();

  // display the scene with the boxes and HUD text 
  scene.displayScene();
  //
} // func draw

// ---------------------------------------------------

void manageAngles() {
  // manage Angles

  // calc the angle from the line between the ball pos and tha balls previous position
  float angle1 = PI + ball.atan2FromBall();    // gets atan2FromBall + PI 

  angle1 = tools.fixAngle(angle1);

  angleToWorkWith=angle1; 

  if ( (angle1-angle2) > PI ) {
    angleToWorkWith=angle1-TWO_PI;
    //println("Here 13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++###");
  }//if

  if ( (angle2-angle1) > PI ) {
    angleToWorkWith=angle1+TWO_PI;
    //println("Here 14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++###");
  }//if

  // debug   
  //println(degrees(angle1)
  //  +", "
  //  +degrees(angle2));
  //
}//func 

// =================================================================
// classes 

class Scene {

  // cubes 
  float angleCubes=45; // angle for the cubes in the scene

  void setCanvasAndEnvironment() {
    // set Canvas and Environment

    // clear canvas 
    background(111);

    // avoid clipping : https : // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
    perspective(PI/3.0, (float) width/height, 1, 1000000);

    // apply lights 
    lights();
  }

  void displayScene() {

    // Drawing of the scene / decoration  

    // Drawing of the red field  ---- 
    fill(255, 2, 2);//RED
    noStroke(); 
    tools.mySphere(500, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 100, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(500, GENERAL_Y_HEIGHT, 100, 20);

    // rect of lines  
    stroke(255, 2, 2);//RED
    // using 3D lines: 
    line(500, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 100);  // up |
    line(500, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 100);  // left <-
    line(100, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 500 ); // down |
    line(100, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 500 ); // right ->

    // one small wall of boxes
    stroke(0);
    int z = -60; 
    for (int x = 10; x < 600; x+= 100) {
      fill(x/3, 2, 2);
      for (int y = 410; y < 600; y+= 100) {
        tools.myBox(x, y, z, 24, angleCubes);
      }
    }

    // a few additional blue boxes
    fill(0, 0, 255);
    z=-400;
    tools.myBox(220, 10, z, 24, angleCubes);
    tools.myBox(600, 10, z, 24, angleCubes);
    z=-400;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    z=399;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    z=900;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    angleCubes++;
    //

    // text upper left corner (HUD)
    fill(0, 255, 0); 
    cam.HUD_text("The green ball is contained in a red field."
      +"\nHold Space Bar to stop the camera."
      +"\nHold 'm' to stop the ball.\n" );  // Hold Space Bar and m has debug purpose
  }
  //
} // class 

// =================================================================

class CameraClass {

  // capsules the normal camera() command and its vectors 

  PVector camPos;     // its vectors 
  PVector camLookAt;
  PVector camUp;

  PVector camPosInitial;     // its vectors - the default (unchanged) 
  PVector camLookAtInitial;
  PVector camUpInitial; 

  // for follow
  PVector camWhereItShouldBe = new PVector(0, 0, 0);
  PVector camAdd = new PVector(0, -60, 0);
  float easing = .019; // .07; // how fast it changes

  float camCurrentAngle=0;// -90;   // for cam rotation around itself (around Y-axis)
  float camRadius;             // same situation

  // how high is the cam above the player / ball 
  final int HEIGHT_ABOVE_PLAYER = 63; 

  boolean firstTime=true; 

  float angleForCamerasUpAndDownMovement=0;   // angle for the slight up and down movement of the camera

  // constructor without parameters
  CameraClass() {
    // constr
    // set vectors 
    camPos    = new PVector(width/2.0, height/2.0, 990);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();
  }  // constr

  // ----------------------------------------

  void set() {
    // apply internal class vectors to actual camera
    camera (camPos.x, camPos.y, camPos.z, 
      camLookAt.x, camLookAt.y, camLookAt.z, 
      camUp.x, camUp.y, camUp.z);
  }

  // ---

  void setLookAt (float x1, float y1, float z1) {
    camLookAt = new PVector(x1, y1, z1);
  }

  // ---

  void lookAtPVectorFollowOnlyLookAt(PVector followMe) {
    // Two versions of this. Without easing. 
    // Follows a player (e.g.),
    // change only look at.
    camLookAt = followMe.copy();
  }

  void lookAtPVectorFollowOnlyLookAtWithEasing(PVector followMe) {
    // Version  with easing.
    // Follows a player (e.g.),
    // change only look at.
    float easing = 0.0398; 
    camLookAt.x += (followMe.x-camLookAt.x) * easing;   // followMe.copy();
    //camLookAt.y += (followMe.y-camLookAt.y) * easing;
    camLookAt.y  =  followMe.y; // other principle 
    camLookAt.z += (followMe.z-camLookAt.z) * easing;
  }

  // ---

  void lookAtPVectorFollowCircle(PVector followMe) {
    // Two versions of this. 
    // One version of doing it:
    // The camera moves on a circle around the player (fixed radius = RadiusCam).

    // space key leaves the function (camera stands still)
    if ((keyPressed&&key==' ')) {    // debug purpose 
      return;
    }//if ---------

    float RadiusCam=170.0;  // dist camera from the player (radius of the cam around the player) 

    if (firstTime) {
      lookAtPVectorFollowOnlyLookAt(followMe);
      firstTime=false;
    } else {
      lookAtPVectorFollowOnlyLookAtWithEasing(followMe);
    }

    // calc delta with easing (the classic easing formula is stretched over a few lines here)
    float easing = 0.0198; 
    float delta = (angleToWorkWith-angle2) * easing;

    // constrain delta:
    delta=constrain(delta, -0.04, 0.04);  

    // add delta 
    angle2 += delta; 

    angle2 = tools.fixAngle(angle2); 

    // the camera is around the avatar/player  
    // in a distance RadiusCam from the avatar/player 
    camPos.x = followMe.x + RadiusCam*cos(angle2);

    // other principles for y, no circle calculation 
    if (ball.ballIsStopped)
      camPos.y  = (followMe.y - HEIGHT_ABOVE_PLAYER) + (sin(angleForCamerasUpAndDownMovement) * HEIGHT_ABOVE_PLAYER/2); // slight movement of the cam up and down 
    else
      camPos.y = followMe.y - HEIGHT_ABOVE_PLAYER;  // other principle for y, no circle calculation 

    camPos.z = followMe.z + RadiusCam*sin(angle2);

    angleForCamerasUpAndDownMovement+=.021;
  } //  

  void lookAtPVectorFollow (PVector followMe) {

    // second version of doing it 
    // camera is trying to get to player position, but with easing. 

    // follows a ball / player (e.g.),
    // complete following (lookAt and camPos).

    // manage Look At 
    camLookAt =  followMe.copy();

    // manage position of the camera
    float easing = 0.0198; 
    // x
    camPos.x    += (followMe.x-camPos.x) * easing;

    // y
    // camPos.y    += (followMe.y-camPos.y) * easing -20;
    camPos.y    = followMe.y - HEIGHT_ABOVE_PLAYER; // other principle for y ! 

    // z
    camPos.z    += (followMe.z-camPos.z) * easing;
  }

  // ---

  void printData() {
    println ( "Cam at " + camPos 
      + " looking at " + camLookAt 
      + " (angle = "
      +camCurrentAngle
      +").");
  }

  void HUD_text (String a1) {
    // HUD text upper left corner 
    // this must be called at the very end of draw()

    // this is a 2D HUD 
    camera();
    hint(DISABLE_DEPTH_TEST);
    noLights();
    // ------------------
    textSize(16);
    text (a1, 20, 20);
    // ------------------
    // reset all parameters to defaults
    textAlign(LEFT, BASELINE);
    rectMode(CORNER);
    textSize(32);
    hint(ENABLE_DEPTH_TEST); // no HUD anymore
    lights();
  } // method
  //
} // class

// ======================================

class Ball {

  // position and previous position 
  PVector ballPos = new PVector (300, GENERAL_Y_HEIGHT, 300);
  PVector ballPosPrev =  new PVector (300, GENERAL_Y_HEIGHT-10, 310);

  // ball velocity - see constructor   
  PVector ballVel;

  // when the ball is not running, we have a slight up and down movement of the camera 
  boolean ballIsStopped=false; // flag tells whether the ball is stopped or not 
  boolean keyMhasBallStopped=false; // key M  

  Ball() {
    // constructor  ----

    // ball vel 
    ballVel = new PVector (  
      random(1, 2), 
      0, 
      random(1, 2));

    // give vel another sign in 50 % of the cases  
    if (random(100) > 50) 
      ballVel.x*=-1; 
    if (random(100) > 50) 
      ballVel.z*=-1;
  } // constructor  -----

  void move() {
    ballPosPrev = ballPos.copy(); // store previous ball pos

    // key 'm' leaves the function (ball stands still)
    if (keyPressed&&key=='m') {  // debug 
      keyMhasBallStopped=true;
      return;
    }//if  

    keyMhasBallStopped=false;  
    ballPos.add(ballVel);   // move
  }

  void script() {
    // display ball 
    fill(0, 255, 0); // green 
    noStroke();
    tools.mySphere(ballPos.x, ballPos.y, ballPos.z, 10);

    // contain ball in a field 
    contain(ballPos, ballVel);
  }

  // Tools within the class ----

  boolean isMoving() { 
    // Returns whether the ball is moving. 
    // It's moving when the prev pos is different from the current pos. 
    return 
      ballPosPrev.dist(ballPos) != 0.0;
  }

  void checkStop() {
    if (ball.keyMhasBallStopped && !ball.isMoving()) {
      //  ball is stopped 

      // the first time we detect that the ball has stopped (only the first time) 
      if (!ball.ballIsStopped)
        cam.angleForCamerasUpAndDownMovement=0;     // we reset the angle height  

      ball.ballIsStopped=true; // set flag
    } else {
      ball.ballIsStopped=false;
    }
  }

  float atan2FromBall() {
    // ball.atan2FromBall() is an important function that returns the angle between the ball and its previous position; 
    // this angle makes a line from current ball pos to prev ball pos. When you prolongue the line 
    // you come to the x,z pos of the camera (y pos of the ball is "higher" than the ball).
    // The angle is used to place the cam on a circle with a fixed radius around the player/ball. The angle is changed with an
    // constrained easing to make the cam movement smooth. So the cam rotates around the ball and follows the ball. 

    return
      atan2(ballPos.z - ballPosPrev.z, ballPos.x - ballPosPrev.x );
  }

  void contain(PVector ballPos, PVector ballVel) {  
    // contain ball / bouncing on field borders 

    if (ballPos.x>500) {
      ballVel.x=abs(ballVel.x)*-1;
      println("---"); // 4x println for debug
    }
    if (ballPos.z>500) { 
      ballVel.z=abs(ballVel.z)*-1;
      println("---");
    }

    if (ballPos.x<100) {
      ballVel.x=abs(ballVel.x);
      println("---");
    }
    if (ballPos.z<100) {
      ballVel.z=abs(ballVel.z);
      println("---");
    }
  }//method 
  //
}//class 

// ======================================

class Tools {
  // tools 

  float fixAngle(float angle1) {
    // if > 2xPI 
    if (angle1>TWO_PI) 
      angle1-=TWO_PI; 
    if (angle1>TWO_PI) 
      angle1-=TWO_PI; 

    // if < 0 (negative angles like -40 should be expressed as positive angles like 320)
    if (angle1<0.0) {
      angle1 = TWO_PI + angle1;
      // println("Here 1 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++###");
    }
    if (angle1<0.0) 
      angle1 = TWO_PI + angle1;

    return angle1;
  }

  void myBox(float x, float y, float z, 
    float size1, 
    float angleCube) {
    // one nice wrapper for build in box-command
    pushMatrix();
    translate(x, y, z);
    rotateY(radians(angleCube));
    rotateX(radians(45));
    box(size1);
    popMatrix();
  }

  void mySphere(float x, float y, float z, 
    float size1) {
    // one nice wrapper for build in sphere-command
    pushMatrix();
    translate(x, y, z);
    sphere(size1);
    popMatrix();
  }
}//class 
//
2 Likes