Object-Oriented Programming

Last Time

Characters are encoded in ASCII, which maps numbers to symbols.

Strings are internally implemented as an array of characters, but this is not exposed to you as the user! Have to use special methods.

void setup(){
  String s = "Hello there!";

  // Like before, we cannot mix string and char
  // initializations. These lines are both illegal.
  String x = 'howdy';
  String z = 'z';
  
  // While strings are internally arrays of
  // chars, Processing intentionally hides
  // this from you. This line is illegal.
  char s3 = s[3];
}

Read files with loadStrings()

Write files with PrintWriter class

Fonts

Strings and characters control the content of text, fonts and layout control how it's displayed.

Questions

What makes Unicode so hard to work with?

A small slice of the problem at https://eev.ee/blog/2015/09/12/dark-corners-of-unicode/

What is the correct way to capitalize "istanbul"?
  1. Istanbul
  2. İstanbul

Which of the following strings are whitespace?

  1. "   "
  2. "‎‎‎‎‎    "
  3. "    "

What is the length of this string?

"💣"

How do we sort the following strings alphabetically?

  1. ㅎㅏㄴ ㄱㅡㄹ
  2. Pokémon

  3. Между нами

How do fonts deal with Unicode and different languages?

In practice: split fonts into language packs. Only download font parts that you need on your system.

Unicode literally has two different glyph which are intended to be used when the software cannot display a symbol (e.g. when the font does not have a glyph for that codepoint)

Do people still make fonts?

IBM Plex family (2018)

Adobe Source Code Pro (2012)

Can we make our own fonts?

Absolutely! You can do it in a variety of ways: most pro fonts these days are made with designers, but you can also vectorize handwritten texts.

Are some fonts more efficient than others?

Generally, no. Some things will cause font layout engines to work a lot harder (e.g. Arabic) but that's usually a function of the language and not the font.

How large does a text file have to be before pulling it in all at once starts to affect your runtime?

It varies from computer to computer, but BIG.

 

A rule of thumb on modern desktop/laptop class systems is that a file load of 1GB is noticeable but not annoying.

Would vector fonts be better than bitmapped fonts for an 8-bit game?

Can we move text across the screen like we can with shapes?

No, sometimes you want the "ugliness" of bitmap fonts for aesthetic reasons.

Yep.

float xpos;

void setup(){
  size(1000,500);
  xpos = 0.0;
}

void draw(){
  background(50);
  xpos += 1.0;
  textSize(50);
  text("Away into the unknown!", 
                      xpos, 300);
}

How do you handle multiple keypresses in Processing?

How are vector fonts any better if they're ultimately being displayed on a pixel grid?

import java.util.HashMap;
HashMap<char, boolean> keysHeld;

void keyPressed(){
  keysHeld.put(key, true);
}

void keyReleased(){
  keysHeld.put(key, false);
}

Vector fonts retain the info needed to scale them up on a pixel grid, bitmaps do not.

Hands-On Demo

Simplifying Code

So far, all the systems we've worked on have been relatively simple.

Real graphics are complex!

https://processing.org/examples/multipleparticlesystems.html

  • Codebase size:
    • 3000 lines of C
    • 8500 lines of C++ code
    • 17,000 lines of C++ headers
    • Doesn't count external libraries for doing math, handling vectors, etc.

How can we control the complexity of our code?

Alt. Phrasing: How can we make it harder to get things wrong?

Case Study: A Car

We're going to model a very simple car.

Our car has two variables: fuel and speed.

 

It can do three things:

  • Accelerate: reduce fuel and add speed
  • Decelerate: reduce speed
  • Refuel: add fuel

What are some logical limits on how these actions work?

We're going to model a very simple car.

Variables:

  • Speed
  • Fuel

 

Actions the car can take:

  • Accelerate
  • Decelerate
  • Refuel

Rules that we might want to enforce:

  • A car cannot accelerate if it has no fuel.
  • A car cannot decelerate if its speed is zero.
  • A car can never have negative fuel.
  • A car cannot refuel past its tank capacity.

