A downloadable asset pack for Windows

Download NowName your own price

------------------ Description ------------------

> Verlet integration is a method of simulating physics.

> This implementation for Gamemaker 2.3+ contains a library for basic 2D simulations as well as an example implementation.


------------------ Features ------------------

> Simulate 2D ropes, cloth and softbodies

> Various colliders, as well as custom shaped sprite colliders

> Force fields for simulating wind, pulling or destroying structures

> Connectors let you chain together different simulated objects, or instances

> Documented functions and clean script structure

> All objects can be textured


------------------ Contribute------------------

> You can contribute to the project on github!

https://github.com/sareklambert/gms-verlet-integration


------------------ License ------------------

This work is released under general MIT license. You are free to use it for any private or commercial projects c: (See LICENSE file)

StatusReleased
CategoryAssets
Rating
Rated 5.0 out of 5 stars
(6 total ratings)
AuthorJamJamTeam
Tags2D, GameMaker, gms2

Download

Download NowName your own price

Click download now to get access to the following files:

verlet integration.yyz 128 kB
VerletIntegration.yymps 118 kB
verlet integration.zip 4.3 MB
LICENSE.txt 1 kB

Development log

Comments

Log in with itch.io to leave a comment.

Hi!, very good plugin, extremely polished, I just had a problem trying to attach a verlet to another verlet, is there a way to do this without having to change the core scripts?

Hi! You can attach a point of one group to a point of another group using the VIConnector like this:

var rope1 = new VIRopeColored(0, 0, 8, 10, c_red, 1, 1, -1);
system.AddObject(rope1);
var rope2 = new VIRopeColored(0, 0, 8, 10, c_green, 1, 1, -1);
system.AddObject(rope2);
var connector = new VIConnector(0, 0);
connector.SetParent(VI_PC_TYPE.POINT, rope1.GetPointByKeyword(VI_POINT_INDEX.LAST));
connector.AddChild(VI_PC_TYPE.POINT, rope2.GetPointByKeyword(VI_POINT_INDEX.FIRST), false);
system.AddObject(connector);


This connects the first point of the green rope to the last point of the red rope. Note that you can't set up circular hierarchies though with multiple groups where the last one is connecting to the first.


If you need some new object which is not represented by a rope/cloth/softbody, you need to create a new function which derives from VIPhysical. You can look at how the VIRope functions are set up for that :)

Thanks for the help! I've been racking my brains for a few days trying to do this, thank you very much :D

(1 edit) (+1)

No problem :)

(1 edit)

Hello,
So i've been using this library for a while, it's really good. I'm porting my project to this new version, but I'm struggling to make it so the ropes and stuff dont spazz out when the game starts. I used to run the simulation 30 times on the first game frame with high friction, but it doesnt seem to work now.
Any ideas?

Edit: It also seems that increasing the number of points increases the length of the rope. Like, with points set to length/16 I get a much shorter rope than with length/8.

(1 edit)

Hi!

You can run the simulation multiple times by calling system.Simulate(delta); and manually override / temporarily store the friction variable system.frict before that.

The reason the rope with more points appears longer is because every point is affected by gravity, which is dragging the rope down and streching it. You can increase the "stiffness" in the rope's constructor to counteract that. :)

Is there a way you could create/is there already an existing quick tutorial on how to implement this? It looks like exactly what I am looking for, but I consider myself a game designer and not a programmer, so it looks a bit daunting. I'm basically trying to recreate Yoshi's tongue attack as a rope/grappling hook that extends outward and retracts and looks like it's being affected by physics, but not really. LoL I'd even be willing to pay for it!

Unfortunately I don't have any time atm to create tutorials beyond the function documentation and the implementation provided :c Sounds like a complicated setup. What you could do is create a rope and attach both ends to connectors. One connector is then also attached to your player instance and the other one to your hook instance (which you'd control with your own physics probably). Retracting a rope is not a build in functionality. A couple of months ago, someone else asked a similar question about a fishing line, where I explained how you'd implement something like that in theory. That does require some understanding of programming though :/ Hope that helps you a bit!

Maaan, I just sat down, downloaded your system and rewrote all the function names and fixed Feather's errors. Started saving the file, wanted to look up your nickname to put in the title and found that you had just updated the asset... 

(1 edit)

Thanks a lot for the asset, you've rewritten everything even better than I did. It's much more structured and concise! The only thing you could do would be to package the asset in a local package and make the *.yymps file available for download.

Glad you like it :) I never used packages but I've added the file now. Hope it works :D

Oh no D: Yeah the previous version was two years old and very messy. Back then I made this asset for one of my game projects but decided to also upload it here. Now I gave it a bit more love and added better documentation and stuff..

(2 edits)

I added one more function for VIObject to be able to delete self when object is destroyed. Since I didn't find a corresponding function for this. The function I added does the following:

var _ind = ds_list_find_index(systemReference.objectList, self);
ds_list_delete(systemReference.objectList, _ind);


Did I do it right? Everything works fine for me!

If it works, it works :D There is still some functionality one could add like the delete function you've added, or interaction between different ropes/softbodies. However, I won't be able to work on this project for a longer time again now so feel free to add what you need :)

That being said, I plan to upload the project to github the next couple of days, so if you want you could also contribute there.

As mentioned by others, this is an excellent example. Three things though:

