05
repetition

what are lines made of?

pixels

import flash.display.BitmapData;
import flash.display.Bitmap;

var raster:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
var bitmap:Bitmap = new Bitmap(raster);
addChild(bitmap);

raster.setPixel(0, 50, 0x000000);
a ten pixel horizontal line:
raster.setPixel(0, 50, 0x000000);
raster.setPixel(1, 50, 0x000000);
raster.setPixel(2, 50, 0x000000);
raster.setPixel(3, 50, 0x000000);
raster.setPixel(4, 50, 0x000000);
raster.setPixel(5, 50, 0x000000);
raster.setPixel(6, 50, 0x000000);
raster.setPixel(7, 50, 0x000000);
raster.setPixel(8, 50, 0x000000);
raster.setPixel(9, 50, 0x000000);
a 500 pixel horizontal line.. ?

repetition

why computers exist, after all, is to be highly efficient at executing lists of intructions over and over and over. we can take advantage of that strength by constructing loops of instructions.

while

the basic loop has three significant parts:
  1. a counter variable
  2. a termination condition
  3. something that guarantees the termination condition will become true
var i:Number = 0; // 1. creates a variable to count the loop iterations
while (i < 10) {  // 2. tests whether to continue
   trace(i); 
   i++;           // 3. ensures that loop will enventually stop
}

for

the for loop puts the three parts together on one line for convenience and brevity.
for (var i:Number = 0; i < 10; i++) {
    trace(i);
}

drawing with loops

a loop implies range

when you set up a loop counter's initial value and termination condition, you have defined a range of values that will be traversed over the execution of the loop. you can harness those values to draw repeated shapes, like making a line out of a row of pixels. here the range of the loop equates to the length of the line.
var lineLength:Number = 350;
for (var xPos:Number = 0; xPos < lineLength; xPos++) {
    raster.setPixel(xPos, 50, 0x000000);
}
note that the difference now between drawing one pixel or five hundred is one number, not 499 lines of code. loop structures exhibit a high measure of data compression—you can ask the computer to execute a lot of instructions without writing much.

by drawing lines instead of pixels within the loop, we could make a rectangle out of columns of lines.

writing functions

as soon as you accumulate several lines of code that do something useful, it's often convenient to package them into a function so you can reuse the code without having to retype it.

function anatomy

a function has three basic parts:
  1. the declaration, which uses the keyword function and provides a name
  2. the parameter list, which encloses zero or more parameters in parenthesis ( )
  3. the function body, which encloses zero or more statements in curly braces { }
function doesNothing() {}

function parameters

you should think of a function as an autonomous little program that lives alone in a box and doesn't know anything about the world around it except for what's given to it in the form of parameters.

function parameters are variables for use within the function that store the values provided to the function. they're different from the usual variable declaration in that we don't use the keyword var, and the value isn't assigned when we declare the parameter variable; it's assigned when we call the function. but otherwise, they're exactly the same: a container that holds a value labeled with a name that we choose.

suppose we wrote the following function:
function friendlyTrace(msg:String, sender:String) {
    trace("hello, message for you:");
    trace(msg);
    trace(sender);
}
if we were to call it:
friendlyTrace("the eagle has landed.", "agent grey");
then what happens behind the scenes is this: note that we can also define default values for our parameters:
function friendlyTrace(msg:String, sender:String="anonymous") {
    trace("hello, message for you:");
    trace(msg);
    trace(sender);
}
which means we could call it like this now, too, with just a single argument and accept the default value for the second:
friendlyTrace("I'm in ur Homeworks Reading ur codes.");
optional parameters have to be at the end of the parameter list; they can't come before required parameters.

returning values

but what if we want to write a function that does a calculation for us, how can we get the result of the calculation? we use the keyword return and specify a data type for the function itself:
function circumference(diameter:Number):Number {
    var circ:Number = Math.PI * diameter;
    return circ;
}
now the function call can be used as an expression that evaluates to a value:
var wheelDiameter:Number = 17;
var revolutions:Number = 1187;
var distance:Number = circumference(wheelDiameter) * revolutions;
actually all functions will evaluate to a value, which will be undefined unless something is specifically returned. functions that don't return a value should be typed with the datatype void to help the compiler check that we're using the function as intended. the following would generate a 'type mismatch' error:
function foo():void {
    trace("foo");
}

var q:Number = foo();

 

designing functions

a well-designed function will be very flexible, able to be reused in many different environments. the key to writing a portable function is two-fold: no dependencies, and good parameterization.

suppose we wanted to draw a picture with a lot of triangles in it. we realize that having a triangle function will make our code shorter and our lives easier. we could write a function like this:

function drawTriangle() {
   graphics.moveTo(20,80);
   graphics.lineTo(50,20);
   graphics.lineTo(80,80);
   graphics.lineTo(20,80);
}

but nothing about this function is very reusable, because it depends on running in a context that has a Graphics instance existing in a variable named graphics, it assumes lineStyle will be taken care of before it's called, and it doesn't accept any parameters to control where the points of the triangle are— it always draws the exact same triangle.

we can do better by first providing a variable to accept a Graphics instance. this way, any object that has access to a Graphics instance (Shape, Sprite, MovieClip, etc) can make use of this function. next we can expose the points of the triangle as parameters so the function can be used to draw triangles of any shape, at any location. we could also expose more parameters to control the lineStyle, but it's actually not a bad thing to require that lineStyle setup be taken care of before our method is called.

i chose Array as the value type of the point parameters, because if each point is represented as an array, then i only have to accept three point values, instead of six coordinate values, and it looks cleaner. i'll use the convention that the point arrays only contain two values and that the first (index 0) is the x coordinate, and the second (index 1) is the y coordinate.

function drawTriangle(g:Graphics, p1:Array, p2:Array, p3:Array) {
   var x:Number = 0;
   var y:Number = 1;
   graphics.moveTo(p1[x], p1[y]);
   graphics.lineTo(p2[x], p2[y]);
   graphics.lineTo(p3[x], p3[y]);
   graphics.lineTo(p1[x], p1[y]);
}
and now i can draw triangles to my heart's content:
graphics.lineStyle(5, 0x000000);
drawTriangle(graphics, [20,30], [50,90], [70,10]);
drawTriangle(graphics, [10,70], [40,30], [80,90]);

Point

instead of resorting to made-up structures to manage point coordinates, we should have a true point object with actual x and y properties. if you import flash.geom.Point, you'll have just that. see the documentation for details.
import flash.geom.Point;
var P:Point = new Point(0, 0);
and we could now refactor the method above to work with Point instances instead of Arrays:
function drawTriangle(g:Graphics, p1:Point, p2:Point, p3:Point) {
   graphics.moveTo(p1.x, p1.y);
   graphics.lineTo(p2.x, p2.y);
   graphics.lineTo(p3.x, p3.y);
   graphics.lineTo(p1.x, p1.y);
}

graphics.lineStyle(5, 0x000000);
drawTriangle(graphics, new Point(20,30), new Point(50,90), new Point(70,10));
drawTriangle(graphics, new Point(10,70), new Point(40,30), new Point(80,90));