3
\$\begingroup\$

I've seen a lot of tutorials for things like "fixed circular orbit" and "elliptical orbits" which end up never been what I actually want.

I have two objects: oPlayer, and oPlanet.

I am trying to allow the player to move around freely, but be able to be caught by the gravity of oPlanet, causing the player to go around in circles/elliptical orbit. I also need the player to be able to escape thate orbit, and end up on a trajectory. In fact, I want it to work for any oPlanet.

What I am looking for is something similar to the orbital gravity in Kerbal Space Program.

Is there any way I should go about this? If anyone can be of help, I would rather answers be in GML rather than the Drag and Drop, but any help is great!

\$\endgroup\$
  • \$\begingroup\$ I know absolutely nothing about game maker, but I am quite well-versed in orbital mechanics. Would you be interested in a purely pseudocode explanation of how to calculate the movement of an object affected by multiple gravity sources? \$\endgroup\$ – Philipp Feb 10 '15 at 1:59
  • \$\begingroup\$ @Philipp I have a mediocre understanding, but perhaps it may provide some sort of help. Sure! Tell me! Very interested! \$\endgroup\$ – user59493 Feb 11 '15 at 2:03
1
+50
\$\begingroup\$

I use Game Maker 8.1 all the time, and I've done orbital sims in them too. More good news: Game Maker has a built-in function that does vector addition for you:

motion_add(direction, acceleration) this will automatically change an object's hspeed and vspeed with the correct vector addition.

Remember that Game Maker treats 0 degree angle pointing right, 90 degree pointing up (which is the negative y direction), 180 deg pointing left, 270 deg pointing down. However, with motion add, you don't even need to know that.

Here's what I would do. In oPlayer, use the built-in variables x, y, hspeed, vspeed so that GM automatically does motion based on speed. Now you just need to do the acceleration from gravity, using motion_add. In the step event of oPlayer, write this:

var g, gdir; // it's necessary to make these temp vars because GM code remembers them in the scope even if you go into "with" for other objects. THIS ALSO ASSUMES YOU HAVE NO OTHER VARIABLES NAMED g OR gdir IN EITHER oPlayer OR oPlanet

with (oPlanet)
{
   // this assumes each planet has a mass variable, I used 1000
   g = mass/sqr(point_distance(x, y, oPlayer.x, oPlayer.y)); // handy built-in distance function
   gdir = point_direction(oPlayer.x, oPlayer.y, x, y); // VERY HANDY built-in get direction function from point 1 to point 2

   with (oPlayer)
     motion_add(gdir, g);
}

Now in the key down events for oPlayer, for all 4 arrow buttons, put this

hspeed += 0.2; // for right arrow
hspeed -= 0.2; // for left arrow
vspeed -= 0.2; // for up arrow
vspeed += 0.2; // for down arrow

So if you hold down the right arrow, each step will add 0.2 to your hspeed. Softcode this with whatever variable name you want.

I tested this exact code myself in a GM example. The room speed was 60, oPlanet mass was 1000, and things seemed to flow at a normal pace. One orbit took 1 or 2 seconds and I could easily break or re-enter orbit by pressing the arrows.

There is 1 caveat: If the player goes too close to the planet, such as sinking beneath its surface, it will get SO close to the center that gravity becomes extremely strong, which tends to make the ship go flying off in a random direction and never coming back. To avoid this, you should make a destruction event so that the ship just crashes when it hits or goes below a planet's surface, then restart the game. Use point_distance() to test if the distance is less than or equal to the planet's radius.

Finally, like I said, I use GM 8.1. I have never used GM 9, also known as GM Studio because it looks very bloated and way, way different than the nice interface of GMs 5, 6, and 8 that I am used to.

