Implementing TetrisView

As you may have guessed, at this point TetrisView is far from completion. First and foremost we must implement a few setter methods for the model and activity properties of the view. These methods are shown below. Make sure to add them to your TetrisView class.

fun setModel(model: AppModel) {
this.model = model
}

fun setActivity(gameActivity: GameActivity) {
this.activity = gameActivity
}

setModel() and setActivity() are setter functions for the model and activity instance properties. As the names imply, setModel() sets the current model in use by the view and setActivity() sets the activity in use. Now, let us add three additional methods setGameCommand(), setGameCommandWithDelay() and updateScore().

fun setGameCommand(move: AppModel.Motions) {
if (null != model && (model?.currentState == AppModel.Statuses.ACTIVE.name)) {
if (AppModel.Motions.DOWN == move) {
model?.generateField(move.name)
invalidate()
return
}
setGameCommandWithDelay(move)
}
}

fun setGameCommandWithDelay(move: AppModel.Motions) {
val now = System.currentTimeMillis()

if (now - lastMove > DELAY) {
model?.generateField(move.name)
invalidate()
lastMove = now
}
updateScores()
viewHandler.sleep(DELAY.toLong())
}

private fun updateScores() {
activity?.tvCurrentScore?.text = "${model?.score}"
activity?.tvHighScore?.text = "${activity?.appPreferences?.getHighScore()}"
}

 setGameCommand() sets the current motion command being executed by the game. If a DOWN motion command is in execution, the application model generates the field for a block experiencing a downward motion. The invalidate() method being called within setGameCommand() can be taken as a request to draw a change on the screen. invalidate() ultimately results in a call to onDraw().

onDraw() is a method that is inherited from the View class. It is called when a view should render its content. We will need to provide a custom implementation of this for our view. Add the code below to your TetrisView class.

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
drawFrame(canvas)

if (model != null) {
for (i in 0 until FieldConstants.ROW_COUNT.value) {
for (j in 0 until FieldConstants.COLUMN_COUNT.value) {
drawCell(canvas, i, j)
}
}
}
}

private fun drawFrame(canvas: Canvas) {
paint.color = Color.LTGRAY

canvas.drawRect(frameOffset.width.toFloat(),
frameOffset.height.toFloat(), width - frameOffset.width.toFloat(),
height - frameOffset.height.toFloat(), paint)
}

private fun drawCell(canvas: Canvas, row: Int, col: Int) {
val cellStatus = model?.getCellStatus(row, col)

if (CellConstants.EMPTY.value != cellStatus) {
val color = if (CellConstants.EPHEMERAL.value == cellStatus) {
model?.currentBlock?.color
} else {
Block.getColor(cellStatus as Byte)
}
drawCell(canvas, col, row, color as Int)
}
}

private fun drawCell(canvas: Canvas, x: Int, y: Int, rgbColor: Int) {
paint.color = rgbColor

val top: Float = (frameOffset.height + y * cellSize.height + BLOCK_OFFSET).toFloat()
val left: Float = (frameOffset.width + x * cellSize.width + BLOCK_OFFSET).toFloat()
val bottom: Float = (frameOffset.height + (y + 1) * cellSize.height - BLOCK_OFFSET).toFloat()
val right: Float = (frameOffset.width + (x + 1) * cellSize.width - BLOCK_OFFSET).toFloat()
val rectangle = RectF(left, top, right, bottom)

canvas.drawRoundRect(rectangle, 4F, 4F, paint)
}

override fun onSizeChanged(width: Int, height: Int, previousWidth: Int, previousHeight: Int) {
super.onSizeChanged(width, height, previousWidth, previousHeight)

val cellWidth = (width - 2 * FRAME_OFFSET_BASE) / FieldConstants.COLUMN_COUNT.value
val cellHeight = (height - 2 * FRAME_OFFSET_BASE) / FieldConstants.ROW_COUNT.value
val n = Math.min(cellWidth, cellHeight)
this.cellSize = Dimension(n, n)
val offsetX = (width - FieldConstants.COLUMN_COUNT.value * n) / 2
val offsetY = (height - FieldConstants.ROW_COUNT.value * n) / 2
this.frameOffset = Dimension(offsetX, offsetY)
}

The onDraw() method in TetrisView overrides the onDraw() in its superclass. onDraw(), takes a canvas object as its only argument and must call the onDraw() function in its superclass. This is done by invoking super.onDraw() and passing the canvas instance as an argument.

After invoking super.onDraw(), onDraw() in TetrisView invokes drawFrame(), which draws the frame for TetrisView. After which, individual cells are drawn within the canvas by utilizing the drawCell() functions we created. 

The setGameCommandWithDelay() works similarly to setGameCommand() with the exception that updates the game score and it puts viewHandler to sleep after executing the game command. The updateScore() function is used to update the current score and high score text views in game activity.

The onSizeChanged() is a function that is called when the size of a view has changed. The function provides access to the current width and height of the view, as well as its former width and height. As with other overriden functions we have used, we invoke its counterpart function in its super class. We use the width and height arguments provided to us to calculate and set dimensions for the size of each cell—cellSize. Finally, in onSizeChanged(), the offsetX and offsetY are calculated and used to set frameOffset.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.123.126