Applications of Physics

Exclusive offer: get 50% off this eBook here
AndEngine for Android Game Development Cookbook

AndEngine for Android Game Development Cookbook — Save 50%

Over 70 highly effective recipes with real-world examples to get to grips with the powerful capabilities of AndEngine and GLES 2 with this book and ebook.

$26.99    $13.50
by Brian Broyles Jayme Schroeder | February 2013 | Cookbooks Games Open Source

In this article by Jayme Schroeder and Brian Broyles the authors of AndEngine for Android Game Development Cookbook, we are going to see Physics-based games provide players with a unique type of experience not encountered in many other genres. This article covers the use of AndEngine's Box2D physics extension. Our recipes include:

  • Introduction to the Box2D physics extension

  • Understanding different body types

  • Creating category-filtered bodies

  • Creating multiple-fixture bodies

  • Creating unique bodies by specifying vertices

  • Using forces, velocities, and torque

(For more resources related to this topic, see here.)

Introduction to the Box2D physics extension

Physics-based games are one of the most popular types of games available for mobile devices. AndEngine allows the creation of physics-based games with the Box2D extension. With this extension, we can construct any type of physically realistic 2D environment from small, simple simulations to complex games. In this recipe, we will create an activity that demonstrates a simple setup for utilizing the Box2D physics engine extension. Furthermore, we will use this activity for the remaining recipes in this article.

Getting ready...

First, create a new activity class named PhysicsApplication that extends BaseGameActivity and implements IAccelerationListener and IOnSceneTouchListener.

How to do it...

