Tapestries with constraint-based physics

This is my first post, so my apologies if this is not what you expected.

A few weeks ago, I decided to mess around with physics for fun to see if I could make tapestries with actual physics. My intent was to put them in a dungeon known as “Fort Morrow” in my game Puzzle Dungeon. Overall, it went imperfectly, but well enough.

I will start with a GIF showcasing the results:
Tapestries

This is far from perfect, but it does what I intended. I’ll explain how.
Firstly, each tapestry consists of a 6 x 12 grid of square parts, sized 2 x 2 x 0.1.


I designed the tapestries this way because I wanted them to bend along two axes. I pulled this off, as one can see when the sunset tapestry bends horizontally and the moon tapestry bends vertically when I finish interacting with each in the above gif.

There are eight attachments in each part. Each corner has two, one for a vertical constraint and one for a horizontal constraint. This matters because they have to vary by orientation in order for constraints to face the right way by default. Previously I had them set up so the default orientation was backwards, which made the tapestry twist like crazy. Once I realized that, I designed the current version.


(The above image is from the back, as there is nothing in front of the tapestries that would distract the viewer.) Attachments are 0.6 studs away from the center in the X and Y dimensions. This leaves 0.4 studs of space between each one and the edge of the square, allowing the constraints to be 0.8 studs long.

The constraints are RodConstraints, which ended up working best when I tested various constraint types. As their length has a minimum, I could not make them as short as I wanted, hence why the attachments aren’t at the edges of the squares (though in hindsight, perhaps I could have gotten it to work in a different way than I tried). Finally, their limits were set to 5 for LimitAngle0 and 0 for LimitAngle1. This prevents the tapestry from bending more than desired, and giving it more freedom makes this complicated constraint-ridden assembly begin to overwhelm the engine.

You may have noticed that the tapestries have a different design in the GIF. I recorded it before finalizing the colors. Final designs are here:


Each tapestry utilizes one texture for the lighter colors, the parts being the darker colors. Each texture is a solid white color, allowing me to use the Color3 property to make it whatever I want (I suggest doing this for all images that you intend to be one solid color!) Each square is a darker color, so any square without a lighter color does not need any textures. I used the offset properties so each square is covered by a different portion of the tapestry’s image, thereby sparing Roblox (and myself) 41 more assets’ worth of work than necessary for each tapestry (82 for the asymmetrical tapestries, which have a horizontally mirrored version of the image on the back).

I also put textures on the inner sides of the squares so that darker-colored seams are not seen when a tapestry bends, but that does leave risk of lighter-colored seams when tapestries are straightened. I had to choose one over the other unless I wanted to look into making this out of skinned meshparts, which I may attempt someday.

There is one problem, however. These tapestries can get stuck in walls if you try hard enough to push the former against them. As such, I had to do a bit of scripting using GetTouchingParts and changing CanCollide briefly to ensure the tapestry will swing back to its resting position. However, it became harder to get them stuck after I moved them half a stud farther away from the wall than I first put them. Overall, my solution works well enough.
TapestryUnstuck2

Finally, an example image of tapestries in the dungeon:

Overall, the tapestries were an afterthought. I didn’t design them until I was two dungeons beyond Fort Morrow in my game development process. Should these break in a Roblox update, I am fine with that. After all, they already begin to push the limits of constraint-based assemblies, as I mentioned earlier.

What do you think? Does this seem worth the hours I put into experimenting with physics? Do the non-centered crescent moons bother you like they did one of my friends? I definitely learned from this, and hope you can as well if you experiment like I did. Thanks for reading!

5 Likes

Lovely work, keep it up! Maybe you could try adding a few more squares to the grid, as I think it would upscale the quality of the simulation. Great work though!

1 Like

Sick implementation of verlet integration using constraints. Lovely!

1 Like

Perhaps I’ll try that. RodConstraints can be as short as 0.2, so the only potential problem is whether or not Roblox can handle an assembly with more squares. I’ll look into it at some point. I may even make a small enough version to use as curtains or something. Thanks!

1 Like

for the wall clipping thing why not just use 2 different collision groups? so it just ignores the wall? alternativly you could also use prismatic constraints to stop it moving backwards past a certain point?

1 Like

I considered having it ignore the wall. Honestly it might not end up as bad as I thought if the player pushes it into a wall. I should have given it a try regardless, and will do so. As for prismatic constraints, I’m afraid those would limit movement along two axes as it confines attachments to the third. It would be preferable if I only limit movement along the third axis and it could can still freely move along the other two. Thanks for the suggestions!