Following a body with the camera in Box2D
If you want to make a good game, a good camera movement is necessary.
This time we’ll learn to follow a Box2D object with the camera. Box2D does not have a “camera”, so we will have to move the stage according to body position. This is the same script as Real world catapult using Box2D – cleaner code, I just placed a gradient background to help you seeing how the camera is following the objects.
The main idea is following the catapult until it fires the cannonball, then following the cannonball.
This is the result:
Left and right to move, spacebar to fire
And this is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | package { import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Common.Math.*; import Box2D.Dynamics.Joints.*; public class main extends Sprite { public var world:b2World=new b2World(new b2Vec2(0,10.0),true); public var world_scale:int=30; var the_cannonball_itself:b2Body; var catapult_chassis_body:b2Body; var catapult_arm_body:b2Body; var rear_wheel_body:b2Body; var front_wheel_body:b2Body; var arm_revolute_joint:b2RevoluteJoint; var front_wheel_revolute_joint:b2RevoluteJoint; var rear_wheel_revolute_joint:b2RevoluteJoint; var left_key_pressed:Boolean=false; var right_key_pressed:Boolean=false; var following_catapult:Boolean=true; var bg:background_mc = new background_mc(); public function main():void { addChild(bg); debug_draw(); the_ground(); the_catapult_body(); the_catapult_arm(); the_catapult_motor(); the_wheels(); the_wheel_motors(); the_cannonball(); addEventListener(Event.ENTER_FRAME, update); stage.addEventListener(KeyboardEvent.KEY_DOWN, key_down); stage.addEventListener(KeyboardEvent.KEY_UP, key_up); } public function the_cannonball():void { var cannonball:b2BodyDef= new b2BodyDef(); cannonball.position.Set(90/world_scale, 90/world_scale); cannonball.type=b2Body.b2_dynamicBody; var ball:b2CircleShape=new b2CircleShape(10/world_scale); var cannonball_fixture:b2FixtureDef = new b2FixtureDef(); cannonball_fixture.shape=ball; cannonball_fixture.friction=0.9; cannonball_fixture.density=20; cannonball_fixture.restitution=0.5; the_cannonball_itself=world.CreateBody(cannonball); the_cannonball_itself.CreateFixture(cannonball_fixture); } public function the_wheel_motors():void { var front_wheel_joint:b2RevoluteJointDef = new b2RevoluteJointDef(); front_wheel_joint.enableMotor=true; front_wheel_joint.Initialize(catapult_chassis_body, front_wheel_body,new b2Vec2(0,0)); front_wheel_joint.localAnchorA=new b2Vec2(80/world_scale,0); front_wheel_joint.localAnchorB=new b2Vec2(0,0); front_wheel_revolute_joint=world.CreateJoint(front_wheel_joint) as b2RevoluteJoint; front_wheel_revolute_joint.SetMaxMotorTorque(1000000); // var rear_wheel_joint:b2RevoluteJointDef = new b2RevoluteJointDef(); rear_wheel_joint.enableMotor=true; rear_wheel_joint.Initialize(catapult_chassis_body, rear_wheel_body,new b2Vec2(0,0)); rear_wheel_joint.localAnchorA=new b2Vec2(-80/world_scale,0); rear_wheel_joint.localAnchorB=new b2Vec2(0,0); rear_wheel_revolute_joint=world.CreateJoint(rear_wheel_joint) as b2RevoluteJoint; rear_wheel_revolute_joint.SetMaxMotorTorque(1000000); } public function the_wheels():void { var rear_wheel:b2BodyDef= new b2BodyDef(); rear_wheel.position.Set(250/world_scale, 200/world_scale); rear_wheel.type=b2Body.b2_dynamicBody; var rear_wheel_shape:b2CircleShape=new b2CircleShape(40/world_scale); var rear_wheel_fixture:b2FixtureDef = new b2FixtureDef(); rear_wheel_fixture.shape=rear_wheel_shape; rear_wheel_fixture.friction=0.9; rear_wheel_fixture.density=30; rear_wheel_fixture.restitution=0.1; rear_wheel_body=world.CreateBody(rear_wheel); rear_wheel_body.CreateFixture(rear_wheel_fixture); // var front_wheel:b2BodyDef= new b2BodyDef(); front_wheel.position.Set(450/world_scale, 200/world_scale); front_wheel.type=b2Body.b2_dynamicBody; var front_wheel_shape:b2CircleShape=new b2CircleShape(40/world_scale); var front_wheel_fixture:b2FixtureDef = new b2FixtureDef(); front_wheel_fixture.shape=front_wheel_shape; front_wheel_fixture.friction=0.9; front_wheel_fixture.density=30; front_wheel_fixture.restitution=0.1; front_wheel_body=world.CreateBody(front_wheel); front_wheel_body.CreateFixture(front_wheel_fixture); } public function the_catapult_motor():void { var arm_joint:b2RevoluteJointDef = new b2RevoluteJointDef(); arm_joint.enableMotor=true; arm_joint.enableLimit=true; arm_joint.Initialize(catapult_chassis_body, catapult_arm_body,new b2Vec2(0,0)); arm_joint.localAnchorA=new b2Vec2(-80/world_scale,-90/world_scale); arm_joint.localAnchorB=new b2Vec2(60/world_scale,0); arm_revolute_joint=world.CreateJoint(arm_joint) as b2RevoluteJoint; arm_revolute_joint.SetMotorSpeed(1000); arm_revolute_joint.SetLimits(-Math.PI,Math.PI/3); arm_revolute_joint.SetMaxMotorTorque(1); } public function the_catapult_arm():void { var catapult_arm:b2BodyDef = new b2BodyDef(); catapult_arm.allowSleep=false; catapult_arm.position.Set(210/world_scale,110/world_scale); catapult_arm.type=b2Body.b2_dynamicBody; var arm_part:b2PolygonShape = new b2PolygonShape(); arm_part.SetAsOrientedBox(150/world_scale, 10/world_scale, new b2Vec2(0,0),0); var arm_part_fixture:b2FixtureDef = new b2FixtureDef(); arm_part_fixture.shape=arm_part; arm_part_fixture.friction=0.9; arm_part_fixture.density=5; arm_part_fixture.restitution=0.1; var stopper:b2PolygonShape = new b2PolygonShape(); stopper.SetAsOrientedBox(10/world_scale, 20/world_scale, new b2Vec2(-140/world_scale,-30/world_scale),0); var stopper_fixture:b2FixtureDef = new b2FixtureDef(); stopper_fixture.shape=stopper; stopper_fixture.friction=0.9; stopper_fixture.density=10; stopper_fixture.restitution=0.1; catapult_arm_body=world.CreateBody(catapult_arm); catapult_arm_body.CreateFixture(arm_part_fixture); catapult_arm_body.CreateFixture(stopper_fixture); } public function the_catapult_body():void { var catapult_body:b2BodyDef = new b2BodyDef(); catapult_body.position.Set(350/world_scale,200/world_scale); catapult_body.type=b2Body.b2_dynamicBody; var main_part:b2PolygonShape = new b2PolygonShape(); main_part.SetAsOrientedBox(125/world_scale, 20/world_scale, new b2Vec2(0,0),0); var chassis_fixture:b2FixtureDef = new b2FixtureDef(); chassis_fixture.shape=main_part; chassis_fixture.friction=0.9; chassis_fixture.density=50; chassis_fixture.restitution=0.1; var fixed_arm:b2PolygonShape = new b2PolygonShape(); fixed_arm.SetAsOrientedBox(20/world_scale, 60/world_scale, new b2Vec2(-80/world_scale,-40/world_scale),0); var fixed_arm_fixture:b2FixtureDef = new b2FixtureDef(); fixed_arm_fixture.shape=fixed_arm; fixed_arm_fixture.friction=0.9; fixed_arm_fixture.density=1; fixed_arm_fixture.restitution=0.1; catapult_chassis_body=world.CreateBody(catapult_body); catapult_chassis_body.CreateFixture(chassis_fixture); catapult_chassis_body.CreateFixture(fixed_arm_fixture); } public function the_ground():void { var ground:b2BodyDef= new b2BodyDef(); ground.position.Set(250/world_scale, 400/world_scale); var my_box:b2PolygonShape = new b2PolygonShape(); my_box.SetAsBox(5000/world_scale, 15/world_scale); var ground_fixture:b2FixtureDef = new b2FixtureDef(); ground_fixture.shape=my_box; ground_fixture.friction=0.9; ground_fixture.restitution=0.1; var the_ground_itself:b2Body=world.CreateBody(ground); the_ground_itself.CreateFixture(ground_fixture); } public function key_up(event:KeyboardEvent):void { switch (event.keyCode) { case 39 : right_key_pressed=false; break; case 37 : left_key_pressed=false; break; } } public function key_down(event:KeyboardEvent):void { switch (event.keyCode) { case 39 : right_key_pressed=true; left_key_pressed=false; break; case 37 : left_key_pressed=true; right_key_pressed=false; break; case 32 : arm_revolute_joint.SetMaxMotorTorque(10000); following_catapult=false; break; } } public function debug_draw():void { var debug_draw:b2DebugDraw = new b2DebugDraw(); var debug_sprite:Sprite = new Sprite(); addChild(debug_sprite); debug_draw.SetSprite(debug_sprite); debug_draw.SetDrawScale(world_scale); debug_draw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit); debug_draw.SetFillAlpha(0.5); world.SetDebugDraw(debug_draw); } public function set_motor_speed():void { var current_speed:Number; if (right_key_pressed) { current_speed=1; } if (left_key_pressed) { current_speed=-1; } if (! right_key_pressed&&! left_key_pressed) { current_speed=rear_wheel_revolute_joint.GetMotorSpeed()*0.9; if (Math.abs(current_speed)<0.1) { current_speed=0; } } rear_wheel_revolute_joint.SetMotorSpeed(current_speed); front_wheel_revolute_joint.SetMotorSpeed(current_speed); } public function update(e:Event):void { var pos_x:Number; var pos_y:Number; set_motor_speed(); world.Step(1/30,10,10); if (following_catapult) { pos_x=catapult_chassis_body.GetWorldCenter().x*world_scale; pos_y=catapult_chassis_body.GetWorldCenter().y*world_scale; } else { pos_x=the_cannonball_itself.GetWorldCenter().x*world_scale; pos_y=the_cannonball_itself.GetWorldCenter().y*world_scale; } x=stage.stageWidth/2-pos_x; y=stage.stageHeight/2-pos_y; world.ClearForces(); world.DrawDebugData(); } } } |
Download the source code. Next time, smarter camera movement and fully commented code.
They can be easily customized to meet the unique requirements of your project.















(7 votes, average: 4.71 out of 5)









This post has 8 comments
Quintus
Naijs
Ramon Fritsch
Hello mate!
Could you please send yout e-mail to me? I would like to speak with you about your game partnership. I am interested on that and I would really be pleased if you could help me on that subject.
cheers
superdean
i sense a kitten cannon like game in the works
Emanuele Feronato
@superdean: maybe some more realistic…
@ramon: info[at]emanueleferonato.com
Emanuele Feronato - italian geek and PROgrammer
[...] Following a body with the camera in Box2D [...]
AlexRath
Hey, I had another Idea for the Camera Following Algorithm. It uses an Focus Point and some more Easing for Camera Following.
Anyway, I zipped the rewritten Version (since I added 2 Helper Classes) and should be available to download here: http://plunder.com/fc94de9042
Warll
Emanuele it would be nice if you mentioned which version of the box2d library you are using. Judging from the debug draw’s pink colouring on active objects it would appear that you are using 2.1a.
I bring this up mainly because I spent most of yesterday pulling my hair out after every single box2d tutorial I used (Even hello worlds) wouldn’t even compile, it turns out that using brand new flex 4 and alpha box2d isn’t going to luck you into too much compatibility.
Arindam
What is this, can’t control the game