2011-05-23

Start developing for the Roku Part 4: Iterate!

This is the fourth part of a multi-part series. Please be sure to check out Parts 1 through 3.

So far our channel displays a few rectangles we've defined previously. Now, let's explore some code constructs that allow us to process work in a more effective manner.

For now, we'll keep working with the same main.brs file as in the previous parts. This time, we're going to add the following code after the last setLayer() method call, and before the canvas.show() call:

' Create iteratively smaller boxes using a loop
' Array of colors to use
colors = [ "#AA0000", "#0000AA", "#A0A0A0", "#F0F0F0" ]
' Initial location data
shapeLocation = { x: 100, y: 100 }
shapeSize = { w: 400, h: 300 }
for i=0 to colors.count() -1
' Access desired color
c = colors[i]
' Update the location and size data
shapeLocation.x = shapeLocation.x + 25
shapeLocation.y = shapeLocation.y + 25
shapeSize["w"] = shapeSize["w"] - 50
heightVar = "h"
shapeSize[heightVar] = shapeSize[heightVar] - 50
' Add shape to canvas
print "Adding shape"
print shapeLocation
print shapeSize
canvas.setLayer(1+i, {
color: c,
targetRect: shapeSize,
targetTranslation: shapeLocation,
})
end for

That's a doozy, huh? Well, let's get to work explaining this.

The first new non-comment line is assignment of an array. Not an associative array, as we saw previously, but a regular array, which is of set of sequential items. In this case, we are assigning four strings, each a hex color code, to a variable called colors. We'll be using these colors later.

Note: BrightScript isn't picky about what items go in an like some languages. For example, we can easily create an array with the first item being an integer, the second being a string, and the third being another array or associative array.


Next we assign two associative arrays to the variables shapeLocation and shapeSize. These hold the same things their names suggest, but we'll be changing the values we set here later.

Loopty Loop

Here we've gotten to something really new, a for loop. If you don't know what that is, I'll let Wikipedia explain the gory details, and summarize it here as a way to repeat a chunk of code multiple times. Here we are looping by initializing a variable i to 0, and looping until it's no longer true that i is less than colors.count() (i is automatically incremented by one each pass through the loop).

Now, there's one other thing not explained about the loop statement we just went over, and that's what colors.count() means. In this case, since colors contains an array, count() is a method provided for arrays which returns the number of items in the array. Here the value returned is 4 since that's the number of items we set in the array on creation. If we had added or removed items since then, the count() method would represent the current number of items in the array at this point.

Note: By convention we indent while within the loop. This provides an easily identifiable visible clue that this code is slightly different than the surrounding code (it may execute multiple times). Indentation and other non-enforced formatting are a very important part of the source. Ignoring the benefits they bring to the readability of the program source will most likely cost you later.


The first thing we do within the loop is assign the color we want this box to be. In this case, we take the loop variable i and use it as an index into the colors array using square brackets. The first time through the loop, i is 0, so we access the 0th (first for all you non-computer science people out there) item of the array. The first pass through the loop that's the string #AA0000, which is what the variable c now contains.

Note: It may seem odd that we are looping from 0 to the number of items in the array colors minus one, but that's because of a very particular fact of history; the C proggramming language is the most commone one on earth, and 40 years ago it was defined with arrays accessed in this manner (it actually makes some sense in context). We've been living with it ever since in many, many languages that claim some C heritage. Just remember when accessing array elements that item 0 is the first item, and the number of items in the array less one is the last item.


Accessing and Changing Arrays and Associative Arrays

The next 5 lines of code are all accessing and setting the elements of the shapeLocation and shapeSize associative arrays in various ways. I'll cover them in order:
  • shapeLocation.x = shapeLocation.x + 25
    Element x of shapeLocation is set to the value of element x plus 25 more using dot notation.
  • shapeLocation.y = shapeLocation.y + 25
    Element y of shapeLocation is set to the value of element y plus 25 more using dot notation.
  • shapeSize["w"] = shapeSize["w"] - 50
    Element w of shapeSize is lessened by 50 using array subscript syntax
  • heightVar = "h" and shapeSize[heightVar] = shapeSize[heightVar] - 50
    Here we set a new variable, and then use that variable to access the appropriate element of shapeSize. This is the real power of the array subscript syntax.


Note: While the same code is executed each iteration of the loop, the values of the variables end up changing each time. For example, each pass through the loop ends up reducing shapeSize.w by 25, until it eventually ends up at 200, after starting at 400.


