So, I may have bitten off a bit more than I could chew in this post, but it is something that has been an intriguing thought to me for some time: how can I simulate the effect, or pull, of gravitational forces between different objects on my stage? Obviously, if you read my previous post, you know that I have had some fascination with orbits and circular motions, but I am much more interested in paths that appear to be natural — almost evolving, if you will.
This got me to contemplating that, in our universe, every object acts upon every other in some way: keeping our planets in orbit around the sun while helping each other to retain their individual satellites and keep from hurtling into outer space. Embodying the interactions of the various bodies on one another and trying to come up with a simple enough algorithm that will simulate a fluid motion while not overloading the Flash player with unnecessary overhead was my goal. I have some work yet to do, but I thought I would at least share my concepts with you and see what improvements can be made whilst still keeping things lightweight.
In this sample code, there are two main things that I have accomplished. First, I have created a Actionscript object that serves as the building block for a planet (or satellite of some sort). This object is created by simply passing the application object (which houses the array of all objects on the stage for interaction) and the radius you wish for this object to have. Determining the size of your satellite is extremely important to getting the desired effect, because the gravity it exudes upon all other objects is proportional to its size and distance from them (unlike true gravitational fields, we allow ours to degrade significantly faster than that of a real planet for ease of calculation — in fact, it is shown that the earth’s gravitational field on the orbiting space shuttle crew pulls with about 90% of the strength it would have on the same person standing atop the earth’s crust, but because of the nature of the orbit, the crew members are in perpetual free-fall, simulating the feeling of weightlessness).
With an understanding of how these gravitational fields would work, we can gather assumptions for the exceptions we are willing to make. So, rather than trying to calculate true gravitational forces across the whole of a SWF file, I have opted to take the route of degrading 1% for every 15 pixels of distance there is between a body and the object upon which it is exerting its force. Along the same lines, I have allowed for no specification of true density into our calculations — only size — although, this wouldn’t be an enormous task to add in the future. Also, for a reference point of calculation, I have chosen that a planet with a diameter of 30 would pull at a rate of 1 pixel per second and every other object will pull proportional to that constant (we have to have somewhere to start, right?). So, here is our simplistic way to see how strong of a gravitational force an individual object will have:
protected function calculateGravity() :void
{
// Let's default average gravity based on a 30px diameter planet
var grav_ratio :Number = (this.radius * 2) / 30;
// Increase in gravity should be 1 pixel per second (pixels per second / frame rate)
var pixels_per_second :Number = 1;
var pixels_per_frame :Number = pixels_per_second / 30;
this.gravity = pixels_per_frame * grav_ratio;
}
Once we have the personal gravity of the object calculated, we simply loop over all other object in the SWF and modify their velocity slightly whenever we enter the frame. To do so, we attach the following code to an ENTER_FRAME Event:
protected function pull(e :Event) :void
{
for (var i :int = 0; i < this.swf.objcts.length; i++)
{
var o :Object = this.swf.objects[i];
// Be sure we're not acting on this object or any marked as immune
if (o != this && o.immune == false)
{
var xDiff :Number = this.x - o.x;
var yDiff :Number = this.y - o.y;
var dist :Number = Math.sqrt((xDiff * xDiff) + (yDiff * yDiff));
var modifier :Number = this.gravity;
for (var x :Number = 0; x < dist; x += 15)
{
modifier *= .99;
}
var xChange :Number = (modifier / dist) * xDiff;
var yChange :Number = (modifier / dist) * yDiff;
o.velX += xChange;
o.velY += yChange;
}
}
}
That's really all there is to it. Each object then moves themselves based on their current velX and velY values, and we also manually set which objects we want to act upon others but not be affected by the gravitational pulls themselves. So, in the base example you can link to at the end of this post, you will notice that, though it pulls strongly on its satellites, the central planet is not affected by the gravity of the moons. If you look at the code, you will see that this can easily be remedied by commenting out the line declaring the central planet to be immune.
One other piece of information worth noting is that, depending on what reaction you want your satellites to have, you need to carefully specify what starting velocity and trajectory you wish them to have (by manually setting the velX and velY variables). If you do not do this, the expected outcome of the satellites coming crashing into the predominant body will occur. To avoid this catastrophe, you need to assign values that will have the satellite passing next to (through the atmosphere, as it were) its object of origin, and the gravitational pulls will take care of the rest.
I hope this is as interesting to some of you as it is to me. As I mentioned before, I have a lot of honing and more calculations for this little algorithm, but when I wrote this up a couple hours ago, I was quite excited at the initial outcome, so I wanted to share. Who knows what can be done next?
Sample SWF: GravityStudy.swf
Full Source Code: Gravity Study SWF Source
This is really cool. Its very rare when I get to play around with code ideas that don’t go into a specific project or client’s work. Glad to see you sharing. It would be interesting to see this in PaperVision or some 3d ish environment. It would be great to simulate a simple galaxy based on the sizes of the planets and not a canned flight path. I am a very big fan of this site: http://taggalaxy.de. Thanks again for sharing…
Thanks so much for the comment. I love playing with new ideas (as unorthodox as mine may be sometimes), and I’ve found that there is nothing better than to share some ideas with other developers and see what the collective input may be. I would LOVE to do the 3d type rendering, but time doesn’t allow me that type of luxury at the moment. I will definitely file that thought and address it when I can actually get a little Flash focus in my job instead of just in my hobby (wishful thinking).