Android Pong is a very simple game, as you can see on the picture. It will have at the left top corner a text. This will show the current points. Next to the text will be the start position of our ball. The player shape is a rectangle at the bottom of the playground.
Step 1 – Android Canvas
First of all we have to speak about the Android Canvas. With the Canvas class we can perform 2D drawing onto the screen. Basically it is an empty space to draw onto.
The Canvas class is not a new concept, this class is actually wrapping a SKCanvas under the hood. The SKCanvas comes from SKIA, which is a 2D Graphics Library that is used on many different platforms. SKIA is used on platforms such as Google Chrome, Firefox OS, Flutter, Fuschia etc. Once you understand how the Canvas works on Android, the same drawing concepts apply to many other different platforms.
Shapes to draw on Canvas
There are many different things you can draw onto a Canvas. One of the most common drawing operations is to draw a bitmap (image), a line, a circle, arc or recangle.
On our tutorial we will use the drawArc, drawCircle and drawLine.
It draws a simple circle. It only requires the center coordinate and the radius.
draw an circle
Draw the specified range of text, specified by start/end, with its origin at (x,y), in the specified Paint.
Draw the specified Rect using the specified paint. The rectangle will be filled or framed based on the Style in the paint.
Step 2 – activity_main.xml
After a brief introduction we start the coding with the activity_main.xml. In our app we will have only one user interface. There we will have two Buttons for the start and stop. Under the buttons will be the view of the game.
We will have two LinearLayout. One of them will be a nested one with horizontal orientation and the two Buttons inside.
The first LinearLayout will have vertical orientation and the PongView will be under the LinearLayout of the two Buttons.
Step 3 – PongView::class
Before the start of the implementation, we have to specify the size of our shapes, and the Paint.
In our game the rectangle will be named as player. The width and the height are two integer constant.
- PLAYER_WIDTH = 180
- PLAYER_HEIGHT = 60
The y position of the Player is always the same, and we won’t save it in constant. It will be always the height-PLAYER_HEIGHT. In this case the height is a constant, and we can get it from the Android system. The height is equal with the height of the view.
The x position will change regarding of our touch on the screen. This position will be stored in
- playerX: Float = 0f
For the ball we will have only one constant, and it is the radius.
- CIRCLE_RAD = 50f
The set the position of the Ball, we need only one point on the view, and it is the coordinate of the center point of the circle. This will change also during the game. For the start we will set a default value.
- circleX = 200f
- circleY = 200f
We have to set also the size of the movement. This means that the position of center of the ball will be change during the time. The direction depends on this 2 numbers, are they positive or negative. We will see the detailes later. 🙂
- dX = 10
- dY = 10
The point the simplest part of our game, it is only an integer.
- point = 0
The PongView contains 7 methods
- override fun onSizeChanged(width: Int, height: Int, oldwidth: Int, oldheight: Int)
- override fun onDraw(canvas: Canvas?)
- override fun onTouchEvent(event: MotionEvent?): Boolean
- private fun handleMove(event: MotionEvent)
- fun startGame()
- fun stopGame()
- private fun resetGame()
… and an inner class. This class extended with Thread() and it handles the move of the ball.
Android doesn’t know the real size at the start, it needs to calculate it. Once it’s done, onSizeChanged() will notify us with the real size. onSizeChanged() is called once the size has been calculated.
After the extend our LampView::class, we have to implement the onDraw method. This method will run at the first time, so we will implement here the methods separetly and draw the shapes on the canvas.
This method is called several times as the pressure, size, position, etc. of the touch event changes or even when a new finger is put on the touch screen.
MotionEvent: Motion events describe movements in terms of an action code and a set of axis values. The action code specifies the state change that occurred such as a pointer going down or up. The axis values describe the position and other movement properties.
For example, when the user first touches the screen, the system delivers a touch event to the appropriate View with the action code ACTION_DOWN and a set of axis values that include the X and Y coordinates of the touch and information about the pressure, size and orientation of the contact area.
In our first selfdefined method the playerX variable will be changed if the event is ACTION_MOVE.
playerX = playerX – (touchX – event.x)
playerX → Current position of the player.
touchX → x coordinate of the players tocuh on the screen.
event.x → The X component of the pointer movement.
After this calculation the player rectangle will move at the direction where we scroll with our finger and the distance will be the same.
- If the playerX is minus, then it has to be 0.
- If the player is closer to the right side then it should be, then the value of playerX has to be width – PLAYER_WIDTH.
- else the playerX won’t be changed.
At the end of this method we have to call invalidate() method.
It invalidates the whole view. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future. Generally, invalidate() means ‘redraw on screen’ and results to a call of the view’s onDraw() method. So if something changes and it needs to be reflected on screen, we need to call invalidate().
startGame method starts the thread, which handeld the movement of the ball and sets the boolean variable to true, so later on our Android Pong will know that the game is running.
stopGames sets to false the game enabled boolean variable, fire the resetGame method, and invalidate again the view.
In this method all of the variables will get back the value what they had at the start of the round.
GameThread : Thread()
This is the most important part of the Android Pong game 😉
Direction x of the ball
In case, if the game is running, then the centerpoint of the ball changes every 0.01 milliseconds. If the ball touches the right side of the PongView, then bounced with a minus sign. If it touches the left side then the ball bounced with positive sign.
Direction y of the ball
In case of the direction of y the movement is a little bit different, because the game ends if the centerpoint of the ball is closer to the bottom side of the PongView, then the left top corner of the players rectangle. If it happens, then the resetGame method will be called in case if the x position is not in the range of the x position of the player, otherwise the ball has to bounced back.
After this longer introduction finally the source code of the PongView::class 🙂
Step 4 – MainActivity::class
The last step of our Android Pong game is the MainActivity::class.
It contains only the 2 setOnClickListeners for the Start and for the Stop Buttons.
I hope the description was understandable and clear. But if you have still questions, then leave me comments below! 😉
Have a nice a day! 🙂