Follow these steps to build our PhysicsApplication activity class:

  1. Create the following variables in the class:

    public static int cameraWidth = 800; public static int cameraHeight = 480; public Scene mScene; public FixedStepPhysicsWorld mPhysicsWorld; public Body groundWallBody; public Body roofWallBody; public Body leftWallBody; public Body rightWallBody;

  2. We need to set up the foundation of our activity. To start doing so, place these four, common overridden methods in the class to set up the engine, resources, and the main scene:

    @Override public Engine onCreateEngine(final EngineOptions pEngineOptions) { return new FixedStepEngine(pEngineOptions, 60); } @Override public EngineOptions onCreateEngineOptions() { EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_SENSOR, new FillResolutionPolicy(), new Camera(0,0, cameraWidth, cameraHeight)); engineOptions.getRenderOptions().setDithering(true); engineOptions.getRenderOptions(). getConfigChooserOptions() .setRequestedMultiSampling(true); engineOptions.setWakeLockOptions( WakeLockOptions.SCREEN_ON); return engineOptions; } @Override public void onCreateResources(OnCreateResourcesCallback pOnCreateResourcesCallback) { pOnCreateResourcesCallback. onCreateResourcesFinished(); } @Override public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) { mScene = new Scene(); mScene.setBackground(new Background(0.9f,0.9f,0.9f)); pOnCreateSceneCallback.onCreateSceneFinished(mScene); }

  3. Continue setting up the activity by adding the following overridden method, which will be used to populate our scene:

    @Override public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) { }

  4. Next, we will fill the previous method with the following code to create our PhysicsWorld object and Scene object:

    mPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0f,-SensorManager.GRAVITY_EARTH*2), false, 8, 3); mScene.registerUpdateHandler(mPhysicsWorld); final FixtureDef WALL_FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.1f, 0.5f); final Rectangle ground = new Rectangle(cameraWidth / 2f, 6f, cameraWidth - 4f, 8f, this.getVertexBufferObjectManager()); final Rectangle roof = new Rectangle(cameraWidth / 2f, cameraHeight – 6f, cameraWidth - 4f, 8f, this.getVertexBufferObjectManager()); final Rectangle left = new Rectangle(6f, cameraHeight / 2f, 8f, cameraHeight - 4f, this.getVertexBufferObjectManager()); final Rectangle right = new Rectangle(cameraWidth - 6f, cameraHeight / 2f, 8f, cameraHeight - 4f, this.getVertexBufferObjectManager()); ground.setColor(0f, 0f, 0f); roof.setColor(0f, 0f, 0f); left.setColor(0f, 0f, 0f); right.setColor(0f, 0f, 0f); groundWallBody = PhysicsFactory.createBoxBody( this.mPhysicsWorld, ground, BodyType.StaticBody, WALL_FIXTURE_DEF); roofWallBody = PhysicsFactory.createBoxBody( this.mPhysicsWorld, roof, BodyType.StaticBody, WALL_FIXTURE_DEF); leftWallBody = PhysicsFactory.createBoxBody( this.mPhysicsWorld, left, BodyType.StaticBody, WALL_FIXTURE_DEF); rightWallBody = PhysicsFactory.createBoxBody( this.mPhysicsWorld, right, BodyType.StaticBody, WALL_FIXTURE_DEF); this.mScene.attachChild(ground); this.mScene.attachChild(roof); this.mScene.attachChild(left); this.mScene.attachChild(right); // Further recipes in this chapter will require us to place code here. mScene.setOnSceneTouchListener(this); pOnPopulateSceneCallback.onPopulateSceneFinished();

  5. The following overridden activities handle the scene touch events, the accelerometer input, and the two engine life cycle events—onResumeGame and onPauseGame. Place them at the end of the class to finish this recipe:

    @Override public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) { // Further recipes in this chapter will require us to place code here. return true; } @Override public void onAccelerationAccuracyChanged( AccelerationData pAccelerationData) {} @Override public void onAccelerationChanged( AccelerationData pAccelerationData) { final Vector2 gravity = Vector2Pool.obtain( pAccelerationData.getX(), pAccelerationData.getY()); this.mPhysicsWorld.setGravity(gravity); Vector2Pool.recycle(gravity); } @Override public void onResumeGame() { super.onResumeGame(); this.enableAccelerationSensor(this); } @Override public void onPauseGame() { super.onPauseGame(); this.disableAccelerationSensor(); }

How it works...

The first thing that we do is define a camera width and height. Then, we define a Scene object and a FixedStepPhysicsWorld object in which the physics simulations will take place. The last set of variables defines what will act as the borders for our physics-based scenes.

In the second step, we override the onCreateEngine() method to return a FixedStepEngine object that will process 60 updates per second. The reason that we do this, while also using a FixedStepPhysicsWorld object, is to create a simulation that will be consistent across all devices, regardless of how efficiently a device can process the physics simulation. We then create the EngineOptions object with standard preferences, create the onCreateResources() method with only a simple callback, and set the main scene with a light-gray background.

In the onPopulateScene() method, we create our FixedStepPhysicsWorld object that has double the gravity of the Earth, passed as an (x,y) coordinate Vector2 object, and will update 60 times per second. The gravity can be set to other values to make our simulations more realistic or 0 to create a zero gravity simulation. A gravity setting of 0 is useful for space simulations or for games that use a top-down camera view instead of a profile. The false Boolean parameter sets the AllowSleep property of the PhysicsWorld object, which tells PhysicsWorld to not let any bodies deactivate themselves after coming to a stop. The last two parameters of the FixedStepPhysicsWorld object tell the physics engine how many times to calculate velocity and position movements. Higher iterations will create simulations that are more accurate, but can cause lag or jitteriness because of the extra load on the processor. After creating the FixedStepPhysicsWorld object, we register it with the main scene as an update handler. The physics world will not run a simulation without being registered.

The variable WALL_FIXTURE_DEF is a fixture definition. Fixture definitions hold the shape and material properties of entities that will be created within the physics world as fixtures. The shape of a fixture can be either circular or polygonal. The material of a fixture is defined by its density, elasticity, and friction, all of which are required when creating a fixture definition. Following the creation of the WALL_FIXTURE_DEF variable, we create four rectangles that will represent the locations of the wall bodies. A body in the Box2D physics world is made of fixtures. While only one fixture is necessary to create a body, multiple fixtures can create complex bodies with varying properties.

Further along in the onPopulateScene() method, we create the box bodies that will act as our walls in the physics world. The rectangles that were previously created are passed to the bodies to define their position and shape. We then define the bodies as static, which means that they will not react to any forces in the physics simulation. Lastly, we pass the wall fixture definition to the bodies to complete their creation.

After creating the bodies, we attach the rectangles to the main scene and set the scene's touch listener to our activity, which will be accessed by the onSceneTouchEvent() method. The final line of the onPopulateScene() method tells the engine that the scene is ready to be shown.

The overridden onSceneTouchEvent() method will handle all touch interactions for our scene. The onAccelerationAccuracyChanged() and onAccelerationChanged() methods are inherited from the IAccelerationListener interface and allow us to change the gravity of our physics world when the device is tilted, rotated, or panned. We override onResumeGame() and onPauseGame() to keep the accelerometer from using unnecessary battery power when our game activity is not in the foreground.

There's more...

In the overridden onAccelerationChanged() method, we make two calls to the Vector2Pool class. The Vector2Pool class simply gives us a way of re-using our Vector2 objects that might otherwise require garbage collection by the system. On newer devices, the Android Garbage Collector has been streamlined to reduce noticeable hiccups, but older devices might still experience lag depending on how much memory the variables being garbage collected occupy.

Visit http://www.box2d.org/manual.htmlto see the Box2D User Manual. The AndEngine Box2D extension is based on a Java port of the official Box2D C++ physics engine, so some variations in procedure exist, but the general concepts still apply.

See also

  • Understanding different body types in this article.

Understanding different body types

The Box2D physics world gives us the means to create different body types that allow us to control the physics simulation. We can generate dynamic bodies that react to forces and other bodies, static bodies that do not move, and kinematic bodies that move but are not affected by forces or other bodies. Choosing which type each body will be is vital to producing an accurate physics simulation. In this recipe, we will see how three bodies react to each other during collision, depending on their body types.

Getting ready...

Follow the recipe in the Introduction to the Box2D physics extension section given at the beginning of this article to create a new activity that will facilitate the creation of our bodies with varying body types.

How to do it...

Complete the following steps to see how specifying a body type for bodies affects them:

  1. First, insert the following fixture definition into the onPopulateScene() method:

    FixtureDef BoxBodyFixtureDef = PhysicsFactory.createFixtureDef(20f, 0f, 0.5f);

  2. Next, place the following code that creates three rectangles and their corresponding bodies after the fixture definition from the previous step:

    Rectangle staticRectangle = new Rectangle(cameraWidth / 2f,75f,400f,40f,this.getVertexBufferObjectManager()); staticRectangle.setColor(0.8f, 0f, 0f); mScene.attachChild(staticRectangle); PhysicsFactory.createBoxBody(mPhysicsWorld, staticRectangle, BodyType.StaticBody, BoxBodyFixtureDef); Rectangle dynamicRectangle = new Rectangle(400f, 120f, 40f, 40f, this.getVertexBufferObjectManager()); dynamicRectangle.setColor(0f, 0.8f, 0f); mScene.attachChild(dynamicRectangle); Body dynamicBody = PhysicsFactory.createBoxBody(mPhysicsWorld, dynamicRectangle, BodyType.DynamicBody, BoxBodyFixtureDef); mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector( dynamicRectangle, dynamicBody); Rectangle kinematicRectangle = new Rectangle(600f, 100f, 40f, 40f, this.getVertexBufferObjectManager()); kinematicRectangle.setColor(0.8f, 0.8f, 0f); mScene.attachChild(kinematicRectangle); Body kinematicBody = PhysicsFactory.createBoxBody(mPhysicsWorld, kinematicRectangle, BodyType.KinematicBody, BoxBodyFixtureDef); mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector( kinematicRectangle, kinematicBody);

  3. Lastly, add the following code after the definitions from the previous step to set the linear and angular velocities for our kinematic body:

    kinematicBody.setLinearVelocity(-2f, 0f); kinematicBody.setAngularVelocity((float) (-Math.PI));

How it works...

In the first step, we create the BoxBodyFixtureDef fixture definition that we will use when creating our bodies in the second step. For more information on fixture definitions, see the Introduction to the Box2D physics extension recipe in this article.

In step two, we first define the staticRectangle rectangle by calling the Rectangle constructor. We place staticRectangle at the position of cameraWidth / 2f, 75f, which is near the lower-center of the scene, and we set the rectangle to have a width of 400f and a height of 40f, which makes the rectangle into a long, flat bar. Then, we set the staticRectangle rectangle's color to be red by calling staticRectangle. setColor(0.8f, 0f, 0f). Lastly, for the staticRectangle rectangle, we attach it to the scene by calling the mScene.attachChild() method with staticRectangle as the parameter. Next, we create a body in the physics world that matches our staticRectangle. To do this, we call the PhysicsFactory.createBoxBody() method with the parameters of mPhysicsWorld, which is our physics world, staticRectangle to tell the box to be created with the same position and size as the staticRectangle rectangle, BodyType. StaticBody to define the body as static, and our BoxBodyFixtureDef fixture definition.

Our next rectangle, dynamicRectangle, is created at the location of 400f and 120f, which is the middle of the scene slightly above the staticRectangle rectangle. Our dynamicRectangle rectangle's width and height are set to 40f to make it a small square. Then, we set its color to green by calling dynamicRectangle.setColor(0f, 0.8f, 0f) and attach it to our scene using mScene.attachChild(dynamicRectangle). Next, we create the dynamicBody variable using the PhysicsFactory.createBoxBody() method in the same way that we did for our staticRectangle rectangle. Notice that we set the dynamicBody variable to have BodyType of DynamicBody. This sets the body to be dynamic. Now, we register PhysicsConnector with the physics world to link dynamicRectangle and dynamicBody. A PhysicsConnecter class links an entity within our scene to a body in the physics world, representing the body's realtime position and rotation in our scene.

Our last rectangle, kinematicRectangle, is created at the location of 600f and 100f, which places it on top of our staticRectangle rectangle toward the right-hand side of the scene. It is set to have a height and width of 40f, which makes it a small square like our dynamicRectangle rectangle. We then set the kinematicRectangle rectangle's color to yellow and attach it to our scene. Similar to the previous two bodies that we created, we call the PhysicsFactory.createBoxBody() method to create our kinematicBody variable. Take note that we create our kinematicBody variable with a BodyType type of KinematicBody. This sets it to be kinematic and thus moved only by the setting of its velocities. Lastly, we register a PhysicsConnector class between our kinematicRectangle rectangle and our kinematicBody body type.

In the last step, we set our kinematicBody body's linear velocity by calling the setLinearVelocity() method with a vector of -2f on the x axis, which makes it move to the left. Finally, we set our kinematicBody body's angular velocity to negative pi by calling kinematicBody.setAngularVelocity((float) (-Math.PI)). For more information on setting a body's velocities, see the Using forces, velocities, and torque recipe in this article.

There's more...

Static bodies cannot move from applied or set forces, but can be relocated using the setTransform() method. However, we should avoid using the setTransform() method while a simulation is running, because it makes the simulation unstable and can cause some strange behaviors. Instead, if we want to change the position of a static body, we can do so whenever creating the simulation or, if we need to change the position at runtime, simply check that the new position will not cause the static body to overlap existing dynamic bodies or kinematic bodies.

Kinematic bodies cannot have forces applied, but we can set their velocities via the setLinearVelocity() and setAngularVelocity() methods.

See also

  • Introduction to the Box2D physics extension in this article.

  • Using forces, velocities, and torque in this article.

Creating category-filtered bodies

Depending on the type of physics simulation that we want to achieve, controlling which bodies are capable of colliding can be very beneficial. In Box2D, we can assign a category, and category-filter to fixtures to control which fixtures can interact. This recipe will cover the defining of two category-filtered fixtures that will be applied to bodies created by touching the scene to demonstrate category-filtering.

Getting ready...

Create an activity by following the steps in the Introduction to the Box2D physics extension section given at the beginning of the article. This activity will facilitate the creation of the category-filtered bodies used in this section.

How to do it...

Follow these steps to build our category-filtering demonstration activity:

  1. Define the following class-level variables within the activity:

    private int mBodyCount = 0; public static final short CATEGORYBIT_DEFAULT = 1; public static final short CATEGORYBIT_RED_BOX = 2; public static final short CATEGORYBIT_GREEN_BOX = 4; public static final short MASKBITS_RED_BOX = CATEGORYBIT_DEFAULT + CATEGORYBIT_RED_BOX; public static final short MASKBITS_GREEN_BOX = CATEGORYBIT_DEFAULT + CATEGORYBIT_GREEN_BOX; public static final FixtureDef RED_BOX_FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_RED_BOX, MASKBITS_RED_BOX, (short)0); public static final FixtureDef GREEN_BOX_FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_GREEN_BOX, MASKBITS_GREEN_BOX, (short)0);

  2. Next, create this method within the class that generates new category-filtered bodies at a given location:

    private void addBody(final float pX, final float pY) { this.mBodyCount++; final Rectangle rectangle = new Rectangle(pX, pY, 50f, 50f, this.getVertexBufferObjectManager()); rectangle.setAlpha(0.5f); final Body body; if(this.mBodyCount % 2 == 0) { rectangle.setColor(1f, 0f, 0f); body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, rectangle, BodyType.DynamicBody, RED_FIXTURE_DEF); } else { rectangle.setColor(0f, 1f, 0f); body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, rectangle, BodyType.DynamicBody, GREEN_FIXTURE_DEF); } this.mScene.attachChild(rectangle); this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector( rectangle, body, true, true)); }

  3. Lastly, fill the body of the onSceneTouchEvent() method with the following code that calls the addBody() method by passing the touched location:

    if(this.mPhysicsWorld != null) if(pSceneTouchEvent.isActionDown()) this.addBody(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());