If we accidentally break one of these rules, we've generated a bug!

Enforcing Rules: Attempt 1

Just remember to apply the rules!

float car1_speed = 0.0;
float car1_fuel = 0.0;

// Lots of intermediate code

// car1_fuel -= 0.5;
// car1_speed += 100.0;

if (car1_fuel > 0.5){
  car1_fuel -= 0.5;
  car1_speed += 100.0;
}
float car1_speed = 0.0;
float car1_fuel = 0.0;

// Lots of intermediate code

car1_speed += 100.0;

Remembering is not safety

Enforcing Rules: Attempt 2

Use functions so that we can't forget to do all the operations.

// Magic floats which have changes
// reflected outside the function
void accelerate(float fuel, float speed){
  if (fuel == 0.0){
    return;
  } else if (fuel <= 0.5){
    // Use what fuel we have left
    speed += 100.0 * (fuel / 0.5);
    fuel = 0.0;
  } else {
    speed += 100.0;
    fuel -= 0.5;
  }
}

Since this is wrapped in a function, we can afford to be complex now!

float car1_speed = 0.0;
float car1_fuel = 0.3;

accelerate(car1_speed, car1_fuel);

Yay!

float car1_speed = 0.0;
float car1_fuel = 0.3;

// Oops.
accelerate(car1_fuel, car1_fuel);

