Springs between objects
#1
Posted 16 January 2011 - 06:31 PM
I've been looking at a couple of examples people made of a stretchy polygon that maintains its volume as it falls, bounces, etc. I tried deconstucting it and just using the parts I think I need, but the result is always body parts that either don't budge, fall off the screen, or fly off in crazy directions as soon as the head moves. I might have parts of the volume and gravity calculations left over from the example that are throwing it off.
I know F = -k*dx is the main formula for the sping force. I'm pretty sure that F is going to be a modifier for my speed and direction variables for each body part, so each body part would have a "dv" (change in speed) and "dd" (change in direction) applied on it from the piece to either side (or a "dhspeed" and "dvspeed" to change the hspeed and vspeed).
My "dx" should be "point_distance(body1.x, body1.y, body2.x, body2.y) - def_length"
"k" I take to be how strong I want the spring to be, so I'll have to find a value I like.
How do I then convert my "F" and properly split it into either an hspeed and vspeed, or a dv and dd, acting on the body part?
#2
Posted 16 January 2011 - 06:45 PM
As soon as you have a size and a direction, I think you can now figure out what to do with them
#3
Posted 16 January 2011 - 08:19 PM
Light bulb! Ting! It's been such a long time since I dealt with math like this, I've forgotten useful tidbits like that. I've been writing everything out on paper for the past hour or so and think I have a much better way of setting up my objects, and now I can sort out that pesky direction issue I think. Thanks! I'll follow up later with my results.As soon as you have a size and a direction, I think you can now figure out what to do with them
#4
Posted 17 January 2011 - 09:12 AM
I have a "tail" (end piece) which creates the "body" pieces, and finally the "head".
The tail is in a fixed position.
The head can move about freely.
"follow" is the ID of the previous body part (closer to head).
"trail" is the ID of the next body part (closer to tail).
"spacing" is the starting space between parts, which is the equilibrium spring length.
In the step event of the body pieces:
f1 = -k * (point_distance(follow.x, follow.y, x, y) - spacing) f2 = -k * (point_distance(trail.x, trail.y, x, y) - spacing) if (f1 >= 0) dir1 = point_direction(x, y, follow.x, follow.y) else if (f1 < 0) dir1 = point_direction(follow.x, follow.y, x, y) if (f2 >= 0) dir2 = point_direction(x, y, trail.x, trail.y) else if (f2 < 0) dir2 = point_direction(trail.x, trail.y, x, y) dx1 = lengthdir_x(f1, dir1) dx2 = lengthdir_x(f2, dir2) dy1 = lengthdir_y(f1, dir1) dy2 = lengthdir_y(f2, dir2) dx = dx1 + dx2 dy = dy1 + dy2 x += dx y += dyIt seems to work very well, with two issues:
- I need to know how to add in dampening to eliminate piece wiggle.
- If the pieces get too close to one another, they snap on top of one another and twitch around like crazy. This is affected by the spring length, so I think there's an issue possibly if the distance between parts is smaller than the spring length.
Any suggestions on those two items? Both issues become unnoticeable if I use a very small (like "1") spring length, but I'd like to do it properly if possible.
#5
Posted 17 January 2011 - 12:10 PM
if (f1 >= 0) dir1 = point_direction(x, y, follow.x, follow.y) else if (f1 < 0) dir1 = point_direction(follow.x, follow.y, x, y)
You shouldn't do this. A few lines below, you're taking lengthdir_x(f1, dir1) and lengthdir_y(f1, dir1). If distance < spacing, f1 wil be negative, and then (lengthdir_x(f1, dir1), lengthdir_y(f1, dir1)) will automatically "turn around" too, because moving a negative distance in a direction moves you in the opposite direction. So you do not have to turn around the direction yourself, this is automatically done by this system. So replace the above code by
dir1 = point_direction(x, y, follow.x, follow.y)Same goes for trail.
Probably this is what causes things to go weird when pieces get too close. When the spring is longer than spacing, lengthening it will generate pulling force, however because both you and GM switch signs when spring is shorter than spacing, this will cause a further shortening of the spring to generate pulling force also, which is not what you want.
I usually just put- I need to know how to add in dampening to eliminate piece wiggle.
dx *= 0.9; dy *= 0.9(or some similar constant) in the step event to simulate friction.
#6
Posted 17 January 2011 - 07:02 PM
So you do not have to turn around the direction yourself, this is automatically done by this system.
You don't even have to work with angles, either. In fact, that's a waste of time, since you're just using lengthdir to get it back into rectangular coordinates. But you already have rectangular coordinates, since that's how you got the direction in the first place.
#7
Posted 17 January 2011 - 11:08 PM
If I take out my direction reversal, as soon as the head moves, the body pieces go flying off the screen, alternating starting at the head, and moving down the line, with one piece flying off one side, the next off the other, etc. along the initial axis of movement.too, because moving a negative distance in a direction moves you in the opposite direction. So you do not have to turn around the direction yourself, this is automatically done by this system. So replace the above code by
I think it's because the point_distance function I use to find the direction doesn't take sign into account, so I have to compensate for it.
How would I do it otherwise? Is there a force equation that works with rectangular coordinates? I thought maybe doing a four force calculation with just the x and just the y so I'd have an x and y force for each spring, but then I'd still need the angle of the spring to figure out the force "length" in each direction.You don't even have to work with angles, either. In fact, that's a waste of time, since you're just using lengthdir to get it back into rectangular coordinates. But you already have rectangular coordinates, since that's how you got the direction in the first place.
Originally, before the spring math got involved, I was using a simple
x = (follow.x + trail.x) / 2 y = (follow.y + trail.y) / 2
but that only moves the pieces directly between the other bits, and doesn't give the fluidity I'd like.
#8
Posted 17 January 2011 - 11:52 PM
Assuming a system with time step t, (velocities and forces relative to a time unit. A time step of 0.5 moves everything by 1/2 of a time unit)
Given two points with positions [x1, y1] and [x2, y2], with velocities [dx1, dy1] and [dx2, dy2] and a spring with spring constant k, resting length len, and maximum friction force f:
Compute the difference between positions [diff_x, diff_y] = [x2 - x1, y2 - y1]
The length of this vector is dist = sqrt(diff_x * diff_x + diff_y * diff_y)
The force to apply is (dist - len) * k. We create a vector of this length by multiplying a unit vector by this scalar. [force_x, force_y] = [diff_x, diff_y] * ((dist - len) * k / dist)
dx1 += force_x * t / 2;
dy1 += force_y * t / 2;
dx2 -= force_x * t / 2;
dy2 -= force_y * t / 2;
Now friction (only along the length of the vector):
[rel_dx, rel_dy] = [dx2 - dx1, dy2 - dy1]
spd = (rel_dx * diff_x + rel_dy * diff_y) / dist;
max_friction_change = abs(f * t); // Remove the absolute values if you can be sure no prankster is going to set negative friction or time.
if (spd > max_friction_change)
spd = max_friction_change;
if (spd < -max_friction_change)
spd = -max_friction_change;
// Now apply an equal and opposite force to both.
dx1 += spd * diff_x / dist / 2;
dy1 += spd * diff_y / dist / 2;
dx2 -= spd * diff_x / dist / 2;
dy2 -= spd * diff_y / dist / 2;
So yeah. The basic idea is: Use vectors, use Hooke's law, have fun.
#9
Posted 18 January 2011 - 08:34 PM
f1 = -k * (point_distance(follow.x, follow.y, x, y) - spacing) f2 = -k * (point_distance(trail.x, trail.y, x, y) - spacing) dir1 = point_direction(follow.x, follow.y, x, y) dir2 = point_direction(trail.x, trail.y, x, y) dx1 = lengthdir_x(f1, dir1) dx2 = lengthdir_x(f2, dir2) dy1 = lengthdir_y(f1, dir1) dy2 = lengthdir_y(f2, dir2) dx = dx1 + dx2 dy = dy1 + dy2 x += dx y += dy image_angle = point_direction(x, y, follow.x, follow.y) - 180That'll do it. You were correct, Erik, about not needing to reverse the angle, but the problem was I had my point_distance set up facing the wrong way. It works beautifully now.
And as for Gamer3D, I am technically not using vecters, but I am using their components. And, err, it's been so long I don't remember all of that "fancy" stuff
Thanks!
#10
Posted 19 January 2011 - 04:02 AM
Hahaha. How do you think vector operations are done?And as for Gamer3D, I am technically not using vecters, but I am using their components. And, err, it's been so long I don't remember all of that "fancy" stuff
I will pore through your example, however, and if I can adapt it I will see which method is more efficient for me.
FYI, I got distracted partway through writing my example, so it's probably not the best thing to learn from.
#11
Posted 17 February 2011 - 03:51 AM
f1 = -k * (point_distance(follow.x, follow.y, x, y) - spacing) f2 = -k * (point_distance(trail.x, trail.y, x, y) - spacing) dir1 = point_direction(follow.x, follow.y, x, y) dir2 = point_direction(trail.x, trail.y, x, y) dx1 = lengthdir_x(f1, dir1) dx2 = lengthdir_x(f2, dir2) dy1 = lengthdir_y(f1, dir1) dy2 = lengthdir_y(f2, dir2) dx = dx1 + dx2 dy = dy1 + dy2 x += dx y += dy image_angle = point_direction(x, y, follow.x, follow.y) - 180
I'm sorry to resurrect this thread, but could someone comment this?
I'm trying to figure out how it works, and would really appreciate it.
#12
Posted 17 February 2011 - 04:12 AM
This code sets up two spring forces acting on the object. 'follow' and 'trail' are the two objects it is connected to. The forces [f1 and f2] point toward the object if they have a positive value.
f1 = -k * (point_distance(follow.x, follow.y, x, y) - spacing) f2 = -k * (point_distance(trail.x, trail.y, x, y) - spacing) dir1 = point_direction(follow.x, follow.y, x, y) dir2 = point_direction(trail.x, trail.y, x, y) dx1 = lengthdir_x(f1, dir1) dx2 = lengthdir_x(f2, dir2) dy1 = lengthdir_y(f1, dir1) dy2 = lengthdir_y(f2, dir2) dx = dx1 + dx2 dy = dy1 + dy2 x += dx y += dy image_angle = point_direction(x, y, follow.x, follow.y) - 180
I'm sorry to resurrect this thread, but could someone comment this?
I'm trying to figure out how it works, and would really appreciate it.
point_distance gives the current length of the spring.
'spacing' is the "at rest" spring length.
dir1 and dir2 are the direction each spring is pulling. dx and dy are the amount of x and y movement each spring would cause by itself, added together to get the actual movment of the object.
I will clarify further if that still doesn't make sense. Typing with a wiimote right now. Not the best way to reply to a complicated post
#13
Posted 17 February 2011 - 04:26 AM
Also, I need to commend you on the use of a wii-mote to type anything. That's hard to do.
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users