How it works...

In the first step, we create an integer, mBodyCount, which counts how many bodies we have added to the physics world. The mBodyCount integer is used in the second step to determine which color, and thus which category, should be assigned to the new body.

We also create the CATEGORYBIT_DEFAULT, CATEGORYBIT_RED_BOX, and CATEGORYBIT_ GREEN_BOX category bits by defining them with unique power-of-two short integers and the MASKBITS_RED_BOX and MASKBITS_GREEN_BOX mask bits by adding their associated category bits together. The category bits are used to assign a category to a fixture, while the mask bits combine the different category bits to determine which categories a fixture can collide with. We then pass the category bits and mask bits to the fixture definitions to create fixtures that have category collision rules.

The second step is a simple method that creates a rectangle and its corresponding body. The method takes the X and Y location parameters that we want to use to create a new body and passes them to a Rectangle object's constructor, to which we also pass a height and width of 50f and the activity's VertexBufferObjectManager. Then, we set the rectangle to be 50 percent transparent using the rectangle.setAlpha() method. After that, we define a body and modulate the mBodyCount variable by 2 to determine the color and fixture of every other created body. After determining the color and fixture, we assign them by setting the rectangle's color and creating a body by passing our mPhysicsWorld physics world, the rectangle, a dynamic body type, and the previously-determined fixture to use. Finally, we attach the rectangle to our scene and register a PhysicsConnector class to connect the rectangle to our body.

