# Flappy Bird – Scoring

In the very last lecture of the Flappy Bird tutorial we learned how to add to game the collision detection. When the circle of the bird overlap the rectangels of the pipes, then we are going to get a log message in the Logcat of the Android Studio.

In this lecture we are going to learn how to add the scoring to the Flappy Bird game. It means the score has to be even higher when our bird could fly through the gap of the pipes.

Before the start we have to clarify when we will get 1 score. When the bird could fly through the gap between the pipes, but it is not quite true. In the previous lecture we defined the collision detection. If the birds circle overlap the rectangelas of the pipes, then the bird collided with the pipes. In case if the bird is in the gap, then logically this shapes won’t be overlaped, so we can the score. It looks like easier, right? 🙂 So let’s start coding.

#### Step 1 – Scoring integer

The first thing what we are going to do is the scoring integer variable. We ill define it in the FlappyBird::class and the initial value will be 0, because at the start of the game we won’t we point, logically.

var score = 0

#### Step 2 – Scoring pipe

During the game we have to that the bird could fly through the gap of the pipes or it couldn’t. For this we have to wher is the next pipe. As we have defined earlier, we have in the same time 4 pipes in the game. Every pipe has a specific x position on the screen. They are stored in the pipeX mutableList.

We will get a score, when the pipe’s x position is less then the half of the width. It means the bird could fly through the gap. So we will define an if-statement inside of the render method and when the gameState not null, but before the our touch.

``````if(pipeX[scoringPipe] < Gdx.graphics.width / 2)
{
score++

Gdx.app.log("Score", "\${score}")

if(scoringPipe < numberOfPipes - 1)
{
scoringPipe++
}
else
{
scoringPipe = 0
}
}

Scoring``````

What you can see in the if-statements is that first we check the position of the current pipe, then the score is going to be increased by one, and we will jump to the next pipe.

#### Step 3 – Show the collected points

Now we are counting the points, but we have only a log message. We want to see it on the screen. For this we have 10 images in the assests folder from 1.png to 9.png.

As we have done with the states of the bird’s flap, we are going to have a mutableList, and it will contain the 10 images. We will add to the list the images using a for-loop in the create method.

for (i in 0..9)
{
}

To figure out which picture and where has to be visible is a little bit difficult, but don’t worry, I am going to explaine it. 🙂

We have to split the score to it’s digits, because we have to know in every position of the score number the exact number. If we know this, then we can set the correct number’s picture. To do that we will use modulo by 10. After that we will get the numbers in reverse order, so we have to call reverse on the list of the numbers the reverse method. We are going to do that only if the score is higher then 0.

To draw the correct numbers in the correct order next to each other we will add to the x position the size multiplied by the i variable from the for-loop.

``````val scoreDigits = mutableListOf()
var _score = score
if (_score == 0)
{
batch!!.draw(
scoreTextures,
size,
Gdx.graphics.height - size*2,
size,
size)
}
else
{
while (_score > 0)
{
_score /= 10
}
scoreDigits.reverse()<br />
Gdx.app.log("scoreDigits", "\$scoreDigits")
for (i in 0 until scoreDigits.count())
{
batch!!.draw(
scoreTextures[scoreDigits[i]],
size*(i+1),
Gdx.graphics.height - size*2,
size,
size)
}
}

Scoring textures``````

If you are surprised why we do use the _score variable, then here is the answer 🙂 During the while loop, where we split the score integer to it’s digits, we have to modify the score variable, and we are going to see always 1 digit on the screen.

#### Step 4 – FlappyBird::class

If you are lost, then you can compare your source code here with our whole FlappyBird::class

``````import com.badlogic.gdx.ApplicationAdapter
import java.util.*
import kotlin.math.min

