Sprites¶
In these notes you will learn:
- How to write a simple class.
- How to use objects with ”.”-notation.
- How assignment works with object variables.
- What
null
is.
Introduction¶
Every 2-dimensional animated object needs, at least, these four variables:
float x; // (x, y) is the position
float y; // of the object
float dx; // speed along the x-axis
float dy; // speed along the y-axis
So, for example, if you want to animated 3 different objects, you will need at least 12 variables:
float x1; // object 1
float y1;
float dx1;
float dy1;
float x2; // object 2
float y2;
float dx2;
float dy2;
float x3; // object 3
float y3;
float dx3;
float dy3;
Dealing with so many similarly-named variables is quite difficult in practice.
It’s easy to accidentally write y2
instead of y1
.
Sprites¶
One way to deal with this complexity is to group x
, y
, dx
, and
dy
together into one object. To do this in Processing, we first need to
create a class:
class Sprite {
float x;
float y;
float dx;
float dy;
}
Using the Sprite
class, we can now create Sprite
objects like this:
Sprite ball = new Sprite();
Sprite plate = new Sprite();
When new Sprite()
is called, it creates a new object that contains its own
x
, y
, dx
, and dy
values. We can use it like this:
ball.x = 10; // initialize ball
ball.y = 10;
ball.dx = 1;
ball.dy = 1.5;
plate.x = 450; // initialize plate
plate.y = 450;
plate.dx = -1.5;
plate.dy = -1;
The .
is used to access the variables in an object. Clearly, ball.x
refers to the x
in the ball
object, while plate.x
refers to the
x
in plate
.
Two advantages of using the Sprite
class are:
- The variable names tend to be more descriptive.
- You don’t have to define as many variables.
While this doesn’t solve all the problems of so many variables, it is an important first step. Later, we will see how other features can be used to even further simplify the creation of animated objects.
Note
Sprite is the traditional name for a 2-dimensional animated object. It originated in early video games, where support for animated objects was often designed into the hardware itself.
Sample Program¶
Here’s a complete sample program using a Sprite
to represent a ball:
class Sprite {
float x;
float y;
float dx;
float dy;
}
color white = color(255);
color orange = color(255, 165, 0);
Sprite ball = new Sprite();
float diam;
void setup() {
size(500, 500);
smooth();
ball.x = 100;
ball.y = 100;
ball.dx = 1;
ball.dy = 2;
diam = 50;
}
void draw() {
background(white);
noStroke();
fill(orange);
ellipse(ball.x, ball.y, diam, diam);
ball.x += ball.dx;
ball.y += ball.dy;
// hit the left edge?
if (ball.x - diam / 2 <= 0) {
ball.dx = -ball.dx;
ball.x = diam / 2;
}
// hit the right edge?
if (ball.x + diam / 2 >= 499) {
ball.dx = -ball.dx;
ball.x = 499 - diam / 2;
}
// hit the top edge?
if (ball.y - diam / 2 <= 0) {
ball.dy = -ball.dy;
diam += 10;
ball.y = diam / 2;
}
// hit the bottom edge?
if (ball.y + diam / 2 >= 499) {
ball.dy = -ball.dy;
ball.y = 499 - diam / 2;
}
}
Assigning Object Variables¶
Consider this code fragment:
Sprite ball1 = new Sprite();
Sprite ball2 = new Sprite();
ball1.x = 100;
ball2.x = 200;
println(ball1.x); // prints 100
println(ball2.x); // prints 200
We say ball1
and ball2
refer, or point, to their corresponding
Sprite
objects. ball1.x
and ball2.x
thus refer to different
variables.
Now suppose we write this:
Sprite ball1 = new Sprite();
Sprite ball2 = new Sprite();
ball1 = ball2;
ball1.x = 100;
ball2.x = 200;
println(ball1.x); // prints 200
println(ball2.x); // prints 200
The result is different because the assignment statement ball1 = ball2;
makes ball1
refer to the same object as ball2
. Thus ball1.x
and
ball2.x
refer to the same variable.
What’s important to notice here is that ball1 = ball2;
does not make a
copy of the underlying object. Instead, it makes the variable ball1
point
to the same variable ball2
points to.
Garbage Collection¶
There is a subtle but important issue hidden in the previous example:
Sprite ball1 = new Sprite();
Sprite ball2 = new Sprite();
ball1 = ball2;
ball1.x = 100;
ball2.x = 200;
After the assignment statement ball1 = ball2;
is executed, what happens to
the object that ball1
use to refer to? ball1
no longer refers to it,
and so there is now no way to access the variables that are in it. An object
that has no references or pointers to it is called a garbage object.
Garbage objects cannot be used by your program, but still take up memory. If
you have too many garbage objects, your program’s performance could degrade,
or your program may even crash.
In some languages, such as C or C++, garbage objects must be manually deleted by the programmer. Deleting a garbage object means telling the program that the memory it uses can, if needed, be given out to other new objects. Experience has shown that manually deleting garbage objects is surprisingly difficult and error-prone, even for the best programmers. Great care must be taken to ensure that an object truly is garbage, i.e. that nothing points to it.
Java does not have manual garbage deletion, and instead handles garbage objects in two main ways:
Sometimes it does nothing! In small programs that don’t create a lot of objects, there may be no need to delete garbage objects. Just let the garbage objects accumulate, and ignore them. As long as you enough memory, this may not be a big a problem.
The good thing about this approach is that it is fast, simple, and easy to understand. But the bad thing is that it ignores the problem of garbage instead of solving it. In longer running programs, small garbage objects can add up to waste a lot of memory, requiring they they be deleted somehow.
Run an automatic garbage collector sub-program. When you create a Java program, Java automatically gives it a special garbage collector sub- program that will, when it decides it is necessary, automatically delete garbage objects in your main program. The garbage collector sub-program does take a bit of time when it runs, and so because of this Java programs are not necessarily as efficient as equivalent programs in languages with manual garbage deletion.
The nice thing about automatic garbage collection is that the programmer doesn’t need to even know about it: it is totally automatic. The actual details of how garbage collectors are quite subtle and involved, but using it is easy.
null and NullPointerException¶
If you create a Sprite
variable without making it point to a Sprite
object, then it is assigned the special value null
:
Sprite ball; // ball is automatically set to null
println(ball); // prints "null"
null
means that the variable is not referring to any object. You can never
use ”.”-notation with null
, e.g.:
Sprite ball = null;
ball.x = 5; // run-time error: NullPointerException
ball.x
causes the run-time error NullPointerException
. In practice,
this is a very common error, and often means you forgot to use new
to make
a new object for your variable.
Example: A Small Explosion¶
Lets see an example of how to use multiple sprites in the same program. The following code makes three “fragments” move off from the center of the screen in different directions and at different speeds:
class Sprite {
float x;
float y;
float dx;
float dy;
}
Sprite frag1 = new Sprite();
Sprite frag2 = new Sprite();
Sprite frag3 = new Sprite();
void setup() {
size(500, 500);
smooth();
noStroke();
frag1.x = 250;
frag1.y = 250;
frag1.dx = -4.2;
frag1.dy = 3.6;
frag2.x = 250;
frag2.y = 250;
frag2.dx = -2.2;
frag2.dy = -4.6;
frag3.x = 250;
frag3.y = 250;
frag3.dx = 4.2;
frag3.dy = 2.6;
}
void draw() {
background(255);
fill(255, 0, 0);
ellipse(frag1.x, frag1.y, 50, 50);
fill(0, 255, 0);
ellipse(frag2.x, frag2.y, 50, 50);
fill(0, 0, 255);
ellipse(frag3.x, frag3.y, 50, 50);
frag1.x += frag1.dx;
frag1.y += frag1.dy;
frag2.x += frag2.dx;
frag2.y += frag2.dy;
frag3.x += frag3.dx;
frag3.y += frag3.dy;
}
Questions¶
What are two advantages of using the
Sprite
class for representing animated objects?What does the following code fragment print?
Sprite ball = new Sprite(); println(ball.x); println(ball.y); println(ball.dx); println(ball.dy);
The
Sprite
class in these notes is for representing 2-dimensional sprites. Write a class calledSprite3d
that could be used to represent 3-dimensional sprites.
Programming Questions¶
- Modify the sample program in “a small explosion” so that gravity pulls the particles downwards.