Using for loops to draw the Sub' Hunter grid

By the end of the book we will have used every type of loop but the first one we get to utilize is the for loop. Can you imagine having to write a line of code to draw each and every line of the grid in Sub' Hunter?

We will delete the existing drawLine… code in the draw method and replace it with two for loops that will draw the entire grid!

Here I show you the entire draw method just to be sure you can clearly recognize what to delete and what to add. Add the highlighted code shown next.

void draw() {
   gameView.setImageBitmap(blankBitmap);

   // Wipe the screen with a white color
   canvas.drawColor(Color.argb(255, 255, 255, 255));

   // Change the paint color to black
   paint.setColor(Color.argb(255, 0, 0, 0));

   // Draw the vertical lines of the grid
   for(int i = 0; i < gridWidth; i++){
      canvas.drawLine(blockSize * i, 0,
         blockSize * i, numberVerticalPixels,
         paint);
   }

   // Draw the horizontal lines of the grid
   for(int i = 0; i < gridHeight; i++){
      canvas.drawLine(0, blockSize * i,
         numberHorizontalPixels, blockSize * i,
         paint);
   }

   // Re-size the text appropriate for the
   // score and distance text
   paint.setTextSize(blockSize * 2);
   paint.setColor(Color.argb(255, 0, 0, 255));
   canvas.drawText(
      "Shots Taken: " + shotsTaken +
      "  Distance: " + distanceFromSub,
         blockSize, blockSize * 1.75f,
      paint);


   Log.d("Debugging", "In draw");
   printDebuggingText();
}

To explain the code let's focus on the second for loop. This one:

// Draw the horizontal lines of the grid
for(int i = 0; i < gridHeight; i++){
   canvas.drawLine(0, blockSize * i,
      numberHorizontalPixels, blockSize * i,
      paint);
}

This is the code that will draw all the horizontal lines.

Let's break down the second for loop to understand what is going on. Look at the first line of the second for loop again.

for(int i = 0; i < gridHeight; i++){

The code declares a new variable named i and initializes it to 0.

Then the loop condition is set to i < gridHeight. This means that all the time that i is lower than the value that we previously calculated for gridHeight the code will keep looping.

The third part of the for loop declaration is i++. This simply increments i by 1 each pass through the loop.

If we assume that gridHeight is 24 as it is on the Google Pixel emulator, then the code in the for loop's body will execute 24 times going up from 0 through 23. Let's look at the loop body again.

canvas.drawLine(0, blockSize * i,
               numberHorizontalPixels, blockSize * i,
               paint);

First, remember that this is all just one line of code. It is the limitations of printing in a book which has spread it over three lines.

The code starts off just the same as when we drew two lines in the previous chapter with canvas.drawLine(. What makes the code work its magic is the arguments we pass in as coordinates for the line positions.

The starting coordinates are 0, blockSize * i. This has the effect in the first part of the loop of drawing a line from the top left corner 0,0. Remember that i starts at 0 so whatever blockSize is the answer is still 0.

The next two arguments determine where the line will be drawn to. The arguments are numberHorizontalPixels, blockSize * i. This has the effect of drawing the line to the far right of the screen also at the very top.

For the next pass through the loop, i is incremented to 1 and the arguments in drawLine produce different results.

The first two arguments, 0, blockSize * i end up starting the line on the far left again but this time (because i is 1) the starting coordinate is blockSize pixels down the screen. Remember that blockSize was determined by dividing the screen width in pixels by gridWidth. The blockSize variable holds is exactly the number of pixels we need between each line. Therefore, blockSize * i is exactly the right pixel position on the screen for the line.

The coordinates to draw the line to are determined by numberHorizontalPixels, blockSize * i. This is exactly opposite the starting coordinate on the far right of the screen.

As i is incremented each pass through the loop the line moves the exactly correct number of pixels down each time. The process ends when i is no longer lower than gridHeight. If it didn't we would end up drawing lines that are not on the screen.

The final argument is paint and this is just as we had it previously.

The other for loop (the first one) works in exactly the same way except that the loop condition is i < gridWidth (instead of gridHeight) and the lines are drawn vertically from 0 to numberVerticalPixels (instead of horizontally from 0 to numberHorizontalPixels).

Study both loops to make sure you understand the details. You can now run the code and see the Sub' Hunter grid in all its glory.

Using for loops to draw the Sub' Hunter grid

In the previous image, the newly drawn gridlines are overlaid by the debugging text.