In this tutorial we would finish the Menu Screen and look at the Camera and TapResponse class .
Camera
Making a wrapper for camera can help in lots of situations and decreases a lot of work later on. It can be used to easily incorporate different effects like rotation, scaling and translation(useful for platformer games) of the view. We would be concentrating here on how to make an Orthographic camera for a 2d game. Orthographic means that the view has only two dimensions – width and height.
In Libgdx we already have a class called OrthographicCamera on which we will just make a wrapper to suit our purpose.
In CameraHelper.java we will need this function to generate our basic camera.
public static OrthographicCamera GetCamera(float virtualWidth,float virtualHeight) { float viewportWidth = virtualWidth; float viewportHeight = virtualHeight; float physicalWidth = Gdx.graphics.getWidth(); float physicalHeight = Gdx.graphics.getHeight(); float aspect = virtualWidth / virtualHeight; //This is to maintain the aspect ratio. //If the virtual aspect ration does not match with the aspect ratio //of the hardware screen then the viewport would scaled to //meet the size of one dimension and other would not cover full dimension //If we stretch it to meet the screen aspect ratio then textures will //get distorted either become fatter or elongated if (physicalWidth / physicalHeight >= aspect) { // Letterbox left and right. viewportHeight = virtualHeight; viewportWidth = viewportHeight * physicalWidth / physicalHeight; } else { // Letterbox above and below. viewportWidth = virtualWidth; viewportHeight = viewportWidth * physicalHeight / physicalWidth; } OrthographicCamera camera = new OrthographicCamera(viewportWidth, viewportHeight); camera.position.set(virtualWidth/2, virtualHeight/2, 0); camera.update(); return camera; }
For making a camera which stretches to screen size just make viewportWidth=virtualWidth and viewportHeight=virtualHeight.
After the camera is created we have a projection matrix called “combined” in camera object. So in spriteBatch object we can set the projection matrix like this.
spritebatch.setProjectionMatrix(cam.combined); //cam is object return from CameraHelper.GetCamera() //Then do all the rendering which will be drawn using the camera's projection matrix
Now everything drawn using this spritebatch object would be transformed using the camera.
For example if you have a 2d side scrolling game and the objects in the world move with your player, then instead of moving all the objects in the world in every update it is a lot easier to change the position of the camera and set projection matrix of spritebatch to the camera’s projection matrix which then projects every object in the world according to the camera. Effects like zooming and rotation can also be applied in a similar way.
TapResponse
Now the camera is set up, lets look how to check the tap position. We cannot take the position of tap as is when it is read by the input because we have modified the projection or the view. So we would have to un-transform it to the game’s view.
For example our camera viewport size is 320×480 and screen size is 640×960. Now camera would scale the contents of the game to match the screen size which in this case would be scaling by a factor of 2. Lets suppose we tap at the center of the screen. The input coordinates would be ( 320,480) but in games environment they should be (160,240). So to achieve this we would take the inverse of the projection matrix of the camera and transform the input coordinates.
In Libgdx the abstract camera class, which was extended to make our camera, has a function called unproject and it needs a Vector3 argument. What it does is, that it unprojects the Vector3 to the game view.
So the following lines of code should solve our purpose.
Vector3 touchPoint=new Vector3(x,y,0); //where x and y are tap inputs camera.unproject(touchPoint); //now touchPoint would have untransformed coordinates
We will make a little more detailed wrapper for input which will also get us the information regarding touch start point and touch end point.
TapResponse.java
public class TapResponse{ public int TouchStartX; public int TouchStartY; public int TouchEndX; public int TouchEndY; public TapResponse(){touchState=NO_TOUCH;} public int TouchState; public final int NO_TOUCH=0; public final int TOUCH_START=1; public final int TOUCH_DRAG=2; public final int TOUCH_END=3; public void StartTouch(int x,int y) { TouchStartX=x; TouchStartY=y; TouchState=TOUCH_START; } public void DragTouch(int x,int y) { TouchEndX=x; TouchEndY=y; TouchState=TOUCH_DRAG; } public void EndTouch(int x,int y) { DragTouch(x, y); TouchState=TOUCH_END; } public void UpdateTouch(int x,int y,boolean IsTouching) { if(TouchState==TOUCH_END) TouchState=NO_TOUCH; if(!IsTouching) { if(TouchState==TOUCH_START || touchState==TOUCH_DRAG) EndTouch(x, y); } else { if(TouchState==NO_TOUCH) { StartTouch(x,y); } else if(TouchState==TOUCH_START || TouchState ==TOUCH_DRAG) { DragTouch(x, y); } } } }
So this class would handle the states of input like if the tap is started or stopped or is in a drag state.
As this tutorial is getting long we would be completing our menu in the next tutorial. We would be creating our Game class which is instantiated in libgdx android/desktop entry classes. Game class would handle the different screens present in the game. Then we would finish the MainMenu class.
Let us know any of your doubts/suggestions; please put them in the comments section and we will try to answer them.
Thank you for the patience.
Thank for providing such a good tutorial
Good to know you find it useful
thanx for this tutorial.i just couldn’t see where istouching is set.
could you please share the source code?
istouching is passed from main function and it is just “Gdx.input.isTouched()” which returns true if screen is touched
is this an efficient way to handle different screen resolutions or would it pixelate the images? and when you said it would stretch in one direction does it mean it would leave a black border in another dimension?
If you have a tiled background then for higher resolutions you can increase number of tiles to avoid scaling the images.
On the other hand if you have a single background image then it is preferable to have a higher resolution image scaled down rather than having a lower res image scaled up.
For black border issue (image letterboxing) yes it would happen if the image aspect ratio is different than the screen and you scale maintining the image’s aspect ratio.