Last active
August 12, 2019 07:55
-
-
Save makoConstruct/e69f5fb05c33e311175ef576d22accf5 to your computer and use it in GitHub Desktop.
accelerate towards a target and stop perfectly once arrived, with maximum speed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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