Display More Shapes

After a few inconsequential prints to the debugger console, the next thing we do within the loop is draw another rectangle using the setLayer() method. Here we set the layer to 1+i, so we don't overwrite the item we already drew on layer 0 in the first pass of the loop, and draw each of the subsequently smaller rectangles using the color, size and location we've computed earlier in this pass of the loop.

Finally, we end the loop with an end loop statement, and following convention de-indent the code from here on. That's the end of the new code for this part of the tutorial, and that's plenty if I do say so myself. Below you can find the complete contents of the new source/main.brs file, with a few extra spaces and comments thrown in the pretty it up.


sub main()
' Crate canvas component
canvas = CreateObject("roImageCanvas")

' Set background color (no location data means full screen)
canvas.setLayer(0, { color: "#884400" })

' Display a shape
newShapeLocation = { x: 300, y: 200, w: 200, h: 100 }
canvas.setLayer(10, { color: "#00BB00", targetRect: newShapeLocation })

' Display some text
newTextAttributes = {
color: "#0000CC"
font: "Large"
Halign: "Hcenter"
Valign: "Vcenter"
}
canvas.setLayer(5, {
text: "Hello World!",
textAttrs: newTextAttributes,
targetRect: {
x: 200, y: 200, w: 200, h: 100
}
})

' Create iteratively smaller boxes using a loop
' Array of colors to use
colors = [ "#AA0000", "#0000AA", "#A0A0A0", "#F0F0F0" ]
' Initial location data
shapeLocation = { x: 100, y: 100 }
shapeSize = { w: 400, h: 300 }
for i=0 to colors.count() -1
' Access desired color
c = colors[i]
' Update the location and size data
shapeLocation.x = shapeLocation.x + 25
shapeLocation.y = shapeLocation.y + 25
shapeSize["w"] = shapeSize["w"] - 50
heightVar = "h"
shapeSize[heightVar] = shapeSize[heightVar] - 50
' Add shape to canvas
print "Adding shape"
print shapeLocation
print shapeSize
canvas.setLayer(1+i, {
color: c,
targetRect: shapeSize,
targetTranslation: shapeLocation,
})
end for

' Show the canvas
canvas.show()

' Print something to dbugger console
print "canvas shown"

' Sleep so the channel doesn't end immediately
sleep(5000)

end sub


Go ahead and package and upload the channel now. You should see what looks like square rings around the original "Hello World" text (or what is visible of it, at least). This is because each subsequent rectangle was a higher layer then the previous and obscured the previous, yet they were all lower than the text we set before the loop, which stayed in front and thus visible.

That concludes Part 4 of the tutorial. Next we'll go into a bit more detail on functions, and how to use them. I'll try to make it a bit shorter than this tutorial, which ended up going a bit longer than I hoped.

14 comments:

  1. Thanks for the great tutorial on how to get started programming on the Roku with BrightScript. Even though I have been programming for years in many different languages, I simply never got the motivation to get started writing stuff for the Roku. Your tutorial made the process seem very simple and I really enjoyed stepping through the examples you wrote.

    Thanks again for sharing this with everyone!

    ReplyDelete
  2. Glad you found some use in it! If you have questions, the developer forum at forums.roku.com has lots of helpful people.

    ReplyDelete
  3. Why did you quit doing these? :P They were really good tutorials.

    ReplyDelete
  4. OH Man you are osome person.please Continue next part i am waiting very exitedly.

    ReplyDelete
  5. Hmm, there still seems to be some traffic to these. Maybe I'll get around to writing part 5...

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Thank you for writing these tutorials, they have been most helpful. Please consider writing more!

      Delete
  6. These are great tutorials... Yeah please continue to the next ones! It's hard to find easy to understand tutorials on this for non-coders. When you explain what the code actually does that is a huge help!

    ReplyDelete
  7. Please continue your great tutorials. I also have been programming for years and can tell you not enough programmers are willing to take the time to explain
    things as you have. THANK YOU...

    ReplyDelete
  8. I just finished going through these four tutorials, enjoying the process very much! I almost didn't post anything here, and I wonder how many others have been helped a lot but didn't post. Please consider whipping up part 5 (and parts 6-12 too!), you're SOOOO good at writing and explaining this stuff in plain English!

    ReplyDelete
  9. Agreed. I wish more people would comment and say thank you for the tutorial and wish you would continue. Thanks for 1-4.

    ReplyDelete