Session 2: Variables and Methods

Write methods that use the information in their parameter variables.
  1. Using parameter variables
  2. Calling a method
  3. Writing a method
  4. Instance variables

1. Using parameter variables

In the method signature for onMousePress(), the parentheses contain the phrase "Location point". We know what a Location is now, so what does the point mean?

This is an example of a parameter variable. A variable, in programming, is a label that I stick on an object in order to be able to refer to it later in my code; a parameter variable is a label refering to one of the parameters given to that method when it runs. It "varies" because every time the method is called, that variable will end up attached to a different object. You can see this if I put in an instruction to print out the value of point every time I click the mouse:

public void onMousePress(Location point) {
    System.out.println(point);
}

The method System.out.println() is a useful one to remember; it prints out the value of a variable in the console in Eclipse. If you run "UsingParameters.java" in "S2-VariablesAndMethods", you can see that the Location printed out in the console corresponds to where you clicked in the window.

The phrase "Location point" is like saying "Doctor Joe" or "Janitor Bob" - the first word is saying what type of object I'm dealing with, the second is the name. Location, as we learned before, is a class, a type of object. Since point is the name of a particular Location, I can use the word point in my code anywhere I would use a Location object. This code, for example, would draw a 10 by 10 rectangle with its top corner where I clicked:

public void onMousePress(Location point) {
    new FilledRect(point, 10, 10, canvas);
}

So, just to quickly review who we've learned so far: point is a parameter variable that can be used to refer to a Location object that was passed as a parameter to the onMousePress() method. I can use it in my code, and it will be replaced by whatever point the user clicked at. Since that point is different every time you click, the same new FilledRect() instruction can make rectangles all over the screen.

Quick exercise:
Modify the program "UsingParameters.java" so that when the mouse is moved, a line is drawn from (0, 0) to the mouse location, and when the mouse is dragged, a line is drawn from (400, 400) to the mouse location. (You can eliminate the mouse-pressed behavior).
Give me a hint?
First, let's think about what methods you will need. You have to respond to mouse moving and dragging, so copy in these method signatures:

public void onMouseMove(Location point) {
    
}

public void onMouseDrag(Location point) {
    
}

You can eliminate the onMousePress() method, since you don't want to do anything special in that situation.

Now, you have to Figure out how to draw a line from (0, 0) to the point where the user clicked. You know that you can create a line from (0, 0) to, say, (163, 92) with this code:

new Line(new Location(0, 0), new Location(163, 92), canvas);

Now you have point, which you can use in the place of a Location object. What in the line above would you want to replace with point to have the line go from (0, 0) to where the mouse is?
OK, just tell me.
My code looks like this:

public void onMouseMove(Location point) {
    new Line(new Location(0, 0), point, canvas);
}

public void onMouseDrag(Location point) {
    new Line(new Location(0, 0), point, canvas);
}

2. Calling a method

So far, we have only made methods with the intention of having them be triggered by some user-generated event. However, it is also possible to write an instruction that will run a particular method. This is known as "calling" the method.

Let me give you an example of this. The Location class defines a method called translate() that will tell a Location object to move itself by some amount in the x coordinate and some amount in the y. If I wanted to shift the point in onMousePress() ten to the left and up five, I could do this:

public void onMousePress(Location point) {
    point.translate(-10, -5);
    new FilledRect(point, 20, 10, canvas);
}

So, for example, if point started out as (285, 159), this would translate it to (285 - 10, 159 - 5) = (275, 154). I've used this to make the rectangle appear centered around where the mouse was clicked.

Pay attention to exactly how I formulated the instruction telling point to translate itself. I first wrote what object is being asked to run the method, then a ".", then the name of the method. Then, just as with an object creation instruction, I have a set of parentheses containing parameters, and the instruction ends with a semicolon.

What if I want to call a method of an object that is not a parameter and thus isn't stored in a variable? You can make up a new variable name and assign it to refer to that object:

FramedOval oval = new FramedOval(10, 10, 80, 80, canvas);

Notice how, when declaring the variable, I have to give both the type and the name ("Farmer John"), just as I did in the method signature. Once I have assigned that variable to refer to the new object, I can use just the variable name (oval) to refer to that object I just created. So, for example, this would set my oval to have a wider line:

oval.setLineWidth(20);

It is also possible to call methods of the program itself. There is a special variable this that always refers to the object running the current method. So, if I wanted to start out my program acting as if the user had already clicked in two particular places, I could do this:

public void begin() {
    this.onMousePress(new Location(171, 308));
    this.onMousePress(new Location(254, 67));
}

Quick exercise:
Make three changes to the program "UsingParameters.java" that you worked on in the previous section:
Give me a hint?
I intentionally wrote this problem so that you will have to use all three types of method calling that we just talked about. One of the parts is an example of calling a method of a parameter variable, one requires you to assign a new variable to refer to an object you just created, and one will require you to call a method of this, the special variable referring to the program itself.

