This line assumes that yVel
is constant for the entirety of the duration delta
:
this.y += this.yVel * delta;
But that's not true - we know by the end of duration delta
that yVel
has decreased to a fraction of \$0.99^\text{delta}\$ according to this line:
this.yVel *= Math.pow(0.99, delta);
So if we think of yVel
as a function of time, \$v(t) = v_0 \cdot 0.99^t\$, then the total displacement in y
over the course of the interval delta is the integral:
$$\begin{align}
\Delta y &= \int_0^\text{delta}v_0 \cdot 0.99^t dt\\
&= v_0 \cdot \int_0^\text{delta} e^{\ln (0.99) \cdot t} dt\\
&= v_0 \cdot \left( \frac 1 {\ln(0.99)} e^{\ln(0.99) \cdot t}\right)\Bigg|^\text{delta}_0\\
&= \frac {v_0} {\ln(0.99)}\left(e^{\ln(0.99)\cdot \text{delta}} - 1 \right)\\
&=v_0 \cdot \frac {0.99^\text{delta} - 1} {\ln(0.99)}
\end{align}$$
In code:
var frictionFactor = Math.Pow(0.99, delta);
this.y += this.yVel * (frictionFactor - 1)/Math.Log(0.99);
this.yVel *= frictionFactor;
This will be smoother, but can still vary from one run to another due to limited precision and accumulation of rounding errors. So as Shin Dongho mentioned, your best bet here is to fix your physics timestep at a known value, so you get consistent, reproducible results.