Skip to content

Instantly share code, notes, and snippets.

@makoConstruct
Last active August 12, 2019 07:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save makoConstruct/e69f5fb05c33e311175ef576d22accf5 to your computer and use it in GitHub Desktop.
Save makoConstruct/e69f5fb05c33e311175ef576d22accf5 to your computer and use it in GitHub Desktop.
accelerate towards a target and stop perfectly once arrived, with maximum speed
float movementWhileAccelerating(float subdelta, float velocity, float acceleration){
return subdelta*(velocity + subdelta*acceleration/2);
}
void updateApproacher(float delta, float target, float& position, float& velocity, float maxSpeed, float acceleration, float deceleration){
if(position == target && velocity == 0){
return;
}
float dif = target - position;
float absdist = abs(dif);
float sign = fsign(dif);
float av = velocity*sign; //against dist, not with it
auto moveWhileAccelerating = [&](float subdelta, float acceleration){
subdelta = clamp(0, delta, subdelta);
absdist -= movementWhileAccelerating(subdelta, av, acceleration); //av is against dist, it decreases dist rather than increasing pos. We then normalise that out later.
av += acceleration*subdelta;
delta -= subdelta;
};
auto moveWithoutMaxSpeed = [&](){
float ta;
{
float i = av;
float a = acceleration;
float d = deceleration;
float o = absdist;
// ta = (-i + sqrt(i*i - a*(i*i - 2*o/d)/(d + a)))/a;
// ta = (sqrt(i*i/(2*a) - (i*i/2 - o/d)/(d + a)) - i/sqrt(2*a))/sqrt(a/2);
ta = (sqrt((2*o + i*i/a)/(1/a + 1/d)) - i)/a;
}
moveWhileAccelerating(ta, acceleration); if(delta==0){return;}
moveWhileAccelerating(delta, -deceleration); if(delta==0){return;}
// float nd = absdist - movementWhileAccelerating(delta, av, acceleration);
// if(distanceToSlowDown(av + delta*acceleration, deceleration) > nd){
// //don't accelerate, but probably decelerate
// float ta = absdist/av - av/(2*deceleration);
// moveWhileAccelerating(ta, 0); if(delta==0){return;}
// moveWhileAccelerating(delta, -deceleration); if(delta==0){return;}
// }else{
// //just accelerate
// moveWhileAccelerating(delta, acceleration); if(delta==0){return;}
// }
};
//if going in the wrong direction, reduce the velocity until zero
if(av < 0){
moveWhileAccelerating(abs(av)/deceleration, deceleration); if(delta==0){goto timeExpended;}
}
if(distanceToSlowDown(av, deceleration) >= absdist){
moveWhileAccelerating(abs(av)/deceleration, -deceleration); if(delta==0){goto timeExpended;}
}else{
if(maxSpeed == INFINITY){
moveWithoutMaxSpeed();
}else{
float ma = (maxSpeed - av)/acceleration;
float md = maxSpeed/deceleration;
float go = ma*(av + ma*acceleration/2) + md*md*deceleration/2;
if(go >= absdist){ //then it doesn't hit maxSpeed
moveWithoutMaxSpeed();
}else{
//move with respect to maxSpeed
float ta = (maxSpeed - av)/acceleration;
float tm = (absdist - go)/maxSpeed;
float td = maxSpeed/deceleration;
moveWhileAccelerating(ta, acceleration); if(delta==0){goto timeExpended;}
moveWhileAccelerating(tm, 0); if(delta==0){goto timeExpended;}
moveWhileAccelerating(td, -deceleration);
}
}
}
timeExpended:
//see if it's near enough to kludge it home
if(absdist < abs(velocity)/1000 && av < abs(velocity)/1000){
position = target;
velocity = 0;
}else{
//write back
position = position + dif - sign*absdist;
velocity = sign*av;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment