How to make an object smoothly transition to a new location?

Hello I am trying to make a program in which an ellipse is redrawn at any point in the canvas where the mouse is clicked, although I am stuck on one problem. I am trying to get the ellipse to move smoothly from point A (the ellipses old position) to point B ( new ellipse location where mouse is clicked)

I have gotten far enough that I can update the ellipses X and Y origin, and the ellipse updates to the new position in an instance, but I can’t make it animate to it’s new location.

Thanks for your help, here is my code for this program so far:

int ballX = 250; 
int ballY = 250; 
int ballDi = 50;

void setup()
{
  size(500,500);
}

void draw()
{
  background(0);
  moveball();
  drawball();
}
  
  void mouseClicked()
  {
   ballX = mouseX;
   ballY = mouseY;
  }
  
  void moveball()
  {
  }
  
  void drawball()
  {
    ellipse(ballX,ballY,ballDi,ballDi);
  }
1 Like

The simplest way is to make an linear interpolation between your target position and your actual position using lerp(). Take a look : https://processing.org/reference/lerp_.html

So you can do the basic trick with a fixed coefficient but the transition still be rough

float ballX = 250;
float ballY = 250;
float ballDi = 50;
float targetX,targetY;
void setup()
{
size(500,500);
}

void draw()
{
background(0);
moveball();
drawball();
}

void mouseClicked()
{

targetX = mouseX;
targetY = mouseY;
}

void moveball()
{
  ballX = lerp (ballX, targetX, 0.1);
  ballY = lerp (ballY, targetY, 0.1);
}

void drawball()
{
ellipse(ballX,ballY,ballDi,ballDi);
}

But if you want to have a smoother moving, with a sort of easing effect, you have to add a coef wich change during the interpolation :


void draw()
{
background(0);
if ( targetX != ballX) i ++ ;
else i = 0 ; //reset the value if target is reached
moveball();
drawball();
}

With this way, I increment i while the circle isn’t on target position.
Then I map this value between 0 and 1, or others values that are between 0 and 1 (because lerp need a coefficient between 0 and 1).

  float coef = map(i,0,100,0,0.7); //100 is a abrbitrary value, but it seems near the good value to have a great easing
  ballX = lerp (ballX, targetX, coef);
  ballY = lerp (ballY, targetY, coef);

So, because my value coef change, the speed of the circle also.

Entire code below if you need it :

float ballX = 250;
float ballY = 250;
float ballDi = 50;
float targetX,targetY;
int i = 0;

void setup()
{
size(500,500);
}

void draw()
{
background(0);
if ( targetX != ballX) i ++ ;
else i = 0 ;
moveball();
drawball();
}

void mouseClicked()
{

targetX = mouseX;
targetY = mouseY;
}

void moveball()
{
  float coef = map(i,0,100,0,0.7);
  ballX = lerp (ballX, targetX, coef);
  ballY = lerp (ballY, targetY, coef);
}

void drawball()
{
ellipse(ballX,ballY,ballDi,ballDi);
}
4 Likes

i made a NoGame using PVector
try it and see how the movement looks
( for me it look very natural, i trained air- / gun / pistol when i was young )

// https://discourse.processing.org/t/bug-with-arraylist/5949
// 11/2018 kll  / my first game ever, good its not really a game
// make a arraylist of pvector points
// calc shortest distance to the next target, aim, fire + remove the point from array

int idt, pmax = 10;
ArrayList<PVector> points = new ArrayList<PVector>();     // list of points
PVector target = new PVector(0, 0);                       // position of cross line
boolean theend = false, shoot = false;

int k = 0, kmax = 30;  //firing circles
float tdist, newdist, speedf = 0.04;   // speed factor multiplied with distance gives realistic targeting movement

void setup() {
 size( 300, 300);
 for (int i = 0; i < pmax; i++) points.add(new PVector(random(-width/2, width/2), random(-height/2, height/2)));
 //for ( PVector p : points ) println(p);
 println("targets: "+points.size());
}

void draw_lines() {
 stroke(200, 0, 0);
 line(target.x, -height/2, target.x, height/2); 
 line(-width/2, target.y, width/2, target.y);
}

void draw_points() {
 for (int i = 0; i < points.size(); i++) { 
   if ( i == idt ) stroke(200, 0, 0);  
   else noStroke();
   fill(0, 200, 0);
   ellipse(points.get(i).x, points.get(i).y, 8, 8);
 }
}

int get_nearest() {
 int idx = -1;                               // init to not found
 tdist = width;                              // init to max
 for (int i = 0; i < points.size(); i++) {
   newdist = dist(points.get(i).x, points.get(i).y, target.x, target.y);
   if ( newdist < tdist ) { 
     tdist = newdist; 
     idx = i;
   }
 }
 return idx;                                 // give index of nearest target
}

void aim() {
 if ( idt > -1 ) {
   PVector waytotarget = points.get(idt).copy();
   waytotarget.sub(target);
   if ( waytotarget.mag() > 0.5 ) {                     // thats close enough
     waytotarget.setMag(waytotarget.mag()*speedf);      // calc faster to short step in that direction
     target = target.add(waytotarget);                  // change target
   } else { 
     if ( !shoot ) println("shoot at "+idt);            // only print 
     shoot = true;
     points.remove(idt);
   }
 } else { 
   println("i win, but now i am alone!"); 
   theend = true;
 }
}

void fire() {                                   // only if shoot = true
 fill(200, 100, 0);
 stroke(255, 0, 0); 
 strokeWeight(3);
 ellipse(target.x, target.y, 2*k, 2*k);        // growing red circle
 strokeWeight(1);
 k++;
 if ( k >= kmax ) {  
   shoot = false; 
   k = 0;
 }
}

void show_end() {
 fill(0, 200, 0);
 rect(-50, -25, 100, 40);
 fill(200, 0, 0);
 text(" I WIN ! ", -20, 0);                    // well, what a wonder if you play alone and targets not move
}

void draw() {
 background(200, 200, 0);
 translate(width/2, height/2);
 if ( !theend ) {
   draw_lines();                               // cross lines
   draw_points();                              // all points fix pos, same size / red stroke for next target
   idt = get_nearest();                        // next ( nearest ) target
   if ( !shoot )      aim();                   // not walk while firing
   else               fire();                  // some show / red circles
 } else show_end();                            // all over, no play again button
}

and a other example for “easing”

2 Likes

Awesome! Thanks for the help!