{
var batch: SpriteBatch? = null
var backGround: Texture? = null
var birdsState = mutableListOf()
var topPipe: Texture? = null
var bottomPipe: Texture? = null

var size: Float = 0f

var flapState = 0

var birdY: Float = 0f
var velocity: Float = 0f

var gameState = 0
var gravity = 2f

var gap = 0f

// Maximum up and down of the pipes
var maxPipeOffset = 0f

var randomGenerator: Random? = null

val pipeVelocity = 4
val numberOfPipes = 4
var distHorBwPipes = 0
var pipeX = FloatArray(numberOfPipes)

var distVertBwPipes = FloatArray(numberOfPipes)

//Collision detection
var birdCircle: Circle? = null
var topPipeRect = mutableListOf()
var bottomPipeRect = mutableListOf()
//    var shapeRenderer: ShapeRenderer? = null

// Scoring
var score = 0
var scoringPipe = 0
var bitmapFont: BitmapFont? = null
var scoreTextures = mutableListOf()

override fun create()
{
batch = SpriteBatch()

size = min(
(Gdx.graphics.width*0.1).toFloat(),
(Gdx.graphics.height*0.1).toFloat()
)

birdCircle = Circle()
//shapeRenderer = ShapeRenderer()

bitmapFont = BitmapFont()
bitmapFont!!.setColor(Color.WHITE)
bitmapFont!!.data.scale(size/10)

gap = size*4

backGround = Texture("background-day.png")

topPipe = Texture("topPipe.png")
bottomPipe = Texture("bottomPipe.png")

for(i in 0..9)
{
}

birdY = (Gdx.graphics.height/2 - size/2)

maxPipeOffset = (Gdx.graphics.height - gap - gap/2)

randomGenerator = Random()

distHorBwPipes = Gdx.graphics.width * 3/4

for (i in 0 until numberOfPipes)
{
pipeX[i] = (Gdx.graphics.width + i* distHorBwPipes).toFloat()
distVertBwPipes[i] = (randomGenerator!!.nextFloat() - 0.5f) * maxPipeOffset

}
}

override fun render()
{
batch!!.begin()
//shapeRenderer!!.begin(ShapeRenderer.ShapeType.Filled)
//shapeRenderer!!.setColor(Color.BLUE)

// Background
batch!!.draw(backGround,
0f, 0f,
Gdx.graphics.width.toFloat(),
Gdx.graphics.height.toFloat())

if (gameState != 0)
{
if(pipeX[scoringPipe] < Gdx.graphics.width / 2)
{
score++

Gdx.app.log("Score", "\${score}")

if(scoringPipe < numberOfPipes - 1)
{
scoringPipe++
}
else
{
scoringPipe = 0
}
}

if(Gdx.input.justTouched())
{
velocity = (-gap*0.07).toFloat()
}

for (i in 0 until numberOfPipes)
{
if(pipeX[i] < -size*2)
{
pipeX[i] = pipeX[i] + numberOfPipes * this.distHorBwPipes
distVertBwPipes[i] = (randomGenerator!!.nextFloat() - 0.5f) * maxPipeOffset
}
else
{
pipeX[i] = pipeX[i] - pipeVelocity
}

// Top Pipe
batch!!.draw(
topPipe,
pipeX[i],
(Gdx.graphics.height / 2 + gap / 2) + distVertBwPipes[i],
size*2,
(Gdx.graphics.height / 2 - gap / 2) + maxPipeOffset*0.5f
)
// Bottom Pipe
batch!!.draw(
bottomPipe,
pipeX[i],
0f - (Gdx.graphics.height - gap - gap/2)*0.5f + distVertBwPipes[i],
size*2,
(Gdx.graphics.height/2 - gap/2) + maxPipeOffset*0.5f
)

topPipeRect[i].set(
pipeX[i],
(Gdx.graphics.height / 2 + gap / 2) + distVertBwPipes[i],
size*2,
(Gdx.graphics.height / 2 - gap / 2) + maxPipeOffset*0.5f)
//                shapeRenderer!!.rect(
//                        topPipeRect[i].x,
//                        topPipeRect[i].y,
//                        topPipeRect[i].width,
//                        topPipeRect[i].height
//                )

bottomPipeRect[i].set(
pipeX[i],
0f - (Gdx.graphics.height - gap - gap/2)*0.5f + distVertBwPipes[i],
size*2,
(Gdx.graphics.height/2 - gap/2) + maxPipeOffset*0.5f)
//                shapeRenderer!!.rect(
//                        bottomPipeRect[i].x,
//                        bottomPipeRect[i].y,
//                        bottomPipeRect[i].width,
//                        bottomPipeRect[i].height
//                )
}

if(birdY > 0 || velocity < 0)
{
velocity += gravity
birdY -= velocity
}

when(flapState)
{
0 -> flapState = 1
1 -> flapState = 2
2 -> flapState = 3
3 -> flapState = 0
}
}
else
{
if(Gdx.input.justTouched())
{
gameState = 1
}
}

// Bird
batch!!.draw(
birdsState[flapState],
(Gdx.graphics.width/2 - size/2),
birdY,
size,
size)

//        bitmapFont!!.draw(batch, "\$score", size, Gdx.graphics.height - size)

val scoreDigits = mutableListOf()
var _score = score
if (_score == 0)
{
batch!!.draw(
scoreTextures,
size,
Gdx.graphics.height - size*2,
size,
size)
}
else
{
while (_score > 0)
{
_score /= 10
}
scoreDigits.reverse()<br />
Gdx.app.log("scoreDigits", "\$scoreDigits")
for (i in 0 until scoreDigits.count())
{
batch!!.draw(
scoreTextures[scoreDigits[i]],
size*(i+1),
Gdx.graphics.height - size*2,
size,
size)
}
}

birdCircle!!.set(
(Gdx.graphics.width/2f),
birdY + size/2,
size/2)

//        shapeRenderer!!.circle(
//                birdCircle!!.x,
//                birdCircle!!.y,

// Collision Detection
for (i in 0 until numberOfPipes)
{
if(Intersector.overlaps(birdCircle, topPipeRect[i]) ||
Intersector.overlaps(birdCircle, bottomPipeRect[i]))
{
Gdx.app.log("Collision", "Detected!")
}
}

batch!!.end()
//        shapeRenderer!!.end()
}
}

FlappyBird::class``````

In the next lecture we will finish our Flappy Bird tutorial with game over screen.

#### Questions

I hope the description was understandable and clear. But if you have still questions, then leave me comments below! 😉

Have a nice a day! 🙂

Click to rate this post!
[Total: 0 Average: 0]

## 2 thoughts on “Flappy Bird – Scoring”

1. Verdell Armstrong says:

Informative article, just what I was looking for.

1. inspirecoding says:

Great, have fun 😉