The third step calls the addBody() method from step two only if the physics world has been created and only if the scene's TouchEvent is ActionDown. The parameters that are passed, pSceneTouchEvent.getX() and pSceneTouchEvent.getY(), represent the location on the scene that received a touch input, which is also the location where we want to create a new category-filtered body.

There's more...

The default category of all fixtures has a value of one. When creating mask bits for specific fixtures, remember that any combination that includes the default category will cause the fixture to collide with all other fixtures that are not masked to avoid collision with the fixture.

See also

  • Introduction to the Box2D physics extension in this article.

  • Understanding different body types in this article.

AndEngine for Android Game Development Cookbook Over 70 highly effective recipes with real-world examples to get to grips with the powerful capabilities of AndEngine and GLES 2 with this book and ebook.
Published: January 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Creating multiple-fixture bodies

We sometimes need a body that has varying physics attributes on certain parts of it. For instance, a car with a bumper should react differently if it hits a wall to a car without a bumper. The creation of such a multifixture body in Box2D is fairly simple and straightforward. In this recipe, we will see how to create a multifixture body by creating two fixtures and adding them to an empty body.

Getting ready...

Follow the steps in the Introduction to the Box2D physics extension section at the beginning of the article to create a new activity that will facilitate the creation of our multifixture body.

How to do it...

