Consider the following questions. Some of these we haven’t covered yet explicitly, but it’s a good structure for a discussion with students.
What are the 4 different steps of a variable’s life cycle?
What does the following line do?
float myVariable;
What does the float
mean here?
What about these lines?
float myVariable;
myVariable = 3.14;
And this?
float myVariable = 3.14;
What’s wrong with these lines?
float myVariable = 3.14;
float myVariable = 5.64;
What’s the difference between int
and float
?
What do these lines do?
float x = 3.14;
int y = x;
What’s the difference between putting a variable in a function versus putting it in ofApp.h
?
What happens if you declare a variable in ofApp.h
and within a function?
ofApp.h
:
class ofApp : public ofBaseApp{
public:
// functions not shown
float x
}
ofApp.cpp
:
void ofApp::setup() {
float x = 3.14;
}
What is the result of wholepart
?
float variable = 3.14;
int wholepart = sqrt(abs(variable) * 3) + variable;
This declares a variable called myVariable
. The type of the variable is a float
, which can store decimal numbers.
Here we’re declaring a variable on one line, and assigning it on the next line.
This is an example of declaring and assigning on the same line. It’s a more compact version of #3.
You can’t have two variables with the same name. This will be a compiler error.
int
stores an integer, which is a “whole number”. float
stores a decimal number.
When we assign a float
number to an int
, it truncates the float
— in other words, it rounds down.
Putting a variable in a function means the variable lives for the lifetime of the function. Putting a variable in the .h
file means it persists for the lifetime of the program.
You usually want to avoid this. The version of the variable in the function will be used, and the version of the variable in the .h
file will not be used. This is a confusing subtlety that is best avoided. Don’t name your variables the same thing.
Let’s solve this by thinking like a computer, step-by-step. First, we plug in variable
to the right side of the =
:
int wholepart = sqrt(abs(3.14) * 3) + 3.14;
Then we apply the abs()
(abs gives us mathematical absolute value):
int wholepart = sqrt(3.14 * 3) + 3.14;
Now multiply:
int wholepart = sqrt(9.42) + 3.14;
Apply sqrt
:
int wholepart = 3.0692018506 + 3.14;
Add the two numbers:
int wholepart = 6.2092018506;
We have a decimal number on the right hand side, but we’re storing it in an integer. C++ will truncate (chop off the decimal part) of the number before storing it. So our final value will be:
int wholepart = 6;
Describe a function. What is a function’s purpose?
The simplest type of function is one that doesn’t have any parameters and doesn’t have any return value. How do you add such a function to your program?
You can also write a function that returns output. Write a function called thinkOfANumber()
that returns a random int
between 1 - 10.
Now modify the thinkOfANumber
to add a parameter called high
that determines an inclusive upper bound for the random numbers.
A bit of code that you can write and stash away for later, to be called whenever you want. It also can also optionally accept input (parameters) and produce output (return values).
ofApp.h
:
class ofApp : public ofBaseApp{
public:
// other functions not shown
void myFunction();
}
ofApp.cpp
:
void ofApp::myFunction() {
// function code does here
}
ofApp.h
:
class ofApp : public ofBaseApp{
public:
// other functions not shown
int thinkOfANumber();
}
ofApp.cpp
:
void ofApp::thinkOfANumber() {
return floor(ofRandom(1, 11));
}
void ofApp::setup() {
// now we can use "thinkOfANumber" anywhere in our program
cout << thinkOfANumber() << endl;
cout << thinkOfANumber() << endl;
cout << thinkOfANumber() << endl;
}
ofApp.h
:
class ofApp : public ofBaseApp{
public:
// other functions not shown
int thinkOfANumber();
}
ofApp.cpp
:
void ofApp::thinkOfANumber(int high) {
return floor(ofRandom(1, high + 1));
}
// alternative implementation; does the exact same thing
void ofApp::thinkOfANumber() {
return ceil(ofRandom(0, high));
}
void ofApp::setup() {
// now we can use "thinkOfANumber" anywhere in our program
cout << thinkOfANumber(20) << endl;
cout << thinkOfANumber(100) << endl;
cout << thinkOfANumber(1000) << endl;
}
A good example of something you could do with rotations are orbiting objects. Let’s build a scene with a central spinning planet and an orbiting moon.
There are multiple valid solution, and it’s worth talking about the different approaches with students. Here’s an approach where the rotations are done completely separately:
void ofApp::draw() {
ofBackground(0);
ofPushMatrix();
ofTranslate(ofGetWidth() / 2, ofGetHeight() / 2);
ofRotateDeg(10 * ofGetElapsedTimef());
ofDrawRectangle(-100, -100, 200, 200);
ofPopMatrix();
ofPushMatrix();
ofTranslate(ofGetWidth() / 2, ofGetHeight() / 2);
ofRotateDeg(-20 * ofGetElapsedTimef());
ofTranslate(mouseX, 0);
ofDrawRectangle(-20, -20, 40, 40);
ofPopMatrix();
}
Here’s a version where we have nested rotations:
void ofApp::draw() {
ofBackground(0);
ofTranslate(ofGetWidth() / 2, ofGetHeight() / 2);
ofRotateDeg(10 * ofGetElapsedTimef());
ofDrawRectangle(-100, -100, 200, 200);
ofRotateDeg(-5 * ofGetElapsedTimef());
ofTranslate(mouseX, 0);
ofDrawRectangle(-20, -20, 40, 40);
}
We’ve already used ofRandom
to add randomness to our sketches. ofRandom
has the property the random numbers it generates aren’t related to each other. In other words, they can jump around a lot. Sometimes that’s what we want, but sometimes we want our randomness to be smooth.
openFrameworks has a function for generating smooth, continuous noise. Noise is another word for randomness. However, the ofNoise
function behaves differently than ofRandom
. We pass in coordinates to ofNoise
. If we pass the same coordinates, we get the same value back. However, as we vary the coordinates, we get smoothly changing random movement.
// grab a random value at position (5, 10)
float myValue = ofNoise(5, 10);
TODO: “smoother” intro here
Let’s talk about how to use keyboard input to control an object on screen. There’s an automatically generated function that openFrameworks gives us called keyPressed
, often called an event handler:
void ofApp::keyPressed(int key){
}
Let’s use this function to move a rectangle up and down the window. First, add a float y
to the .h
file:
class ofApp : public ofBaseApp{
public:
// functions not shown
float y;
};
Now let’s draw a rectangle at that y
value in our draw
function:
void ofApp::draw() {
ofDrawRectangle(ofGetWidth() / 2, y, 20, 20);
}
We can we modify our keyPressed
event handler to change our y
value when the user presses the up and down keys:
void ofApp::keyPressed(int key){
if (OF)
}
TODO
My if statements aren’t working!
using = instead of ==