You won't need to create any new methods to solve this; you should only have to modify the ones you already have.
OK, just tell me.
My code looks like this:

public void onMouseMove(Location point) {
    Line line = new Line(new Location(0, 0), point, canvas);
    line.setLineWidth(10);
}

public void onMouseDrag(Location point) {
    point.translate(10, -10);
    this.onMouseMove(point);
}

Notice how:

3. Writing a method

Now that you have seen that it is possible to call your own methods using this, you can probably guess that you are allowed to write any method you want in your program and call it with an instruction in another method. There are two big reasons you will want to do this.

First, if two different methods do similar things, you can have them both call a shared method, rather than having the same set of instructions appear in two different places in your program. That way, if you change those shared instructions, you only need to change them in one place.

Second, if a method is very long - longer than about 10 instructions - it makes sense to break it up into smaller methods that are called one after the other. This just makes your code easier to read - someone can look at the big method to see an overview of the tasks being done, then look into one of the smaller methods to see the actual instructions used. So, for example, your code to get ready in the morning might look like this:

public void begin() {
    shower();
    getDressed();
    eatBreakfast();
    brushTeeth();
}

public void brushTeeth() {
    Toothbrush brush = sink.getToothbrush(this);
    if(brush.isOld) brush = new Toothbrush();
    
    Toothpaste paste = sink.getToothpaste();
    if(paste.isEmpty()) paste = new Toothpaste();
    
    paste.dispense(brush);
    brush.brush(teeth);
    sink.rinse(mouth);
    sink.rinse(brush);
}

If I had put four methods worth of instructions all in begin(), it would be hard to tell what's what. Here, someone looking at begin() can quickly see what major tasks are being done, and then look at one of the other methods if they need to to see exactly how it works.

When writing your own methods, you get to choose not only the name, but also what the parameters will be. So far we have only seen objects used as parameters, but parameters can also be a number - the number type is called double. So, this method would make a circle of a particular diameter with a particular topLeft corner:

public void makeOval(double diameter, Location topLeft) {
    new FilledOval(topLeft, diameter, diameter, canvas);
}

I would call that method like this:

this.makeOval(30, new Location(60, 60));

Exercise: Understanding code
One nice thing about double variables is that you can use them as part of a mathematical expression. Take a look at WritingMethods. Suppose that I were to call:

this.makeSpot(new Location(120, 260), 100);

What objects would be created, with what parameters and what line widths?
Give me a hint?
you can solve this by going through the code line by line and putting the value of each variable in the place of its name. The only tricky part is that the first line changes the value of point.
OK, just tell me.
In the first line, if I substitute in 100 for size, it looks like:

point.translate(-50, -50);

So, point will be move to (70, 210). The next two lines of code, then, make a new FramedOval(70, 210, 100, 100, canvas) and set its width to 30. Then, the last two lines of code make a new FramedRect(70, 210, 100, 100, canvas) and set its line width to 10.


Exercise: Writing a method for your own program
Going back to "UsingParameters.java", write a method with this signature:

public void drawLine(Location start, Location end, double width) {
    
}

Fill in the method so that it draws a line with the given start and end points and width. Then, modify your program so moving the mouse draws a line from (0, 0) to the mouse, only one wide, and dragging the mouse draws a line from (400, 400) to the mouse, three wide.
Give me a hint?
To write the drawLine() method, you will have to create a Line using the two given Locations as parameters. You will want to store it in a variable, because the next thing you will need to do is to set its width to width.

The onMouseDrag() and onMouseMove() methods should bother just have a single instruction, calling this.drawLine(). They will of course pass different sets of parameters.
OK, just tell me.
My code looks like this:

public void drawLine(Location start, Location end, double width) {
    Line line = new Line(start, end, canvas);
    line.setWidth(width);
}

public void onMouseMove(Location point) {
    drawLine(new Location(0, 0), point, 1);
}

public void onMouseDrag(Location point) {
    drawLine(new Location(400, 400), point, 1);
}

4. Instance variables

We now understand how information is passed as a parameter from one method to another. But suppose that I want to have one method do something for which it needs to know what happened in an earlier method. For example, suppose that I want to be able to press and release the mouse, and have onMouseRelease() draw a line to where the mouse is *from where the mouse was pressed. How can I do that?

The problem here is how to store the point from onMousePress() somewhere where it will be kept until onMouseRelease() is later called, and where it will be accessible to onMouseRelease(). The way to accomplish this is to define an instance variable:

public class LineDrawing extends FrameWindowController {
    Location pressPoint;
    
    public void onMousePress(Location point) {
        pressPoint = point;
    }
    
