Animating the key
5.1 Animating the key
When you examine the existing code, you see that not much is there at present: The Piano class only specifies the size and resolution of the world, and the Key class contains only method stubs (empty methods) for the constructor and the act method (shown in Code 5.1).
Code 5.1 The initial Key class
import greenfoot.*; // (World, Actor, GreenfootImage, and Greenfoot) public class Key extends Actor
/** * Create a new key. */
public Key() {
* Do the action for this key. */
public void act() { }
We can start experimenting by creating an object of class Key and placing it into the world. You see that its image is that of a simple white key, and it does nothing at all when we run the scenario.
Our first task will be to animate the piano key: When we press a key on the keyboard, we would like the piano key on screen to change so that it appears to be pressed down. The scenario as it is already contains two image files named white-key.png and white-key-down.png, which we can use to show these two states. (It also contains two more image files, black-key.png and black- key-down.png, which we shall use later for the black keys.) The white-key.png image is the one that we currently see when we create a key.
We can create the effect of the key being pressed quite easily by switching between the two images when a specif ic key on the keyboard is pressed. Code 5.2 shows a f irst attempt at this.
5.1 Animating the key
Code 5.2 First version of
public void act() the act method:
{ changing images
if ( Greenfoot.isKeyDown( “g” )){
setImage ( “white-key-down.png” ); } else {
setImage ( “white-key.png” ); }
In this code, we have chosen an arbitrary key on the computer keyboard (the “g” key) to react to. Which key we use at this stage does not really matter—eventually we want to attach different piano keys to several of our keyboard keys. When the key is pressed on the keyboard, we show the “down” image; when it is not being pressed, we show the “up” image.
Exercise 5.3 Implement this version of the act method in your own scenario. Test it— make sure it works.
While this version works, it has a problem: The image is set not only once when it changes, but con- tinuously. Every time the act method executes, the image is set to either one of the two images, even though it might already show the correct image. For example, if the “g” key is not being pressed, the image will be set to white-key.png, even if this was already the displayed image.
This problem does not seem too serious at first. After all, setting the image when it is not needed is merely unnecessary, but not incorrect. There are several reasons why we want to fix this, though. One reason is that it is good practice to not waste processor resources by doing unnecessary work. Another reason is that we will add sound for the key soon, and then it does matter. When we press a key, it makes a big difference whether the key’s sound is heard once, or over and over again.
So, let us improve our code by ensuring that the image is only set when it actually changes. To do this, we add a boolean field to our class to remember whether the key is currently down or not. We call this field isDown , and its declaration looks as follows:
private boolean isDown;
We will store true in this field while the piano key is down, and false while it isn’t. We can then check whether our keyboard key has just now been pressed: If our isDown field is
false , but the “g” key on the keyboard is being pressed, it must have been pressed just a moment ago. Conversely, if our isDown field is true (we think the key is down), but the “g” key on the keyboard is not down, then it must have been released just now. In these two situations, we can then change the image. Code 5.3 shows the complete act method implementing this idea.
64 | Chapter 5 ■ Making music: An on-screen piano
Code 5.3 Only set the image
public void act() when it needs to
{ change
if ( !isDown && Greenfoot.isKeyDown( “g” )){
setImage ( “white-key-down.png” ); isDown = true ;
} if ( isDown && !Greenfoot.isKeyDown( “g” )){
setImage ( “white-key.png” ); isDown = false ;
In both cases, we make sure to set the isDown field to the new state if we detect a change. This code makes use of two new symbols: the exclamation mark (!) and the double amper-
Concept:
sand (&&) .
Logic operators,
Both are logical operators. The exclamation mark means NOT, while the double ampersand
such as && (AND)
means AND.
and ! (NOT), can be used to
Thus, the following lines from the act method
combine multiple boolean expres-
if ( !isDown && Greenfoot.isKeyDown( “g” )){ sions into
setImage ( “white-key-down.png” );
one boolean expression.
isDown = true ;
can be read a little more informally (attention: not Java code!) as
if ( (not isDown) and Greenfoot.isKeyDown( “g” ) ) ...
The same code, even more informally, can be read as
if ( the-piano-key-is-not-currently-down and the-keyboard-key-is-down) {
change the image to show the “down” image; remember that the piano key is down now;
Have a look at Code 5.3 again, and make sure you understand the code shown there.
A full list of all available logic operators is given in Appendix D.
Exercise 5.4 Implement the new version of the act method in your own scenario. It will not appear to do anything different than before, but it is a necessary preparation for what we shall do next. Don’t forget that you also have to add the boolean isDown field at the beginning of your class.
5.2 Producing the sound