\$\endgroup\$
  • \$\begingroup\$ This looks promising!!! I will give it a go when I get home later. Thanks! \$\endgroup\$ – user59493 Sep 1 '15 at 4:38
  • \$\begingroup\$ Great!!! Thankyou! It still however suffers very minor Apsidal Precession. Any ideas? \$\endgroup\$ – user59493 Sep 1 '15 at 5:52
  • \$\begingroup\$ As for GameMaker Studio, TRY IT! You can easily change the skin back to GM8 and below easily. I personally feel the same way, and it looks no different after changing. \$\endgroup\$ – user59493 Sep 1 '15 at 5:58
  • \$\begingroup\$ Apsidal precession has occurred in every single one of my orbital sims no matter how I implement it. I'm pretty sure it comes from the discreet steps of calculations instead of being truly smooth and continuous. For example, this program calculates things in steps of 1 second. If you want to try, you could get it down to 1/100th of a second, which will be more "accurate" and have less precession, but will cost a lot more computation and could easily slow your game down. BTW this would make a great question on gamedev.SE, go ahead and post it. Some people might have a clever solution. \$\endgroup\$ – DrZ214 Sep 1 '15 at 21:14
  • \$\begingroup\$ Thanks for responding. Would you be able to answer such question for me? You know what you're doing. \$\endgroup\$ – user59493 Sep 1 '15 at 23:05
2
\$\begingroup\$

The first thing to do when you want to model space as it is is to understand Newtons laws of motion. An object keeps moving with a constant speed and direction unless a force acts on it.

That means you need to get away from the methodology of moving an object by changing its position. Give an object a speed in x- and y-direction and then change its position by its current speed every frame. When you want to change the motion of the object, change the speed through acceleration and deceleration.

Now you can add a gravity source by adding another constant acceleration to it every frame in addition to the acceleration from the player input.

When you want to simulate a point gravity source (like a planet), you first need to make the acceleration directed into the direction of the planet. You can do that by calculating the distance between gravity source and object with the Pythagorean law:

dist_x = object_x - source_x;
dist_y = object_y - source_y;
dist = Square_root(dist_x * dist_x + dist_y * dist_y);

Then you can calculate the horizontal and vertical portion of the acceleration vector by dividing each axis distance by the total distance:

acceleration_x = dist_x / dist;
acceleration_y = dist_y / dist;

You now have a constant acceleration away from the gravity source. But you want attraction, not repelling, so you need to invert it:

acceleration_x = -acceleration_x;
acceleration_y = -acceleration_y;

But keep in mind that in astrophysics, the magnitude of gravity is reduced by the distance squared. Also, different objects have different mass which means they are stronger gravity sources:

 gravity_power = source_mass / (dist * dist);
 acceleration_x = acceleration_x / gravity_power;
 acceleration_y = acceleration_y / gravity_power;

You should now have a proper simulation of orbital mechanics.

\$\endgroup\$
  • \$\begingroup\$ Hmmm... I love reading this sort of stuff. :P Lets see what I can do in Game Maker and I'll get back to you. \$\endgroup\$ – user59493 Feb 14 '15 at 10:56
  • \$\begingroup\$ Also Philipp, is source_x, source_y | object_x, object_y referring to the Satellite, or the Body? And what is gravity_power, G-Force? Like Earths 9.81 m/s? \$\endgroup\$ – user59493 Feb 14 '15 at 11:01
  • \$\begingroup\$ Hmm... Well... I sort of got it working. Except I don't orbit the Body. I just sink into it. As if I immediately dropped my velocity to 0m/s in mid air. \$\endgroup\$ – user59493 Feb 14 '15 at 11:21
  • \$\begingroup\$ I literally typed word for word what you wrote, apparently a source_mass of around 5000 makes you move smoothy. (I don't want to wait 90 minutes for an orbit) Then, I wrote x = x + acceleration_x | y = y + acceleration_y And I sink. 0_0 \$\endgroup\$ – user59493 Feb 14 '15 at 11:28
  • \$\begingroup\$ @FinnRayment Add the acceleration to the current speed of the object, not its position. \$\endgroup\$ – Philipp Feb 14 '15 at 13:08
0
\$\begingroup\$

I've found that motion_add behaves weirdly for simple orbital mechanics. There's the precession problem and acceleration is much faster when approaching the object you're using as the gravitational source.

This code gets rid of the precession and the velocity of the orbiting object is more manageable when approaching the planet:

object = obj_player;
source = obj_planet;
ddist = point_distance(object.x, object.y, source.x, source.y)
dsquare = ddist * ddist
grav_power = source.mass / dsquare;
ad = point_direction(object.x, object.y, source.x, source.y)
cx = cos(pi / 180 * ad)
cy = sin(pi / 180 * ad)
hspeed += grav_power*cx
vspeed -= grav_power*cy

Just copy it into a script file in GameMaker and drag it into the step event of your orbiting object.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy