Circular Gravitational Fields

B

Babuchi

Guest
Hi, I have tried to do these sorts of things before, with little success.

As you might have guessed, the game takes place in outer space, although a surreal version of it. Thus, instead of gravity simply pulling objects "down", I'd want a sort that pulls them together--not all; I'd be willing to fudge in that regard, but at least ones that are key to the gameplay. For example, if the player character is right of an object that has a gravitational field, it's pulled left, while if it's to the left of the object with a gravitational field, it's pulled right. Pretty straightforward to describe, but so far not to implement.

I've tried to control for it in the playable character; to the effect that expressions check whether there's an object that's supposed to have gravity nearby, and if so, start moving the player towards the object. Success via this method was mixed at best; sometimes it worked well, but other times it was just bizarre; the character would sometimes be sucked in from far further away than it was supposed to be, and sometimes, for whatever reason, seemed to be repelled from the object. Weird, to say the least.

So what might I have been doing wrong. is there a better way to do these things?
 

NightFrost

Member
Gravity needs to apply velocity on x and y axis towards the center of gravity well. The force exerted on the object is your gravity constant times mass by distance squared. More accurate gravity calculation would require the sum of both masses but you can simply ignore ship's mass for game purposes. If you have but one object with mass, you could even bake together your gravity constant and the object's mass into a single number to save a multiplication.

The formula goes:
Code:
var Distance = point_distance(Ship_X, Ship_Y, Planet_X, Planet_Y);
var Force = Grav_Constant * Planet_Mass / (Distance * Distance); // Set grav and mass to taste to change how strongly gravity pulls
var Dist_X = (Planet_X - Ship_X) / Distance;
var Dist_Y = (Planet_Y - Ship_Y) / Distance;
var Vel_X = Dist_X * Force;
var Vel_Y = Dist_Y * Force;
// Apply Vel_X and Vel_Y to ship's movement calculations on top of everything else.
// If using delta time, multiply them by the delta.
EDIT - if you have multiple gravity-exerting objects, you sum the velocities caused by each, then apply on ship.
 
B

Babuchi

Guest
Is that actual code? I ask because I had thought variables needed to have an underscore in their name. Also, how many of those are core variables, and how many need to be defined elsewhere?
 

TheouAegis

Member
There is no naming convention requirement in Game Maker (or any language that I'm aware of, but that's not saying much).

Ship_X, Ship_Y, Planet_x and Planet_Y are pseudovariables. You'd replace them with the x and y coordinates of the ship and corresponding planet.
 
B

Babuchi

Guest
Okay; so what about multiplying distance by itself? I'm not quite sure why that part is in there. I also am pretty sure "taste" was supposed to be "test".
 

TheouAegis

Member
No, "taste" is supposed to be "taste". The expression "to taste" means "however you see fit".

As for distance multiplied by itself, he's using the formula for gravitational force.


Oh yeah, you'd need to define Grav_Constant yourself. I overlooked that variable in his code when I wrote up the last post.
 
C

CaffeineJunky

Guest
The simple answer is that you really just need an acceleration that increases in proportion to the inverse square distance, scaled to an appropriate unit, whose direction is always pointing towards the center. Maybe something like this.

Code:
metric = 128;
maximum_pull = 4;
relative_cutoff_distance = 2;
gravity_constant = 8; //adjust this for the strength
relative_distance_from_source = max(point_distance(x, y, source.x, source.y) / metric, 1 / sqrt(maximum_pull)); //this keeps the gravity reasonable and also prevents division by zero errors
gravitational_strength = 1 / sqr(relative_distance_from_source) * gravity_constant;
gravitational_direction = point_direction(x, y, source.x, source.y);

if (relative_cutoff_distance > relative_distance_from_source) {
   motion_add(gravitational_direction, gravitational_strength)
}
 
B

Babuchi

Guest
Metric being the user-defined variable there?

Edit: Also, since it seems "Maximum Pull" is a set value and only used in that one place, why is the division function needed, as opposed to just the variable?
 
Last edited by a moderator:
B

Babuchi

Guest
It seems my question wasn't clear enough to answer, so I'll ask it again: If Maximum Pull always equals 4, as that code suggests, then 1 divided by the square root of Maximum Pull always equals 0.5. So my question is why even have that variable defined? Why not just write this code?

Code:
relative_distance_from_source = max(point_distance(x, y, source.x, source.y) / metric, 0.5)
The only reason I could see why is that Maximum Pull is defined in your sample code only for reference, and actually refers to something else, but in that case, what? I would like to know that.
 
C

CaffeineJunky