...oh.  :(

float car1_speed = 0.0;
float car1_fuel = 1.0;
float car2_speed = 0.0;
float car2_fuel = 1.0;
// Oops.
accelerate(car1_fuel, car2_speed);

Q: What went wrong?

A: Even though the actions were correct, we were operating on the wrong data.

Enforcing Rules: Attempt 3

Instead of passing the data in separately, we're going to bundle the data together with the functions for manipulating it.

// float car1_speed = 0.0;
// float car1_fuel = 0.3;
Car car1 = new Car(0.0, 0.3);

car1.accelerate();

Object Oriented Programming

Organizing Code

Code can get complicated!

Two time-honored tricks for reducing complexity:

  • Group related data together
  • Worry only about what something does, not how it does it

One of the techniques that evolved out of these two ideas is Object Oriented Programming.

OOP: Step 1

Define a class.

class Car {
  float fuel;
  float speed;
  
  Car(float f, float s){ 
    // Code goes here
  }
  
  void accelerate(){
    // Code goes here
  }

}

Note that we don't define values for fuel and speed. This is because the class acts as a blueprint for instances of Cars.

Elements of this class (fuel, speed, accelerate()) are known as members.

Data members are known as fields.

Function members are known as methods.

OOP: Step 2

Create objects from the class and use them.

Car c1 = new Car(0.0, 0.0);
Car c2 = new Car(0.0, 0.5);
println(c1.fuel);
c1.accelerate();
println(c1.fuel);

Things to note:

  • The type of the object is the class name (e.g. the type of c1 is Car).
  • We need to use the new keyword to create an object. This is different from Python!
  • We access members of the object using dot-notation.

Class vs Object

Car class

Car object

  • Name: Car
  • Fields:
    • make
    • model
    • color
    • speed
    • fuel
  • methods:
    • accelerate(rate)
    • brake(rate)
  • Name: car_7
  • Fields:
    • make = "Honda"
    • model = "Civic"
    • color = PURPLE
    • speed = 0
    • fuel = 10.0

A Note on Language Usage

None of these are Cars!

Example Class: Spot

class Spot {
  float x, y, radius;
  
  void display() {
    ellipse(x, y, radius, radius);
  }
  
  Spot(){
    x = 50.0;
    y = 50.0;
    radius = 30.0;
  }
  
  Spot(float x, float y, float r) {
    this.x = x;
    this.y = y;
    this.radius = r;
  }
}

Things to note:

  • Constructor is defined as a function within the class, with the same name as the class.
  • We can have multiple constructors, as long as they differ in number and type of arguments.
  • If not ambiguous, can just use class variable names to refer to object variables.
  • Can use this keyword to refer to the current object. Similar to self in Python.
Spot sp1, sp2;

void setup(){
  sp1 = new Spot();
  sp2 = new Spot(75, 80, 15);
}

void draw(){
  sp1.display();
  sp2.display();
}

Using our Spot

Class Files

A single file can contain all of a program’s classes BUT
please use separate files for each class for this course when submitting projects (for hands-on, you can keep it all in one file if you'd like).

 

Multiple files provide modularity and make it easier to share/reuse code later if you choose to work in groups for the final project.

Class Files

  1. In a sketch folder, create the main program with the setup() and draw() functions.
  2. Select "New Tab."
  3. Name the file after the class it contains.
  4. Copy class files to other sketch folders for reuse.

Note: Each Processing sketch can only have one setup and draw function call

Class Functionality

  • Fields represent meaningful object values
    • What might speed represent in Spot?
    • What might direction represent in Spot?
  • Methods represent meaningful object behaviors
    • How could we use a move() method in Spot?
    • How might we use a chameleon() method in Spot? Would we need to add fields to support this?

Reminder: these are sometimes collectively referred to as class members or just members.

Hands-On: Spot Class

  1. Implement the Spot class in a Processing sketch. Create it within its own file.
  2. Add a speed field and a move() method so the spot's position can update.
  3. Implement a draw() method for Spot.
  4. Create at least two different Spot objects that start out with different positions and speeds, then draw things out. (It is okay if the spots eventually move off the screen, as long as it doesn't occur too quickly).
    HINT: Your main draw() function should be 5 lines of code.
class Spot{
  int x;
  /* Other fields */
  
  // Constructors
  Spot(){}
  Spot(int _x){}
  
  // Methods
  void move(/* args */){}

}

Objects in Objects

  • Objects can be fields of other objects.
    • Allows for better code reuse and cleaner division between concepts
  • Example: PVector provides support for vectors.
    • Stores x,y,z values as fields.
    • Provides methods with useful mathematical functionality.

https://processing.org/reference/PVector.html

class Spot {
  PVector position;
  float radius;
  void display() {
    ellipse(position.x, 
            position.y, 
            radius, radius);
  }
}

Designing Classes

What data goes in fields?

What methods should be implemented?

  • Data that creates a meaningful representation of the object in question.
     
  • Preferably should be non-redundant, otherwise we can have inconsistent data.
  • Functionality that has a clear purpose and is likely to be called multiple times
     
  • Helper methods are smaller methods that can assist in building out clean functionality

Designing Classes

Unfortunately, design has no hard and fast rules!

  • Take problem into consideration before starting the design
     
  • Use naming conventions for both fields and methods that express the purpose of that variable or function
     
  • If possible, avoid writing the same functionality out in multiple places
    • If you find yourself copy-pasting code, ask if that code can be put in a method. The answer won't always be yes, but you should think about it!

Calling new

  • Calling new allocates memory for an object. This allocation of memory can be expensive. Doing this too often may degrade performance.
    • Since the draw() loop runs 60 times per second, need to be especially cautious about using new in draw().
  • Try to create objects infrequently if you can.
    • Create objects upfront in setup() instead of every draw().
    • Create objects based on user input in mouse/key callbacks.
    • Create objects using timers (will be discussed later).
    • If you must call new from draw(), consider saving objects into global arrays so you can reuse them on the next frame. (Dangerous!)
    • Consider using advanced techniques like object pooling.

Index Cards!

  1. Your name and EID.
     
  2. One thing that you learned from class today. You are allowed to say "nothing" if you didn't learn anything.
     
  3. One question you have about something covered in class today. You may not respond "nothing".
     
  4. (Optional) Any other comments/questions/thoughts about today's class.

[06]: Object Oriented Programming

By Kevin Song

[06]: Object Oriented Programming

  • 54