1. I tried attaching the last vertex of rope1 to an instance of oDrag, just like how the example attaches the first vertex of rope1 to an oDrag intances. While this works, I note the last vertex is not able to properly connect to the other oDrag instance - there is always a gap, unless both oDrag instances are very close to each other:



I tried fixing this by changing the stiffness, segments, and segments length, but I keep getting a gap. What I was hoping for was that the last vertex of the rope is connected to oDrag exactly like the first vertex. You can see this below, where green is for the first vertex, and red is for the last vertex: 



Is this just default behavior, or is it possible to make the last vertex's connection be just like the first vertex's?

2. Any stiffness under 1 (0.9 for example), causes the rope to droop drastically. Not sure if this is a bug (interestingly, when the rope droops like this, the last vertex seems to attach the way I want it to as I mentioned in point 1)?



3. Lets say I wanted to make something like a fishing line where the user is able to reel-in/retract the rope. Is there a way to do this? My assumption was that the rope properties, namely the number of segments and stiffness, would need to be changed, but those properties are called for creating the rope only, not to update it. Do you have a recommended approach? 

Thanks for any input you can provide!

(4 edits) (+2)

(Seems like I can't upload screenshots for some reason.. :c)

Problem 1:

The verlet system works by having a list of vertices and a list of sticks. Every update, we iterate through the list of vertices from the start, forcing the sticks to their original length. Since we're starting at the first vertex, its position will always be correct, but the rope will drag away from the last point as a result. One way to solve that might be to rewrite how we iterate through the list every update. So update the first vertex, then the last, then the second, second from last, etc. until we reach the center. I'm not sure if this will result in other unwanted behaviour though.

I'd manipulate this for loop and see what happens:

verletFunctions line 299:
for (var i = 0; i < stickAmount; i++) {
    currentStick = stickList[| i]; 

A simple and dirty "fix" would be to rewrite the draw function and draw another line from the last vertex to the point where it is supposed to be attached. It won't be perfect but it will look like it's attached.

verletFunctions line 497:
draw_vertex(currentStick.v2.x + lengthdir_x(wHalf, stickDir - 90), currentStick.v2.y + lengthdir_y(wHalf, stickDir - 90));
draw_vertex(currentStick.v2.x + lengthdir_x(wHalf, stickDir + 90), currentStick.v2.y + lengthdir_y(wHalf, stickDir + 90));
// Draw another line here
draw_primitive_end(); 

Problem 2:

When the verlet system updates, the "stiffness" is simply the amount of times we do the update. The more updates per frame, the more correct the simulation will be, but the more performace we draw.

verletFunctions line 294:
repeat (stiffness) {
    #region Update sticks
    #region Update vertices
} 

A stiffness value below 1 would therefore result in errors.

Problem 3:

That will be a difficult one.. I didn't think of a use case like this.

The sticks already have an individual length value. To retract the rope, you probably want to create some function that retracts the rope by one pixel. It would decrease the length of the first stick by 1 as long as the stick's length is greater than 1. A length of 0 would probably create errors. Otherwise delete the first stick and the first vertex, then continue with the next stick until the rope is gone.

New function for the rope group:
function retractRopeByOnePixel() {
    if (<amount of vertices> > 2 AND <amount of sticks> > 1) {
        var currentStick = <first stick>
        if (currentStick.length > 1) {
            currentStick.length --;
        } else {
            <delete first stick>
            <delete first vertex>
        }
    } else {
        return false;
    }
    return true;
} 

Something like that maybe. You'll need to figure out where to get the amount of ropes/sticks and where to delete them. Call the function until it returns false, then delete the rope.

Hope I could help :)

Thanks for the reply! I'll have to keep working with it to get a better grasp of it, but the info you've provided is much appreciated!

Great plugin! Is there any way to stop the textured rope from stretching the image (instead just spacing out the individual sprites)? I was trying to use a rope in the style of the example chain, but with the two objects moving quite far from each other, the texture can get very stretched. I've done some looking around in the functions and it seems like it could be quite a difficult change. Either way, great work!

(+1)

Thank you! I think I added an option to change the 'stiffness' of the verlet system so it doesn't stretch so much. You should be able to manipulate it either in the rope function or the function which sets up the verlet system. But do note that increasing the stiffness draws a lot of performance, as this basically multiplies how many times per frame the whole physics simulation gets updated.

Thanks for the quick response! I did mess around with stiffness, but I realized I was straying to far from the intended purpose of verlets. So instead I just break the verlet chain and replace it with a line renderer in some edge cases lol

Whatever works :D Glad you found a workaround!

Works great, great work. One question, is there any way to adjust the depth?

(+1)

Thank you :) The verlet system is drawn using the VerletSystem() struct's Draw() function. The depth would be equal to the object which calls the Draw() function. By changing either that object's layer, or where you call the Draw() function (depending on your case), you can control the depth at which it is drawn. There is however no functionality to sort different verlet groups within the same verlet system after they are created. Groups within a system will be drawn in the order in which you added them with the VerletGroupCreateRope() or other functions. If you need to change them dynamically, you could either create multiple verlet systems, or write a new function inside the VerletSystem() constructor, which rearanges the "verletGroups" ds_list. Hope this helps!

(+1)

Thank you for the quick and detailed answer! It works perfectly now. I didn't even think of that :D