Orbital gravity – code sample

So here the actionscript code to create that typical orbit effect! It’s kinda hard to do and there are different ways to let an object fly around a planet.
This code should also work on very fast objects.
Basically, the most important things are:
1. apply some damping to make sure the incoming speed of an object will be reduced.
2. ApplyForce must be well calculated for every angle.
3. To prevent an object from being escaped from a planet, ApplyForce must be stopped based upon old velocity / distance and current velocity / distance.
I am sure there is another way, which is more accurate but at the end, this simulation should all about ‘is it fun?’ and ‘does it feel right? ‘ :-)


package {
	import flash.display.*;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	import Box2D.Dynamics.Joints.*;
	import flash.sampler.NewObjectSample;
	/*
		all code was provided through 

http://www.emanueleferonato.com/2012/03/28/simulate-radial-gravity-also-know-as-planet-gravity-with-box2d-as-seen-on-angry-birds-space/

		So Emanuele Feronato is getting credit for all code. I just added some extra stuff in the update loop to make orbits possible at most speeds...
		
	*/
	public class Main extends Sprite {
		private var world:b2World=new b2World(new b2Vec2(0,0),true);
		private var worldScale:Number=30;
		private var planetVector:Vector.=new Vector.();
		private var debrisVector:Vector.=new Vector.();
		private var orbitCanvas:Sprite=new Sprite();
		private var oldDistance:Number = 0 ;
		private var newSprite:Sprite;
		private var doMoveLeft:Boolean = false;
		private var flt:Number = 0;
		public function Main() {
			addChild(orbitCanvas);
			orbitCanvas.graphics.lineStyle(1,0xff0000);
			debugDraw();
			addPlanet(400,300,90);//90
			//addPlanet(800,300,45);//90
			//addPlanet(480,120,45);
			addEventListener(Event.ENTER_FRAME,update);
			stage.addEventListener(MouseEvent.CLICK,createDebris);
			
			
			newSprite = new Sprite();
			addChild(newSprite);
			var mn:moveLeft = new moveLeft();
			addChild(mn);
			mn.addEventListener(MouseEvent.CLICK, goLeft);
			
		}
		private function goLeft(e:MouseEvent):void{
			trace("click");
			doMoveLeft = !doMoveLeft;
		}
		private function createDebris(e:MouseEvent):void {						
			addBox(mouseX,mouseY,20,20);
			trace(mouseX, mouseY);			
			newSprite.graphics.clear();
			
		}
		private function addPlanet(pX:Number,pY:Number,r:Number):void {
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.restitution=0;
			fixtureDef.density=1;
			var circleShape:b2CircleShape=new b2CircleShape(r/worldScale);
			fixtureDef.shape=circleShape;
			var bodyDef:b2BodyDef=new b2BodyDef();
			bodyDef.userData=new Sprite();
			bodyDef.position.Set(pX/worldScale,pY/worldScale);
			var thePlanet:b2Body=world.CreateBody(bodyDef);
			planetVector.push(thePlanet);
			thePlanet.CreateFixture(fixtureDef);
			orbitCanvas.graphics.drawCircle(pX,pY,r*3);
		}
		private function addBox(pX:Number,pY:Number,w:Number,h:Number):void {
			var polygonShape:b2PolygonShape = new b2PolygonShape();
			//var polygonShape:b2CircleShape = new b2CircleShape();
			//polygonShape.SetRadius(w/worldScale/2);
			polygonShape.SetAsBox(w/worldScale/2,h/worldScale/2);
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.density=1.0;
			fixtureDef.friction=1;
			fixtureDef.restitution=0.1;
			fixtureDef.shape=polygonShape;
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type=b2Body.b2_dynamicBody;
			bodyDef.position.Set(pX/worldScale,pY/worldScale);
			var box:b2Body=world.CreateBody(bodyDef);
			
			var newobject:Object = new Object();
			newobject.oldvel = 0;
			newobject.velchange = 0;
			newobject.oldDis = 0;
			box.SetUserData(newobject);
			debrisVector.push(box);
			box.ApplyForce(new b2Vec2(400,0), box.GetWorldCenter());
			
			box.CreateFixture(fixtureDef);
		}
		private function debugDraw():void {
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(worldScale);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
			debugDraw.SetFillAlpha(0.5);
			world.SetDebugDraw(debugDraw);
		}
		private function convertToRange( OldValue :Number , OldMin :Number , OldMax :Number , NewMin :Number , NewMax:Number ) :Number
		{
		
			var res:Number = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin;
			if(OldMin == 0 && OldMax == 0){
				res = 0.0;
			}        
			return res;
		
		}		
		private function update(e:Event):void {
			world.Step(1/60, 10, 10);
			world.ClearForces();
			
			for (var i:int=0; i debrisVector[i].GetLinearVelocity().Length()){
							var verschil2:Number = (debrisVector[i].GetUserData().oldvel - debrisVector[i].GetLinearVelocity().Length()) * 1.0;
							
							var newF:b2Vec2 = new b2Vec2(F.x * (debrisVector[i].GetLinearVelocity().Length() * (verschil2 * 2)),
														 F.y * (debrisVector[i].GetLinearVelocity().Length() * (verschil2 * 2)));
														 
							//compare previous distance with new current distance...if the difference is higher, that means, we are going up
							//again, which is NOT what we want. That will give an annoying elastic effect and will make body escape from planet.
							var diffDistance:Number = debrisVector[i].GetUserData().oldDis - finalDistance; 
														
							if(diffDistance > 0){
								//red = we must apply some add. force to make sure body goes back to planet.
								//BTW, here one must add some extra code to compare last velocity and current velocity, to make sure
								//we eliminate small hicks...
								var subf:b2Vec2 = new b2Vec2(newF.x * gravityStrenght , newF.y * gravityStrenght );								
								SUPERFORCE.Add(subf);
							}
							  
							var mm2:Number = convertToRange(speedD , 0, 45, 2,3);  
							var dampvalue2:Number = i2*0.0314 / mm2 * speedD/i2;
							
							debrisVector[i].SetLinearDamping(dampvalue2*2 );
							
							if(diffDistance < -0.0){
								//orange = body goes up...so dont apply anti force!
								newSprite.graphics.beginFill(0xFF9900);
         						newSprite.graphics.drawCircle(debrisVector[i].GetPosition().x * worldScale, debrisVector[i].GetPosition().y * worldScale, 2);
         						newSprite.graphics.endFill();
								
							}
							else{
								//red = body needs to be forced someway...
								newSprite.graphics.beginFill(0xFF0000);
         						newSprite.graphics.drawCircle(debrisVector[i].GetPosition().x * worldScale, debrisVector[i].GetPosition().y * worldScale, 2);
         						newSprite.graphics.endFill();						
							}							
						}
						else{
							newSprite.graphics.beginFill(0x00FF00);
         					newSprite.graphics.drawCircle(debrisVector[i].GetPosition().x * worldScale, debrisVector[i].GetPosition().y * worldScale, 2);
         					newSprite.graphics.endFill();							
						}								

						debrisVector[i].ApplyForce(SUPERFORCE, debrisVector[i].GetWorldCenter());
						//store old data into variable, usefull to compare in loop
						debrisVector[i].GetUserData().oldvel = debrisVector[i].GetLinearVelocity().Length();
						debrisVector[i].GetUserData().oldDis = finalDistance;
					}
				}
			}
			world.DrawDebugData();
		}
	}
}

This code will then look like this!
(must download Box2d btw!)
(need Flash for this)


Oh..as a side note!..For all dutch readers interested in physics in games..,
You may find this link interesting to read!

http://www.control-online.nl/gamesindustrie/2012/05/22/column-physics-in-games-door-mark-overmars/

5 Thoughts on “Orbital gravity – code sample

  1. Getting lots of syntax errors

    • Am I meant to change anything to get this to work?

      • Hi DG!
        you add this code as a class to an empty Flash file.
        So in ‘properties’ enter ‘Main’ in the Class field.
        The code above should be put in a textfile called ‘Main.as’. After this, this should run fine!
        (don’t put this code into a timeline frame. That won’t work.)
        Hope this helps!

        • Hi thanks for reply, my compliments on the website.

          I am completely new to this, I changed the class field. I have the new box2d files in the same folder, and I am still receiving syntax errors.

          Would it be possible for you to upload your source files or a small tutorial on simple set up for beginners like myself.

          King regards

Post Navigation