As we mentioned in our last tutorial Game Development in Android using Libgdx Part I, we would be making buttons here which appear in our main menu, taking reference from our game Polar.
Before we get to the button class we would talk about the BitmapFont and Text Wrapper classes
BitmapFont:
They are bitmaps which contain array of glyphs in form of pixels. So when writing some text we actually draw bitmaps of each character one after the other. The good point about bitmap font is that they are faster to render than normal fonts but they do not look good if scaled. For different resolutions we need different fonts. But for our case we made one font and scaled it for different resolutions.
In LIBGDX we get a class BitmapFont which handles everything for us.
To make a bitmapfont we used the tool called Hiero provided in their google code page.
TextWrapper:
We implemented this class as a wrapper for the text we show in the menu.
TextWrapper.java
public class TextWrapper{ public String Text; public Vector2 Position; int width; int height; public TextWrapper(String txt,Vector2 pos){ Text=txt; Position=pos; } public void Draw(SpriteBatch sp,BitmapFont fnt){ width=(int)fnt.getBounds(Text).width; //Get the width of the text we draw using the current font height=(int)fnt.getBounds(Text).height; //Get the height of the text we draw using the current font fnt.draw(sp,Text,Position.x-width/2, // Get center value in x direction Position.y-height/2 //Get center value in y direction ); } }
This is a simple wrapper to draw texts on the screen. In the constructor we pass the Text and its Position on the screen. In Draw function we pass SpriteBatch instance and BitmapFont instance. SpriteBatch was explained in the last tutorial so you can have a look there. The draw function provided in BitmapFont class has two overloads. We used one with four arguments where we pass the spritebatch, the text we want to draw, the left position of the text and the bottom position of the text. Thing to note is that in Libgdx coordinate system, the origin is the left bottom corner and y value increases as we go in the upward direction rather than downward as is the usual case in graphic systems. The x value increases, as usual, from left to right.
Buttons:
The buttons we implemented in Polar were simple. They had two texture wrapper objects one for idle event and other for click event and we had a textwrapper object to show text in the buttons.
Button.java
public class Button{ public TextureWrapper BackTexture; public TextureWrapper ClickedTexture; public TextWrapper Text; public Vector2 Position; public Boolean IsClicked; public Button(TextureWrapper backTex,TextureWrapper clickTex,String text,Vector2 pos){ BackTexture=backTex; ClickedTexture=clickTex; Text=new TextWrapper(text,pos); Position=pos; IsClicked=false; } public void Draw(SpriteBatch sp,BitmapFont fnt){ if(!IsClicked){ BackTexture.Draw(sp); }else{ ClickedTexture.Draw(sp); } Text.Draw(sp,fnt); } public void Update(int tapx,int tapy){ IsClicked=IsInside(tapx,tapy); } Boolean IsInside(int x,int y){ int px=(int)(BackTexture.Position.x-BackTexture.destWidth/2); int py=(int)(BackTexture.Position.y-BackTexture.destHeight/2); int width=(int)(BackTexture.Position.x+BackTexture.destWidth/2); int height=(int)(BackTexture.Position.y+BackTexture.destHeight/2); if(x>=px && x<=(px+width) && y>=py && y<=(py+height)) return true; return false; } }
So for rendering we call the Draw function and for checking if it is clicked or not we call the Update function with the coordinates of tap position. We checked our backtexture to check if tap was inside that area. You can use any one of the textures or use a collection of textures used in the button object to check the click. You can also put padding to the limits we are checking within, in the IsInside function to check with the tap position if the texture is too small and not easily clickable.
Next Tutorial:
In the next tutorial we would finish the menu screen by finding how to calculate the tap position and also handle the tap events on the button.
Let us know any of your doubts/suggestions; please put them in the comments section and we would try to answer them.
Thank you for the patience.
Really withour demo code it’s hard to understand… 🙁
true that
Hi! First, big thanks for the tutorial series,it seems that you are the only ones trying to really explain it step by step, especially thank you for box2d tutorials, i hope you continue.
About the code you provide in this tutorial there seem to be some inconsistencies:
1. in the Button constructor you pass String parameter named “text” and you assign it to TextWrapper field, it looks like you wanted to pass TextWrapper parameter
2. in is inside you refer to “width” field of BackTexture object which is TextureWrapper instance
and in previous tutorial, when you defined TextureWrapper class there was no such field as width, only srcWidth and destWidth. Did you mean destWidth?
Hi Peter,
Thanks for pointing out the mistakes.
1. We updated the button constructor which now creates a textWrapper object inside the constructor from “text” argument which is String type. You can always do the other way round creating the textwrapper object and sending it as argument while instantiating the Button object.
2. Yes we meant destWidth. Updated that in the post now.
int px=BackTexture.Position.X-BackTexture.destWidth/2;
int py=BackTexture.Position.Y-BackTexture.destHeight/2;
int width=BackTexture.Position.X+BackTexture.destWidth/2;
int height=BackTexture.Position.Y+BackTexture.destHeight/2;
I’m encountering the same error in all these lines. 🙁
“The operator – is undefined for the argument type(s) Vector2, int”
Try this.
int px=(int)(BackTexture.Position.x-BackTexture.destWidth/2);
int py=(int)(BackTexture.Position.y-BackTexture.destHeight/2);
int width=(int)(BackTexture.Position.x+BackTexture.destWidth/2);
int height=(int)(BackTexture.Position.y+BackTexture.destHeight/2);
is this code straight from polar and can you make a video series on youtube or something please. That would be easier to understand