Hey Rubeus, of course!
First of all, I have a line class, which simply contains a start and end point. But it also has a bunch of methods that return useful things.
Code:
class Line
{
Line()
{
}
Line(Vec2 p1, Vec2 p2)
{
_p1 = p1;
_p2 = p2;
}
/******************************************************************************/
void Draw()
{
D.line(GREEN, _p1, _p2);
}
/******************************************************************************/
Vec2 GetP1() { return _p1; }
Vec2 GetP2() { return _p2; }
Vec2 GetDir()
{
Vec2 dir = (_p2 - _p1);
dir.normalize();
return dir;
}
flt GetLength () { return (_p2 - _p1).length() ; }
flt GetLength2() { return (_p2 - _p1).length2(); }
// What is the position in screenspace if we have moved 0..1 along the line
Vec2 GetPosForProgress(flt prog) { return Lerp(_p1, _p2, prog); }
// What is the remaining length of the line if we have move 0..1 along the line
flt GetLengthLeftForProgress(flt prog)
{
return (_p2 - GetPosForProgress(prog)).length();
}
/******************************************************************************/
private:
Vec2 _p1, _p2;
}
Now, for my path, I store the points that will connect the lines, and the lines itself. The amount of lines is dependent on the spline resolution. You just need to calculate this once, unless you want to update the path in real-time.
Here is how I calculate and store the lines in between the path nodes:
Code:
void ConstructPath()
{
// Clean up the existing path
FREPA(_pathLines)
{
delete _pathLines[i];
}
_pathLines.clear();
// Only start constructing the path when we have at least 4 points
if(_pathPoints.elms() > 3)
{
int conn = _pathPoints.elms() - 3; // This is the amount of connections we have to calculate
// For every connection
FREPD(start, conn)
{
flt index = 0.0f;
// Calculate all line segments, based on the line resolution
FREP(_lineRes)
{
Vec2 p1 = Lerp4(_pathPoints[start+0], _pathPoints[start+1], _pathPoints[start+2], _pathPoints[start+3], index);
index += 1.0f / _lineRes;
Vec2 p2 = Lerp4(_pathPoints[start+0], _pathPoints[start+1], _pathPoints[start+2], _pathPoints[start+3], index);
_pathLines.add(new Line(p1, p2));
}
}
}
}
Next, we move along the spline. To do this, we set a bool to start moving, and we update a member CurrPos every frame, like so:
Code:
if(_moving)
{
if(_pathLines.elms() > 0)
{
_currPos = FindNextPointOnLineToMove();
_dir = FindDirectionFromLine();
}
}
Direction you can return from the current line segment (_pathLines[_currIndex].GetDir(); ), but finding the position takes some more calculations:
Code:
// For movement, calculate the distance that we want to move in ONE frame.
// Then calculate how much we move along the line segments with this distance.
Vec2 FindNextPointOnLineToMove()
{
flt distance = Time.d() * _speed; // This is how much we want to move in 1 frame
// Keep moving until we run out of distance to move
while(distance > 0)
{
flt lineLengthLeft = _pathLines[_currIndex].GetLengthLeftForProgress(_currLineProgress);
if((distance - lineLengthLeft) > 0)
{
distance -= lineLengthLeft;
_currIndex++;
_currLineProgress = 0;
if(_currIndex >= _pathLines.elms())
{
StopMovingAlongPath();
return _pathLines[_pathLines.elms()-1].GetP2(); // Return end position, stop there
}
}
else
{
flt length = _pathLines[_currIndex].GetLength();
_currLineProgress += distance * (1 / length); // Convert the distance we have left, relative to the line length
break;
}
}
return _pathLines[_currIndex].GetPosForProgress(_currLineProgress);
}
This gives you a completely uniform move speed along the spline, and it will work regardless of which speed you set or how low your FPS is or how smooth or crude your spline is.
I hope that helps!