** Setting up the basic rope behavior ]**
Alright…let’s look at how to set up the rope to act like a rope. I’ll go through the basic setup of the rope actor all the way to a game-ready (passive) rope, and break down the climb and swing mechanics int he final update.
** Construction Script ]**
I set up a few custom functions that handle the setup based on a few literal variables and other user-set values grabbed from my setup structs.
(1) - Set End Constraints
Very simple setup. I check if I should attach the top of the rope (from details panel) and then either set the “TopAnchor” physics constraint to attach to the first bone, or not.
The variable “is Rope Legal” gets queried by my character to check if grabbing the rope should be allowed - I obviously don’t want to trigger climb or swing when the rope is falling or already on the ground.
The second pin of the sequence is for attaching something to the bottom end of the rope, but I haven’t added that part yet (if I’ll add it at all).
(2) - Setup Skeletal Mesh
Just grab the skeletal mesh variable from the setup struct and set it as the new skeletal mesh on the “Rope Skeletal Mesh Component”.
The component has a default mesh set, so if the user input is empty it won’t overwrite (which would lead to warnings at runtime).
(3) - Setup Skeletal Mesh
Nothing fancy, just grab the “Segment Mass (kg)” value from the setup struct and then loop through each bone of the skeletal mesh and assign that new bone mass.
(4) - Create Rope Spline
As a reminder, I set the skeletal mesh component to “hidden in game” and unchecked “visible”. This spline and the spline mesh created along it is what is seen in game.
I added an array to store my spline points, so first I clear that array in the construction script to be on the safe side.
I add a new spline component, store it for later reference and clear all points - I don’t want default points or their location because I want to rebuild it from scratch.
Then I get how many bones my skeletal mesh component has, and loop through to add one spline point at each bone.
Each point created gets added to my spline point array.
At the end, I store the length of the spline “at rest”. There can still be some stretch at runtime, so I want to know how long the rope is without physics acting on it.
I’m using “location at distance along spline” to match my player character to the rope, and when the rope is stretching that loses precision. To compensate, I have a function that compares default length to current length and for that I obviously need to know the default length…
(4) - Create Spline Mesh
(big picture - sorry about that…)
Now to add a spline mesh along my newly created spline…
First off, I grab the scale from the setup struct and convert and store it as a local variable.
I added a custom function (a) to find the dimensions of the spline mesh(es) I’m using.
The “Rope Material” enum in the setup struct has certain static meshes associated with each option, so I’m reading that enum, get the associated mesh, “get bounds” of that mesh and return the box extents. The way my static meshes are aligned, the X value represents the length.
next I’m doing some calculations to see how may times I can add that static mesh along the spline.
I’m using the “division (whole and remainder)” to get my number of segments, and add 1 if the remainder is greater than half of the static mesh length.
Now that I know how many segments I need, I recalculate the actual length of each spline mesh segment. Depending on the earlier “remainder” check, that means the spline mesh will either get stretched or squashed down a bit, but not more than 50%.
Now I start looping and add a spline mesh segment until I reach the end of the rope.
The custom function (b) checks for the current loop index and “Rope Material” enum and returns that static mesh to set each segment to. (I’m using three static meshes for each “Rope Material” type - 1 top end, 1 middle part, 1 bottom end. Index 0 selects top end, index “last index” selects bottom end, everything else selects middle part).
I set start and end position of each segment based on the segment length I determined earlier, and scale down the tangents to the same length.
Then set the scale of each end to the value calculated at the beginning, disable collision (don’t need the rope to do anything but look pretty, collision itself is handled by the skeletal mesh) and add each segment to another array.
** Rope Actor Event Graph]**
Now that I have the visual rope added, I need to update both spline and spline meshes to keep matching the skeletal mesh component.
Each custom function is similar to the ones used in the construction script, but instead of calculating and creating the elements, I loop through the arrays and update them.
The branch at the end checks if my player character is currently hanging on the rope, and if true, I calculate his current velocity. (I’m using “Set Actor Location” to match my character to the rope, so he doesn’t have his own velocity, and I need to know how fast he is swinging for the exit jump or drop)
Update Rope Spline
Fairly straight forward. I check if the rope is actually simulating (no point to update each tick if nothing changes…) and then loop through the spline points and update their location based on their respective skeletal mesh bone location.
You’ll notice here I didn’t grab the Y-location of the bones.
I found that the skeletal mesh still moves a bit in Y even though I specifically told it not to (silly teenager, never does what he’s told…), and since I’m working in 2D and need my character aligned to the viewplane, I decided to just ignore what the skeletal mesh does on Y and simple force it to stay flush.
If you are thinking of doing this for a 3D game, just ignore that part.
Update Spline Mesh
Here I’ll update the component length based on any spline stretch as a local variable, then loop through the spline mesh array and set location and tangents the same way as in the construction script.
Activate the Rope
The last step to make the rope act like a rope is to activate it.
(Not going into the sound part, I’m still working on that.)
At “BeginPlay”, I check if it should be active (from setup struct), and if true, assign the constraint profile (see post II - Skeletal Mesh Setup) and simulate physics.
If the rope is not set to active, I have a BPI function “Activate Rope” I can call that does the same thing.
To illustrate why I’m going through all this trouble to make a spline mesh and not just use the skeletal mesh as it is, here’s a simple side-by-side comparison of the two in action:
It’s not an earth-shattering difference, I admit, but I do prefer the spline mesh look. And in cases where the rope loops back on itself and collapses, the effect is even more pronounced.
One final thing I forgot to mention earlier is my use of sub-stepping.
Physics are quite touchy, and on elements like my rope that can receive a lot of force over a short amount of time, it tends to freak out, so sub-stepping is a great helper to keep the bones in line.
So, sub-stepping is turned on, and I tweaked the delta time values to be basically fixed.
This part is still work in progress, but in my initial tests of capping the frame rates to 30, 60 and 120, this really helped to keep the rope stable and gave me consistent force for swinging.
(Before setting this, higher frame rates made the swing much more powerful than lower frame rates, and I obviously don’t want that kind of difference in behavior…).
BTW, if I’m making any major boo-boos, please do let me know. I’m learning as I go along, and I’m always happy to get some feedback.