Follow these steps to see how we can create multifixture bodies:

  1. Place the following code in the onPopulateScene() method to create two rectangles that have a modified AnchorCenter value which allows for precise placement when linked to a body:

    Rectangle nonbouncyBoxRect = new Rectangle(0f, 0f, 100f, 100f, this.getEngine().getVertexBufferObjectManager()); nonbouncyBoxRect.setColor(0f, 0f, 0f); nonbouncyBoxRect.setAnchorCenter(((nonbouncyBoxRect.getWidth() / 2) - nonbouncyBoxRect.getX()) / nonbouncyBoxRect.getWidth(), ((nonbouncyBoxRect.getHeight() / 2) – nonbouncyBoxRect.getY()) / nonbouncyBoxRect.getHeight()); mScene.attachChild(nonbouncyBoxRect); Rectangle bouncyBoxRect = new Rectangle(0f, -55f, 90f, 10f, this.getEngine().getVertexBufferObjectManager()); bouncyBoxRect.setColor(0f, 0.75f, 0f); bouncyBoxRect.setAnchorCenter(((bouncyBoxRect.getWidth() / 2) – bouncyBoxRect.getX()) / bouncyBoxRect.getWidth(), ((bouncyBoxRect.getHeight() / 2) – bouncyBoxRect.getY()) / bouncyBoxRect.getHeight()); mScene.attachChild(bouncyBoxRect);

  2. The following code creates a Body object and two fixtures, one that is perfectly elastic and another that is perfectly inelastic. Add it after the creation of the rectangles in the preceding step:

    Body multiFixtureBody = mPhysicsWorld.createBody(new BodyDef()); multiFixtureBody.setType(BodyType.DynamicBody); FixtureDef nonbouncyBoxFixtureDef = PhysicsFactory. createFixtureDef(20, 0.0f, 0.5f); final PolygonShape nonbouncyBoxShape = new PolygonShape(); nonbouncyBoxShape.setAsBox((nonbouncyBoxRect.getWidth() / 2f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, (nonbouncyBoxRect.getHeight() / 2f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, new Vector2(nonbouncyBoxRect.getX() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, nonbouncyBoxRect.getY() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT), 0f); nonbouncyBoxFixtureDef.shape = nonbouncyBoxShape; multiFixtureBody.createFixture(nonbouncyBoxFixtureDef); mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector( nonbouncyBoxRect, multiFixtureBody)); FixtureDef bouncyBoxFixtureDef = PhysicsFactory.createFixtureDef(20, 1f, 0.5f); final PolygonShape bouncyBoxShape = new PolygonShape(); bouncyBoxShape.setAsBox((bouncyBoxRect.getWidth() / 2f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, (bouncyBoxRect.getHeight() / 2f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, new Vector2(bouncyBoxRect.getX() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, bouncyBoxRect.getY() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT), 0f); bouncyBoxFixtureDef.shape = bouncyBoxShape; multiFixtureBody.createFixture(bouncyBoxFixtureDef); mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector( bouncyBoxRect, multiFixtureBody));

  3. Lastly, we need to set the location of our multifixture body now that it has been created. Place the following call to setTransform() after the creation of the bodies in the previous step:

    multiFixtureBody.setTransform(400f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, 240f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, 0f);

How it works...

The first step that we take is to define a rectangle that will represent a non-bouncy fixture by using the Rectangle constructor and passing 0f on the x axis and 0f on the y axis, representing the origin of the world. We then pass a height and width of 100f, which makes the rectangle a large square, and the activity's VertexBufferObjectManager.

Then, we set the color of the non-bouncy rectangle to black, 0f, 0f, 0f, and set its anchor-center using the nonbouncyBoxRect.setAnchorCenter() method to represent the location on the body, created in the second step, at which the non-bouncy rectangle will be attached. The anchor-center location of (((nonbouncyBoxRect.getWidth() / 2) - nonbouncyBoxRect.getX()) / nonbouncyBoxRect.getWidth(), ((nonbouncyBoxRect.getHeight() / 2) – nonbouncyBoxRect.getY()) / nonbouncyBoxRect.getHeight() converts the rectangle's location and size to the location that the rectangle rests on the origin. In the case of our non-bouncy rectangle, the anchor-center remains at the default 0.5f, 0.5f, but the formula is necessary for any fixture that will be created from a rectangle that is not centered on the origin. Next, we attach our non-bouncy rectangle to the scene. Then, we create a rectangle that will represent a bouncy fixture using the same method that we used to create the non-bouncy rectangle, but we place the rectangle at -55f on the y axis to put it directly below the non-bouncy rectangle. We also set the width of the rectangle to 90f, making it slightly smaller than the previous rectangle, and the height to 10f to make it a slim bar that will act as a bouncy portion directly below the non-bouncy rectangle. After setting the bouncy rectangle's anchor-center using the same formula used for the non-bouncy rectangle, we attach it to the scene. Take note that we have modified the AnchorCenter values of each of the rectangles, so that the PhysicsConnectors class that we register in the second step can place the rectangles in the proper location when we run the simulation. Also, note that we create our rectangles and multifixture body at the world's origin to make calculations simple and fast. After our body has been created, we move it to the position that it should be in for the simulation, as can be seen in the third step, when we call the multiFixtureBody.setTransform() method with the parameters 400f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT and 240f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, which represent the center of the screen in the physics world, and 0f, which represents the zero-rotation that the body will have.

In the second step, we create an empty body, multiFixtureBody, by calling mPhysicsWorld.createBody(new BodyDef()) and set it to be dynamic by calling its setType() method with the parameter BodyType.DynamicBody. Then, we define a fixture definition, nonbouncyBoxFixtureDef, for the non-bouncy fixture.

Next, we create a PolygonShape shape named nonbouncyBoxShape and set it as a box that mimics our nonbouncyBoxRect by calling nonbouncyBoxShape shape's setAsBox() method with the first two parameters as nonbouncyBoxRect.getWidth() / 2f and nonbouncyBoxRect.getHeight() / 2f to set the nonbouncyBoxShape object to have the same width and height as our nonbouncyBoxRect rectangle. Both of the parameters are divided by PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT to scale the values to the physics world. Furthermore, the setAsBox() method's first two parameters are half sizes. This means that a normal width of 10f will be passed to the setAsBox() method as 5f. The next parameter of the setAsBox() method is a Vector2 parameter that will identify the location of our nonbouncyBoxShape shape in the physics world. We set it to the location of our nonbouncyBoxRect rectangle, converting the location to physics world coordinates by scaling with the PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT variable. The last parameter of the setAsBox() method is the rotation that nonbouncyBoxShape should have. Because our nonbouncyBoxRect rectangle is not rotated, we use 0f.

Then, we set the shape property of our nonbouncyBoxFixtureDef fixture definition to nonbouncyBoxShape, which applies the shape to our fixture definition. Next, we attach the fixture to our multifixture body by calling the body's createFixture() method with the nonbouncyBoxFixtureDef fixture definition as the parameter. Then, we register a PhysicsConnector class to link the nonbouncyBoxRect rectangle in our scene to the multiFixtureBody body in the physics world. Finally, we follow the same procedures that we used when creating the non-bouncy fixture to create our bouncy fixture. The result should be a black square with one bouncy, green side.

By setting the isSensor property of a fixture definition to true, a fixture can be created as a sensor, which allows it to contact other fixtures without a physical interaction occurring. For more information on sensors, see the Fixtures section of the Box2D manual at http://www.box2d.org/manual.html

See also

  • Introduction to the Box2D physics extension in this article.

  • Understanding different body types in this article.

Creating unique bodies by specifying vertices

Not everything in our physics simulations must be made of rectangles or circles. We can also create polygonal bodies by creating a list of the polygonal points. This approach is useful for creating certain types of terrain, vehicles, and characters. In this recipe, we will demonstrate how to create a unique body from a list of vertices.

Getting ready...

Create an activity by following the steps in the Introduction to the Box2D physics extension section given at the beginning of the article. This activity will easily allow the creation of a uniquely constructed body with vertices.

How to do it...

Complete the following steps to define and create our unique, polygonal body:

  1. Our unique body's vertices will be defined by a list of Vector2 objects. Add the following list to the onPopulateScene() method:

    List<vector2> UniqueBodyVertices = new ArrayList<vector2>(); UniqueBodyVertices.addAll((List<vector2>) ListUtils.toList( new Vector2[] { new Vector2(-53f,-75f), new Vector2(-107f,-14f), new Vector2(-101f,41f), new Vector2(-71f,74f), new Vector2(69f,74f), new Vector2(98f,41f), new Vector2(104f,-14f), new Vector2(51f,-75f), new Vector2(79f,9f), new Vector2(43f,34f), new Vector2(-46f,34f), new Vector2(-80f,9f) }));

  2. To use the preceding list of vertices, we must run them through the EarClippingTriangulator class to turn the vertices list into a list of triangles that the physics engine will use to create multiple fixtures that are joined into a single body. Place this code after the creation of the initial Vector2 list:

    List<vector2> UniqueBodyVerticesTriangulated = new EarClippingTriangulator(). computeTriangles(UniqueBodyVertices);

  3. To create a mesh that will represent our unique body, as well as adapt the triangulated vertices for use in the physics world, add the following code snippet:

    float[] MeshTriangles = new float[UniqueBodyVerticesTriangulated.size() * 3]; for(int i = 0; i < UniqueBodyVerticesTriangulated.size(); i++) { MeshTriangles[i*3] = UniqueBodyVerticesTriangulated.get(i).x; MeshTriangles[i*3+1] = UniqueBodyVerticesTriangulated.get(i).y; UniqueBodyVerticesTriangulated.get(i). mul(1/PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT); } Mesh UniqueBodyMesh = new Mesh(400f, 260f, MeshTriangles, UniqueBodyVerticesTriangulated.size(), DrawMode.TRIANGLES, this.getVertexBufferObjectManager()); UniqueBodyMesh.setColor(1f, 0f, 0f); mScene.attachChild(UniqueBodyMesh);

  4. Now that we have adapted the vertices to be used in the physics world, we can create the body:

    FixtureDef uniqueBodyFixtureDef = PhysicsFactory.createFixtureDef(20f, 0.5f, 0.5f); Body uniqueBody = PhysicsFactory.createTrianglulatedBody( mPhysicsWorld, UniqueBodyMesh, UniqueBodyVerticesTriangulated, BodyType.DynamicBody, uniqueBodyFixtureDef); mPhysicsWorld.registerPhysicsConnector( new PhysicsConnector(UniqueBodyMesh, uniqueBody));

  5. Lastly, we want the unique body to have something to collide with. Add the following body definitions to create two static bodies that will act as small pegs in our physics world:

    FixtureDef BoxBodyFixtureDef = PhysicsFactory.createFixtureDef(20f, 0.6f, 0.5f); Rectangle Box1 = new Rectangle(340f, 160f, 20f, 20f, this.getVertexBufferObjectManager()); mScene.attachChild(Box1); PhysicsFactory.createBoxBody(mPhysicsWorld, Box1, BodyType.StaticBody, BoxBodyFixtureDef); Rectangle Box2 = new Rectangle(600f, 160f, 20f, 20f, this.getVertexBufferObjectManager()); mScene.attachChild(Box2); PhysicsFactory.createBoxBody(mPhysicsWorld, Box2, BodyType.StaticBody, BoxBodyFixtureDef);

How it works...

The list of vertices that we first create represents the shape that our unique body will be, relative to the center of the body. In the second step, we create another list of vertices using the EarClippingTriangulator class. This list that is returned from the computeTriangles() method of the EarClippingTriangulator class contains all of the points of the triangles that make up our unique body. The following figure shows what our polygonal body looks like before and after running its vertices through the EarClippingTriangulator class. Notice that our body will be made from several triangular shapes that represent the original shape:

In step three, after adding each vertex to the MeshTriangles array for use in creating a mesh to represent our body, we multiply each vertex by 1/PhysicsConstants.PIXEL_ TO_METER_RATIO_DEFAULT, which is the same as dividing the vertex's coordinates by the default pixel-to-meter ratio. This division process is a common practice used to convert the scene coordinates to the physics world coordinates. The physics world measures distance in meters, so a conversion from pixels is necessary. Any consistent, reasonable value can be used as the conversion constant, but the default pixel-to-meter-ratio is 32 pixels per meter and has been proven to work in almost every simulation.

Step four creates the unique body by calling PhysicsFactory. createTrianglulatedBody. It is important to note that while it is possible to create polygonal bodies from a non-triangulated list of vertices, the only benefit to doing so would be if we were using a list with less than seven vertexes. Even with such a small list, triangulating the body does not have a noticeable negative impact on the simulation.

Several physics-body editors are available to simplify body creation. The following are all usable with AndEngine:

See also

  • Introduction to the Box2D physics extension in this article.

  • Understanding different body types in this article.

AndEngine for Android Game Development Cookbook Over 70 highly effective recipes with real-world examples to get to grips with the powerful capabilities of AndEngine and GLES 2 with this book and ebook.
Published: January 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Using forces, velocities, and torque

No matter what kind of simulation we are creating, we will more than likely want to control at least one body. To move bodies in Box2D, we can apply linear or angular forces, set linear or angular velocities, and apply an angular force in the form of torque. In this recipe, we will see how we can apply these forces and velocities on multiple bodies.

Getting ready...

Follow the steps in the Introduction to the Box2D physics extension section at the beginning of the article to create a new activity that will facilitate the creation of bodies that will react to forces, velocities, and torque. Then, update the activity to include the additional code from the ForcesVelocitiesTorqueActivity class found in the code bundle.

How to do it...

Refer to the supplemental ForcesVelocitiesTorqueActivity class for the complete example of this recipe. We will cover only the basics of the recipe in this section:

  1. We will first work with the methods that handle the linear motion of our bodies. Place the following code snippet in the overridden onAreaTouched() method of the LinearForceRect rectangle:

    LinearForceBody.applyForce(0f, 2000f, LinearForceBody.getWorldCenter().x, LinearForceBody.getWorldCenter().y);

  2. Next, insert this code in the onAreaTouched() method of the LinearImpulseRect rectangle:

    LinearImpulseBody.applyLinearImpulse(0f, 200f, LinearImpulseBody.getWorldCenter().x, LinearImpulseBody.getWorldCenter().y);

  3. Then, add this code to the onAreaTouched() method of the LinearVelocityRect rectangle:

    LinearVelocityBody.setLinearVelocity(0f, 20f);

  4. Now, we will work with the Body methods that affect the angular motion of our bodies. Place this code in the onAreaTouched() method of the AngularTorqueRect rectangle:

    AngularTorqueBody.applyTorque(2000f);

  5. Insert the following code in the onAreaTouched() method of the AngularImpulseRect rectangle:

    AngularImpulseBody.applyAngularImpulse(20f);

  6. Finally, add this code to the onAreaTouched() method of the AngularVelocityRect rectangle:

    AngularVelocityBody.setAngularVelocity(10f);

How it works...

In step one, we apply a linear force on LinearForceBody by calling its applyForce() method with the force parameters of 0f on the x axis and 2000f on the y axis to apply a strong, positive vertical force and the force location in world coordinates of LinearForceBody.getWorldCenter().x and LinearForceBody. getWorldCenter().y to apply the force at the center of the LinearForceBody body.

Step two applies a linear impulse on the LinearImpulseBody body via its applyLinearImpulse() method. The applyLinearImpulse() method's first two parameters are the impulse amount with respect to the world axis. We use the values of 0f and 200f to apply the moderate impulse pointing straight up. The remaining two parameters of the applyLinearImpulse() method are the x and y location that the impulse will be applied to the body in world coordinates. We pass LinearImpulseBody. getWorldCenter().x and LinearImpulseBody.getWorldCenter().y to apply the impulse at the center of the LinearImpulseBody body.

In step three, we set the linear velocity of LinearVelocityBody by calling its setLinearVelocity() method with the parameters 0f and 20f. The parameter of 0f signifies that the body will not be moving on the x axis, and the parameter of 20f sets the y axis motion immediately to be 20 meters per second. When using the setLinearVelocity() method, the velocity is automatically set at the body's center of mass.

Step four applies a torque to AngularTorqueBody. We call the AngularTorqueBody. applyTorque() method with a value of 2000f to apply a very strong torque to the AngularTorqueBody body at the body's center of mass.

In the fifth step, we apply an angular impulse to the AngularImpulseBody body by calling the AngularImpulseBody.applyAngularImpulse() method with a value of 20f. This small, angular impulse will be applied to the AngularImpulseBody body's center of mass.

For the final step, we set the angular velocity of the AngularVelocityBody body. We call the AngularVelocityBody.setAngularVelocity() method with the value of 10f to make the body immediately rotate at 10 radians per second.

There's more...

Impulses differ from forces in that they function independently of the timestep. An impulse actually equals force multiplied by time. Likewise, forces equal the impulse divided by time.

Setting the velocity of bodies and applying an impulse are similar, but there is an important distinction to make—applying impulses directly adds to or subtracts from the velocity, while setting a velocity does not incrementally increase or decrease the velocity.

Summary

This article helped us to understand the various physics-based features of the game engine. We learned how to apply them and make our game more real life. We also learned how to apply forces and torque in our game to make it more interesting and fun to play with.

Resources for Article :


Further resources on this subject:


About the Author :


Brian Broyles

Brian Broyles is a freelance programmer and 2D/3D graphic designer with over 12 years of experience. Before entering the mobile development industry in 2010 as the lead programmer of IFL Game Studio, he designed advanced artificial intelligence systems and graphical effects for interactive PC applications. In addition to his vast programming and design experience, he is also a commercial pilot, instrument flight instructor, and advanced instrument ground instructor.

Jayme Schroeder

Jayme Schroeder was introduced to computers at a very young age. By 11, he had started creating modifications and level packs for his favorite game. By age 16, he had found his true passion in game development and network programming in C++ and OpenGL. In early 2011, Jayme had received an Android smartphone and immediately fell in love with the development experience. Since then, he has been researching and developing for the Android platform on a daily basis.

Books From Packt


Android User Interface Development: Beginner's Guide
Android User Interface Development: Beginner's Guide

Android 3.0 Animations: Beginner’s Guide
Android 3.0 Animations: Beginner’s Guide

Android Database Programming
Android Database Programming

Flash Development for Android   Cookbook
Flash Development for Android Cookbook

 Android Database Programming
Android Database Programming

Android Application Testing Guide
Android Application Testing Guide

Android NDK Beginner’s Guide
Android NDK Beginner’s Guide

Torque 3D Game Development Cookbook
Torque 3D Game Development Cookbook


Your rating: None Average: 5 (1 vote)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
f
f
B
R
F
X
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software