    public void onMouseRelease(Location point) {
        new Line(pressPoint, point, canvas);
    }
    
    public static void main(String[] args) {
        new UsingInstanceVariables();
    }
}

In this program, pressPoint is my instance variable. Notice that I declare it just like any other variable, but I declare it in the class block rather than inside a method. Instance variables have two useful properties:
Exercise: Make the LineDrawing update as the mouse drags
It would be nicer if the LineDrawing program showed the line being drawn while the mouse was dragging, instead of having it appear suddenly when the mouse is released. If you create the line already when the mouse is pressed, having it just connect point to itself, then you can later change the end point by telling the line to setEnd(), passing a Location object.
Give me a hint?
What was not made explicit in the problem statement is that, instead of having an instance variable to remember a Location, you will be remembering the whole Line. That means you will change the type to Line where the variable is declared, and in onMousePress() you will create a Line and store it in that object. Then, in onMouseDrag(), rather than creating a new line, you will simply tell the saved one to setEnd().
OK, just tell me.
My code looks like this:

public class LineDrawing extends FrameWindowController {
    Line line;
    
    public void onMousePress(Location point) {
        line = new Line(point, point, canvas);
    }
    
    public void onMouseRelease(Location point) {
        line.setEnd(point);
    }
    
    public static void main(String[] args) {
        new UsingInstanceVariables();
    }
}


Optional exercise: More practice with variables and methods
Your browser doesn't do Java.
This exercise builds on the Lego exercise from the previous session. Click on the applet to the right and try pressing the H, A, and L keys to alter in some way the head, arms, and legs of the lego person.

As you can see, the head disappears when you press H, and reappears when you release it. When you press L, the legs change from being all blue, to being green with a gray waist; they change back when you release L. When you press A, the arms detach from the body. When you release A, they reattach, but on the opposite sides.

There are methods setHead(), setLegs(), setRightArm(), and so on that you can use to do all this. Of course, if you set something to null, it will disappear. Detaching the arms was done by telling each arm to detach(). Swapping the arms is a bit more tricky, because you will have variables used to hold each arm and you somehow have to reverse what the two variables refer to. You might be tempted to do this:

left = right;
right = left;

... but that would result in both now referring to the same object. The trick is to declare another variable as a temporary storage place for the old value of left, so that you can safely overwrite that value.
Give me a hint?
As usual, it will help to frame the problem if you start out by figuring out what methods you need, and writing them in to the program. You have to respond to press and release events on three different keys, as well as setting things up when the program starts.

Next, think about what instance variables you will need - what objects do you need to hold on to so that your methods can manipulate them? I think that you will at least need to hold on to the Body, both Arms, the Head, and the Legs. Make sure those variables are declared at the top of the class, and make sure that you assign them to the proper objects in begin(). You can create and assign the various pieces first, and create the Body last, passing along the now-assigned variables as its parameters.

Making the head vanish is just a matter of setting the body to have no head. When you want it back, set the body's head back to the original. The legs are just a variation on this theme, setting the legs to a completely new set, then back to the original. Swapping the value of the Arm variables uses a very common programming idiom:

Arm temp = left;
left = right;
right = temp;

The "temp" variable lets me keep a label on the old left arm after I've set the left variable to refer to the same object as the right.
OK, just tell me.
My code looks like this:

public class MoreCompoundObjectPractice extends FrameWindowController {
    Head head;
    Legs legs;
    Arm right;
    Arm left;
    Body body;
    
    public void begin() {
        head = new Head();
        legs = new Legs(new Leg(), new Leg());
        right = new Arm(new Hand(), Color.CYAN);
        left = new Arm(new Hand(), Color.MAGENTA);
        body = new Body(head, legs, right, left, canvas);
        
        body.moveTo(200, 170);
    }
    
    public void onAPress() {
        right.detach();
        left.detach();
    }
    
    public void onARelease() {
        Arm temp = left;
        left = right;
        right = temp;
        
        body.setLeftArm(left);
        body.setRightArm(right);
    }
    
    public void onLPress() {
        body.setLegs(new Legs(new Leg(Color.GREEN), new Leg(Color.GREEN), Color.GRAY));
    }
    
    public void onLRelease() {
        body.setLegs(legs);
    }
    
    public void onHPress() {
        body.setHead(null);
    }
    
    public void onHRelease() {
        body.setHead(head);
    }
    
    public static void main(String[] args) {
        new MoreCompoundObjectPractice();
    }
}


You now know most of the techniques that you need in order to write responsive Java programs. You are able to use the parameters to your event methods to figure out where the event happened, and you can save information in instance variables to use later.

In the next session, we will start right out by writing a program that works over the network, so that what happens on one computer can be seen by them all. Then, we will learn a few last pieces of Java grammar in preparation for writing our first real game.

back to Creating Network Games with ObjectDraw.