Simulate radial gravity (also known as “planet gravity”) with Box2D as seen on Angry Birds Space

Read all posts about "" game

With the launch of Angry Birds Space I am sure you are wondering how to simulate planet gravity with Box2D.

And guess what… the basics are very easy.

First, in space there’s no gravity, so you will create a b2World world without gravity this way:

private var world:b2World=new b2World(new b2Vec2(0,0),true);

Then, it’s just a matter of applying Forces according to bodies and planets position.

Look at this script:

package {
	import flash.display.Sprite;
	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.*;
	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();
		public function Main() {
			addChild(orbitCanvas);
			orbitCanvas.graphics.lineStyle(1,0xff0000);
			debugDraw();
			addPlanet(180,240,90);
			addPlanet(480,120,45);
			addEventListener(Event.ENTER_FRAME,update);
			stage.addEventListener(MouseEvent.CLICK,createDebris);
		}
		private function createDebris(e:MouseEvent):void {
			addBox(mouseX,mouseY,20,20);
		}
		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();
			polygonShape.SetAsBox(w/worldScale/2,h/worldScale/2);
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.density=1;
			fixtureDef.friction=1;
			fixtureDef.restitution=0;
			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);
			debrisVector.push(box);
			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 update(e:Event):void {
			world.Step(1/30, 10, 10);
			world.ClearForces();
			for (var i:int=0; i

The whole code just create static bodies (planets) and let you place dynamic bodies (debris) with the click of the mouse.

The only interesting part of the script is the for loop in the update function, which I'll explain line by line:

for (var i:int=0; i

Loop which scans for all debris previously stored in debrisVector Vector declared at line 14 and updated at line 54

var debrisPosition:b2Vec2=debrisVector[i].GetWorldCenter();

Gets debris position

for (var j:int=0; j

Loop which scans for all planets previously stored in planetVector Vector declared at line 13 and updated at line 38

var planetShape:b2CircleShape=planetVector[j].GetFixtureList().GetShape() as b2CircleShape;

I need to know the mass of the planet because the bigger the mass, the more intense the gravity attraction. Unfortunately Box2D static bodies do not have mass, so I need to get the circle shape of the planet...

var planetRadius:Number=planetShape.GetRadius();

... and get its radius. So in this case the bigger the radius, the more intense the gravity attraction

var planetPosition:b2Vec2=planetVector[j].GetWorldCenter();

Gets planet position

var planetDistance:b2Vec2=new b2Vec2(0,0);

Creates a new b2Vec2 variable which will store the distance between the planet and the debris

planetDistance.Add(debrisPosition);

Adds debris coordinates, then...

planetDistance.Subtract(planetPosition);

... subtracts planet coordinates

var finalDistance:Number=planetDistance.Length();

Calculates the distance between the planet and the debris

if (finalDistance<=planetRadius*3) {

Checks if the debris should be affected by planet gravity (in this case, the debris must be within a radius of three times the planet radius)

planetDistance.NegativeSelf();

Inverts planet distance, so that the force will move the debris in the direction of the planet origin

var vecSum:Number=Math.abs(planetDistance.x)+Math.abs(planetDistance.y);

Gets the sum of distance vector components. I will need this to make gravity attraction weaker when the debris is far from the planet, and stronger when the debris is getting close to the planet

planetDistance.Multiply((1/vecSum)*planetRadius/finalDistance);

This is the final formula to make the gravity weaker as we move far from the planet

debrisVector[i].ApplyForce(planetDistance,debrisVector[i].GetWorldCenter());

And finally the force can be applied to debris

This is the result:

Click to create debris.

Download the source code.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stairs
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers