Hi,
In our last post we used box2d to make a body and attach a fixture to it. Then wrote fixed step update function to update the box2d physics in the game. Now we would attach a texture to the body.
While attaching we take care that the texture is of similar shape to the physics shape we added. This we usually see to it manually rather than reading the image and trying to guess what shape it should be.
First we will make a TextureWrapper class. It would be similar to the class we made in first series of tutorials but we will go through it once again.
public TextureWrapper{ TextureRegion region; int width; int height; Vector2 position; float scaleX; float scaleY; float originX; float originY; float rotation; public TextureWrapper(TextureRegion region,Vector2 pos){ this.position=pos; SetTextureRegion(region); } public void SetTextureRegion(TextureRegion region){ this.region=region; width=region.getRegionWidth(); height=region.getRegionHeight(); originX=width/2; originY=height/2; scaleX=1; scaleY=1; } public int GetWidth(){ return width; } public int GetHeight(){ return height; } public void SetPosition(float x,float y){ position.set(x,y); } public void SetRotation(float r){ rotation=r; } public void Draw(SpriteBatch sp){ sp.draw(region,position.x-width/2, position.y-height/2, originX, originY, width, height, scaleX, scaleY, rotation); } .... }
So this is a basic texturewrapper class whose object we would use to show the box2d physics fixture on the screen.
The function used to draw the region uses many arguments. The first one is the region itself. Next two are the x and y position of the texture and as it draws from top left corner, we substract half width and half height to draw it at the specified location matching its center. Next two are the local cooridnates x and y of the image which are used as pivots while rotating the image. Here we have defined them to half width and half height so they are center of image. Next two are the width and height(if they are different from actual width and height of region, the image would be scaled). ScaleX and scaleY can also be used for scaling and also if we give negative values they flip the image horizontally or vertically. Finally rotation is to rotate the image around the pivot point (described by originX and originY). Rotation value should be in degrees here and not in radians.
Box2D:
We would make a small class called BoxUserData which would be used to store information which would be useful for us when handling collision responses.
public class BoxUserData{ int collisionGroup; int boxId; public BoxUserData(int boxid,int collisiongroup){ Set(boxid,collisiongroup); } public void Set(int boxid,int collisiongroup){ this.boxId=boxid; this.collisionGroup=collisiongroup; } public int GetBoxId(){ return this.boxId; } public int GetCollisionGroup{ return this.collisionGroup; } }
We would use this when we handle collision response. For now we just set the values in it. Secondly we would now make a base class for box2d objects which can be extended to have different types of objects in the game. This would have basic functions to make a body/fixture which we defined in the last post.
BaseClass:
public abstract class BaseBoxObject{ static final float WORLD_TO_BOX=0.01f; static final float BOX_TO_WORLD=100f; float ConvertToBox(float x){ return x*WORLD_TO_BOX; } float ConvertToWorld(float x){ return x*BOX_TO_WORLD; } protected Body body; protected BoxUserData userData; protected Vector2 worldPosition; public BaseBoxObject(Vector2 pos,World world,int boxIndex,int collisionGroup){ userData=new BoxUserData(boxIndex,collisionGroup); worldPosition=new Vector2(); CreateBody(world,pos,0); body.setUserData(userData); } public void CreateBody(World world,Vector2 pos,float angle){ BodyDef bodyDef = new BodyDef(); bodyDef.type = bodyType; bodyDef.position.set(ConvertToBox(pos.x),ConvertToBox(pos.y)); bodyDef.angle=angle; body = world.createBody(bodyDef); } private void MakeRectFixture(float width,float height,BodyDef.BodyType bodyType, float density,float restitution, Vector2 pos,float angle){ PolygonShape bodyShape = new PolygonShape(); float w=ConvertToBox(width/2f); float h=ConvertToBox(height/2f); bodyShape.setAsBox(w,h); FixtureDef fixtureDef=new FixtureDef(); fixtureDef.density=density; fixtureDef.restitution=restitution; fixtureDef.shape=bodyShape; body.createFixture(fixtureDef); bodyShape.dispose(); } void MakeCircleFixture(float radius,BodyDef.BodyType bodyType, float density,float restitution, Vector2 pos,float angle){ FixtureDef fixtureDef=new FixtureDef(); fixtureDef.density=density; fixtureDef.restitution=restitution; fixtureDef.shape=new CircleShape(); fixtureDef.shape.setRadius(BoxObjectManager.ConvertToBox(radius)); body.createFixture(fixtureDef); fixtureDef.shape.dispose(); } public void UpdateWorldPosition(){ worldPosition.set(ConvertToWorld(body.getPosition().x),ConvertToWorld(body.getPosition().y)); } }
Now we would make a simple class by extending the BaseBoxObject class
public class BoxObject extends BaseBoxObject{ TextureWrapper texture; public static final int CIRCLE_OBJECT=1; public static final int POLY_OBJECT=2; public BoxObject(TextureRegion region,Vector2 pos, int bodyType,World world,int index,int colgroup){ super(pos,world,index,colgroup); texture=new TextureWrapper(region,pos); if(bodyType==CIRCLE_OBJECT){ MakeCircleFixture(texture.GetWidth/2,BodyDef.BodyType.StaticBody,1,1,pos,0); }else{ MakeRectFixture(texture.GetWidth,texture.GetHeight(),BodyDef.BodyType.StaticBody,1,1,pos,0); } } public void Draw(SpriteBatch sp){ texture.Draw(sp); } public void Update(float dt){ UpdateWorldPosition(); texture.SetPosition(worldPosition); //MathUtils is a class available in box2d which has useful math functions texture.SetRotation(body.getAngle()*MathUtils.radiansToDegrees); } }
This is a simple implementaion of how we used a box2d body in our game. This will display a texture with a box2d body attached to it. We have given some default values to the fixture and body we created here but you can pass more arguments or make accessor functions to set theses values. The update function has to be called in every frame to update the texture position and rotation with respect to the box2d body. By calling draw function we can render it on the screen.
This is how we implemented box2d in our game. We don’t say it is the best way to do it bust just one way to do it.
In next tutorial we would create an array or a list to hold all instances of the boxobjects which are present in the game. Also we would describe the other properties of box2d body and fixture like sensor and different body types like kinematic and dynamic.
Thank you for the patience. Please leave any queries/suggestions/feedback in comments section. We look forward to hearing from you.
Hi!, just watched this, really helpful, but i got a question, instead of a single texture, can i attach it to an animation?, i have also seen that most people use OrthographicCamera with this, i guess because its easier to get it working with the MKS system, but Animation/Fonts, and stuff start doing weird stuff when i use it. Could you help me a little bit, sorry if its a basic question, but i have been searching for a while, and its a little difficult to understand just reading some code.
Hi,
Attaching an animation should not be a problem though it depends on how you are implementing the animation. Our animation class just had an array of textures in it and all had a same position just at a time only one would be drawn. So as time crosses the threshold for an image, we drew the next image in the same position. So instead of having a class holding reference to a texture and its position , you can have multiple textures with same position only one being drawn at a time. Hope we understood your question correctly.
Regarding the OrthographicCamera, well yes it makes the stuff easier because then we dont have to worry much about the different resolutions especially when it comes to different screens available in android.How we use it is we consider the screen to be 320×480 and all texture sizes and coordinates are made for that resolution. Just while creating box2d bodies their location and fixture sizes are scaled down by a factor like 50 .Now for example if a screen is 480×800 then first, the texture’s(attached to a box body) position is scaled up by 50 which is the scaling factor we used, to get texture’s location to be correct with respect to resolution of 320×480.But we dont scale the texture width/height because texture was made for 320×480 resolution by this factor (50). Then the orthographiccamera checks if the screen resolution is different which is for this case it would scale again everything depending on the new projection matrix (which would be 1.5 scaling factor if we go scaling width wise). Don’t know if it helped or not though you can elaborate on what exactly happens with animation/fonts then we can try to help you.
Hi Thanks A LOT for your reply now it works perfect, loved your post 😀
Minor detail: The ConvertToWorld function uses BOX_TO_WORLD, but the static float is named ‘BOX_WORLD_TO’. Typo, methinks.
Thanks for pointing out the typo. Fixed now.