You're right, you don't need a whole library.
You can try what Allen suggested and it'll probably look ok, but I'd recommend just doing it well to start with. You can do the whole rope simulation in just a few lines of code:
(source in description)
Here's the pieces of source you care about most:
void Solve(real dt)
{
for (u32 i = 0; i < g_verts.size() - 1; ++i)
{
RopeVert& a = g_verts[i];
RopeVert& b = g_verts[i + 1];
Vec2 v = b.position - a.position;
real length = v.Len();
if (length != real(0.0))
{
real error = kMaxDist / length - real(1.0);
Vec2 correction = v * error;
if (i != 0)
{
real invMass = a.invMass + b.invMass;
a.position -= correction * (a.invMass / invMass);
b.position += correction * (b.invMass / invMass);
}
else
{
b.position += correction;
}
}
}
}
void Integrate(real dt)
{
for (u32 i = 1; i < g_verts.size(); ++i)
{
RopeVert& a = g_verts[i];
a.velocity += Vec2(0.0, 9.8) * dt;
a.position += a.velocity * dt;
}
}
void VelocityFixup(real inv_dt)
{
for (u32 i = 1; i < g_verts.size(); ++i)
{
RopeVert& a = g_verts[i];
a.velocity = (a.position - a.oldPosition) * inv_dt;
a.oldPosition = a.position;
}
}
void SolveRope(real dt)
{
Integrate(dt);
for (u32 i = 0; i < 8; ++i)
Solve(dt);
VelocityFixup(real(1.0) / dt);
}
The idea, like Allen was suggesting, is to loop over each piece of the change and shorten/grow it if it's too long/short. You do this a few times in a loop, and you're almost done. The trick to making it look nicer is to keep track of the "velocity" of each particle in the rope, which is just currentPos-prevPos. Then you can use the velocity for integration.
Edit: If the rope looks floaty just raise the gravity constant (and also probably increase iterations to prevent rope from stretching).