[Edit: with further testing, this doesn't actually seem to work. Either you end up extending the rope when it shouldn't be extended (i.e. when you aren't reeling in) or you still have the "dumping energy in" bug. I'm not quite sure how to fix this..]
So, the pull beam is a fun mechanic, but the physics of it are a little problematic. Even using ODE, which does a lot of the physics for us, there are a couple of tight spots. Namely, reeling in and reeling out can be a pain.
Our pull beam is implemented internally using a set of ODE joints connected to some intermediate bodies. This is all encapsulated in the ODERope class in src/data/Rope.py. The joints are:
j0: a hinge joint that connects the rope to the target body (the body the hook connected with) j1: a slider joint that represents the rope itself j2: a hinge joint that connects the rope to the parent body (the body that fired the hook)
Theoretically, you might get better modelling if you used a long series of joints and bodies, but I prototyped it separately about a year ago and didn't like the way it looked or felt, so I did it this way. This works pretty well for a default rope -- if the bodies move closer together, no problem, the slider joint just slides in. The slider joint needs to get a HiStop parameter to know when to stop extending; we used 10 (0 is the initial position of the slider), so you can move out by about ten pixels from where you first shot the beam before being restrained.
Reeling in the rope conceptually means moving the HiStop parameter so that it constrains "stronger". There are a few issues to be concerned with:
1) If the player is at the end of his rope, so to speak, what happens when the rope is reeled in?
If you move down the HiStop so that the player is beyond it, ODE will "snap" the player back in. This might give the player too much velocity, however. What we do is check if the histop is less than the player's position on the rope; if so, move the player in by however much is being reeled in.
Similarly, if the player is at the end of the rope, and the rope is reeled out, then we push the player out. There's no centripetal force acting to hold the player in orbit on the rope, so this simulates the player being flung out to the rope.
If you've gotten this far, you'll have a pretty good quick-and-dirty rope approximation. But there's still some bugs:
2) If the player is at the beginning of his rope, and reeling in will overlap the player with an object, then what?
If you've lowered the HiStop by too much (and moved the player correspondingly into the object it overlaps), collision detection goes crazy. However, you can detect that this happens by the fact that the slider joint is overextended -- player's position is beyond the HiStop. So, the first step to fix this is to institute a check every frame; if the player is outside the HiStop, readjust the HiStop up. However, by this point, the collision has already dumped too much energy into the system; this might not be so bad, but if the player is stuck to a non-static object, both have just gained a bunch of velocity. Not good.
So the next step is to do this check every "step" (Project Alexandria does 10 physics steps per frame), and if the rope is overextended, stop reeling in immediately (before the next frame). The only problem now is that there are other cases when the player's position is a little above HiStop, namely when they're reeling in but trying to apply force in the opposite direction. So we implemented a tradeoff; check if the rope is overextended two steps in a row before stopping the reeling in. This gives a very cool "stutter" reel in if the player is reeling in while accelerating in the other direction.
Here's a video of that stutter. There's still room for improvement; the end of the video shows me trying to get the reel out to work, and not succeeding. And the reeling in just stops when the player happens to be going too fast in some unfriendly direction. So, back to work, I guess.