Guest
If you haven't quite figured it out, here's the breakdown..

In Newtonian physics, gravity is typically modeled as an inverse square law. If r is the distance away between two point particles, then we say that each of them applies a gravitational force on each other that has the following characteristics:
  1. the magnitude (strength) of the gravitational force is proportional to A / r^2, where A is some value that depends on the masses of those particles, and r is the distance, as previously stated.
  2. For both particles, the direction of the force is pointing towards the other particle.
When we start having more than two particles, gravity gets interesting; when we have billions upon billions of particles, gravity starts to have some macroscopic properties. One such property is that a very massive object (planet) is seldomly affected by a very tiny object (a person or a spaceship). Another property is that smaller objects tend to fall towards the large body (and if you move at the right speed you'll be constantly falling without ever hitting that body; this is called orbit.) A massive body has a center of gravity, which is the average of all sources of gravity in space (which is a point). Because this is a point, we can treat the entire massive body as if it were a particle that was centered at that one point (approximately).

Even with these macroscopic observations, we know that the following holds true based on the basic inverse square law that affects all particles:
  1. If you double the distance from the center of gravity, then the force of gravity reduces by a factor of four. Or another way of stating that: if you halve the distance, the force of gravity quadruples.
  2. The direction of gravity is pointing towards the center of gravity.
OK, so where does that leave us?

Well, if you do a little bit of thinking, you'll notice that halving the distance more than once is going to cause the magnitude of the gravity to grow exponentially, and this can be problematic when we try and use the inverse square law for a game, especially if you don't do any techniques to smooth the gravity as you're object is moving about; if you blindly apply the inverse square law, you might end up having one step where an object moves a distance that is equal to 100 lengths of the screen.

So the formulas I have given you will do the following:

we will use an inverse square law, except that will introduce a few parameters to make this easy to control.

The first parameter I provided is the metric variable. This prescribes a distance that we will want a gravitational force of 1 to be. That means that if we are 128 pixels away from the source of gravity, we will have a gravitational strength of 1. Check it out:

r = 128.

relative to the metric, r' = 128 / metric = 1 / 1 = 1, and 1 / r^2 -> 1 / r'^2 = 1 / 1 = 1.

Next, we want to make sure our formula doesn't explode. The largest I'll ever want the gravitational force to be is 4. So I created a variable to control this.

In order to make sure that this is the case, I simply decided that if your relative r' is less than 1/2, then we'll treat the force of gravity as if though it were 1/2.

r = 64
r' = 64 / metric = 64 / 128 = 1/2. So 1 / (1/2)^2 = 1 / (1 / 4) = 4 = magnitude of force.

r = 32
r' = 64 / metric = 32 / 128 = 1/4 so 1 / (1/4)^2 = 16 = magnitude of force; but I don't want the force to be this large. If instead, I make sure that the relative distance r' >= 1/2 is always true , then I'll always have the situation where 1 / r^2 <= 4.

Now if I want to have the gravity grow the same everywhere, I simply multiply the formula by a scaling value, which is the gravity strength.
 
B

Babuchi

Guest
Does mass factor into your code, as you've presented it currently? Also, please clarify, is Maximum Pull something that can be used more than once? It seems we're thinking about this problem from different angles; you like to think about real-world physics and cover all bases in your explanation, whereas I'm looking at it from a purely mathematical standpoint wherein an axiom is "simplify whenever you can". I still am unsure of why your bit about Maximum Pull and its equation can't just be simplified to 0.5, even if that simplification obscures the real-world applications. However, I'll do whatever works.
 

NightFrost

Member
Mass is part of the gravity_constant in that code, it does the summing up of grav constant and mass that I mentioned on my code sample. You change it to change the total strength of gravity. Both pieces of code use the same math, they just fiddle around the numbers a bit differently. Also, depending on how you simulate velocity, you may need separate x and y vectors; simply updating position is the least accurate, then there's verlet (which I tend to use) and then there's more accurate implementations. Net effect over time becomes more accurate, but players will probably not care as long as the approximation feels convincing enough.
 
B

Babuchi

Guest
Here is an update. I have utilized this code in my game, and after tweaking the numbers to fit our dimensions, it works well, except my character sticks to the objects permanently. Note that we've got the simple "start moving in 'no direction'" action for a collision event; what could replace this to make it so gravity can still be conquered with a bit more effort? Or is that just a matter of bumping the character's acceleration up a bit?
 

NightFrost

Member
You'll need to give the player enough thrust so they can successfully combat gravity. It a balancing act between gravity's pull, so that it has a discernible effect, and player movement, so they aren't trapped by it. As for sticking, shouldn't the player explode when they ram into a planet? Or are you having the player land onto planets?
 
B

Babuchi

Guest
That's case-by-case. Some objects will kill the player if they get caught, but others will just hold them down until they escape.

In CaffeineJunky's code, what should I change to make the maximum gravity weaker? Note that my character accelerates, so momentum doesn't build all at once. Acceleration is likely the key problem, since the way we've done it, the character must already be moving somewhat for acceleration to take place.
 
Last edited by a moderator:

GMWolf

aka fel666
I had thought variables needed to have an underscore in their name
It sounds like you have very little experience in GML.
I would strongly recomend you get familiar with it before you attempt more complex projects.

I would also not recomend you simply copy any of the code givent here. It is far better for you to deconstruct it, understand it, and implement your own version.
Not only would that version match your requirements far better, it will also alow you to learn some more GML.
 
B

Babuchi

Guest
You are correct in these assumptions. I tend to learn Game Maker programming, whether GML or D&D, as things come up. I understand that is not a good way to go about it, but for me the "deconstruct and understand" parts require something of a tangible ludological effect to bind them to before I really get it. I'd appreciate a link to tutorials that teach the stuff by binding it to actual familiar gaming archetypes, although the ones that I was presented back when I started learning Game Maker weren't very good.
 
C

CaffeineJunky

Guest
That's case-by-case. Some objects will kill the player if they get caught, but others will just hold them down until they escape.

In CaffeineJunky's code, what should I change to make the maximum gravity weaker? Note that my character accelerates, so momentum doesn't build all at once. Acceleration is likely the key problem, since the way we've done it, the character must already be moving somewhat for acceleration to take place.
Weaker in what sense? There's two notions of being weaker here: the overall strength of the gravity, or the strength of the gravity based on how far away you are.

For the first one, you would increase the gravity constant to make the gravity stronger, and decrease it to make it weaker. This will scale the effect everywhere where gravity applies.

For the second one, increasing the metric will strengthen the overall gravity at any given distance, and decreasing it will cause gravity to be weaker.
 
B

Babuchi

Guest
Weaker in what sense? There's two notions of being weaker here: the overall strength of the gravity, or the strength of the gravity based on how far away you are.

For the first one, you would increase the gravity constant to make the gravity stronger, and decrease it to make it weaker. This will scale the effect everywhere where gravity applies.

For the second one, increasing the metric will strengthen the overall gravity at any given distance, and decreasing it will cause gravity to be weaker.
The issue is our acceleration model; we'll need to look into that.
 
B

Babuchi

Guest
The tutorials that ship with gamemaker studio are very good.
Which do you mean by those? If you're implying things like their platform game tutorial, then no; I don't think that's a very good one. Its omission and misuse of animation is pretty unforgivable to me. I also cannot recall any tutorials included with GM8 that had any instructions about code.
 
N

Never Mind

Guest
GM8?
Get Game Maker Studio! The tutorials are right on the starting menu:
 

TheouAegis

Member
I still am unsure of why your bit about Maximum Pull and its equation can't just be simplified to 0.5, even if that simplification obscures the real-world applications.
Since this was never really answered...

He's giving you a customizable code. One of the things you can customize is the constant maximum_pull, so it's put in that code as a variable. Rather than just saying "1/4" and making it some mysterious magic number you're going to forget about the relevance of down the road, he keeps it as a variable so you can find and change it easily at any time.
 
B

Babuchi

Guest
Okay, further question: It seems that if I place multiple instances of an object called by the gravity code, only the first encountered works with it. That is actually no big deal; it can be fixed just by duplication and parenting, but I just want to check if this is supposed to happen.
 

TheouAegis

Member
Do you mean you have 20 ships and only 1 ship is getting pulled toward a planet, or you have 20 planets and the ship is only getting pulled toward 1 planet?

In either case, it could be variable scope. You should post the whole code.

Like, previously you had source.x and source.y for coordinates to be pulled toward, or something. Are you changing source for each planet or ship?
 

NightFrost

Member
Okay, further question: It seems that if I place multiple instances of an object called by the gravity code, only the first encountered works with it. That is actually no big deal; it can be fixed just by duplication and parenting, but I just want to check if this is supposed to happen.
If you mean multiple gravity sources, I mentioned about this back on my original code fragment; add together all the Vel_X and Vel_Y effects before applying them to player's movement. (In other words, you need to sum all the vectors; GML doesn't do vectors so you have to handle gravity as x and y components separately.)
 
Top