Greenfoot programming is – on the whole – reasonable straight forward. At least if you know how to program in gerenral. Still, there are a lot of things that can be done well or less well. Here are some of the things I came across while writing a few scenarios that I found helpful.
Maybe you will as well.
1 Load images only once
The most common method to set an image for an actor is via the setImage(String filename) method. If an actor’s image never changes, this method is not needed at all, because any actor gets the image from the class automatically when it does not specify another image to use. But often, actors change image during execution of the scenario, and then the setImage method is needed. For instance:
class MyActor extends Actor { ... public void act() { ... if (some-condition) { setImage("imageFile1.png"); } else { setImage("imageFile2.png"); } ... } }
If your scenario is not speed critical, then it can all end here – this is all you need. But in cases where speed is critical (for example if you have several hundred actors) this can be improved.
The problem here (if performance matters) is three-fold: First, every actor here will load its own copy of the image files, even though all actors use the same two images. So, if you have 200 actors, you are dealing with 400 image objects.
Secondly, it’s actually worse than that. The image objects are not re-used: every time you switch images you will create and use a new image object, even if you have used an object for that same image before. So if you switch often, every single actor can create an indefinite number of image objects, and if you have many actors, things can quickly get as crowded as the student bar during Happy Hour.
And thirdly – worst of all – every time you switch images, you might access a file in the file system. Now, file system access, if files are stored on disk, is incredibly slow compared to memory access. Really, really incredibly slow. (Easily 1000 times slower than memory access.) So avoid file accesses where you care about speed.
The alternative is to load images only once, and then reuse the single image objects for each switch, for all actors. Here is some code:
class MyActor extends Actor { private static GreenfootImage image1 = new GreenfootImage("imageFile1.png"); private static GreenfootImage image2 = new GreenfootImage("imageFile2.png"); ... public void act() { ... if (some-condition) { setImage(image1); } else { setImage(image2); } ... } }
This change fixes all three problems. First, it uses the setImage method that takes an image object as a parameter, and not a file name. The image objects are created only once at the beginning. Thus, we access the file system only once for each image, and we also reuse the object, so that we don’t create a new object every time the image is changed. And what’s more: because the fields used are static, we actually load the image only once for the class (not once per actor object), and all actors share the same images. This will run much more efficiently than the first version.
Let me re-iterate, though, that this is really only needed if you are dealing with a speed critical situation. If you have just a handful of objects, and they do relatively simple things, then the first version is fine.
2 Use Mover for relative movement
The easiest way to create movement is by changing one of the actor co-ordinates using the setLocation method. For example,
setLocation (getX() + 2, getY());
This will move an actor a bit to the right. Movement like this, however, is independent of the rotation. Rotate the actor to face in another direction, and the movement will still move you to the right of the screen, not in the direction the actor is facing.
In many scenarios, you’d like actors to move in the direction they are facing, instead of the four compass directions. The easiest way to achieve this is by using a ready-made helper class: Mover.
The Mover class can be downloaded from the Greenfoot Support Classes page. Insert Mover into your scenario as a subclass of Actor, and then make your actor a subclass of Mover. This way, your class will inherit the methods from Mover.
The methods you get are relative turn methods (that is, a method where turn(5) turns you 5 degrees further from where you are, rather than to an absolute direction), and move methods that move you in the direction you are currently facing.
You can then write code such as
turn(40); move(3);
to turn and move on screen.
3 Use the World act method
Sometimes you want to take an action after each frame. (A frame is one act cycle, or the time span in which all actors execute one act operation.) Such actions might be calculating scores, or checking the population to see whether all objects of a certain kind have disappeared, or any of many other possible tasks.
This can be done using the World’s act method. Yes, you read this right: Worlds have act methods, too! Every time, after every actor’s act method has been called (in other words: after every frame), the world is given a chance to do something by having its act method called.
The signature of the World’s act is the same as that of the Actor class:
public void act() { ... <your code here> ... }
Using the World’s act method avoids having to introduce dummy actors for global tasks.
4 Understand key input
Greenfoot has two different methods to pick up key presses, both in the Greenfoot class: getKey() and isKeyDown(String). The difference is that isKeyDown check the state of the key, while getKey recognises individual key presses.
This is often an important difference. isKeyDown may return true repeatedly, as long as the key is being held down. Every time it is called, it checks whether the named key is down right now. So, depending on the execution speed a single short key press on a key may result in isKeyDown returning true once, seven times, or not at all (if the scenario runs very slowly and the key was released again before it was checked).
isKeyDown is most useful where you want continuous user input, such as for steering an actor in a game.
The getKey method, on the other hand, will get a single key press from the keyboard. It will pick up the key press if any key was pressed at any time between the last check and now. And it will deliver any key press only exactly once.
This method is much better when you are expecting single key press input (such as showing a menu that tells the user to “Press 1, 2 or 3” to select something).
5 Know which image file type to use
Many different image file formats exist: JPEG, GIF, PNG, BMP, TIFF, PICT, and many more. Greenfoot can read most of them, but not all are equally good to use.
The trade-off with image formats is usually between file size and quality. But there is also one other detail: Some image formats can have transparent areas (thus showing non-rectangular images) while others cannot.
To make the story short: The two image formats to use are PNG and JPEG. Anything else you can pretty much forget.
JPEG is very good at compressing image files to a small size. Small sizes are especially important if you want to export your scenario to the Greenfoot Gallery: The smaller the scenario files, the faster it is for you to upload your scenario and, more importantly, the faster the scenario starts for your users. So JPEG files are good for relatively large images if we want to save file size.
On the downside: JPEG compromises on quality. This does not make much of a difference in full colour images, but will become visible in images that have sharp lines on them (for instance, writing or line drawings). Look, for example, at the images on the right. While the PNG image looks fine, the JPEG image develops compression artefacts (“dirty” or “blurry” looking areas around the text). The other disadvantage is that JPEG does not do transparency, so if you want non-rectangular actors, this is a problem.
Luckily, PNG does both of this well. It has good quality for images, line drawings and text, and it can do transparent backgrounds. However, it does not compress as well as JPEG, especially on images with many colours.
Taken together, this means: Use JPEG files for scenario backgrounds – they are just about perfect for this, since we have fairly large images and don’t need transparency. Use PNGs for actors. That’s what I almost always use. The only exception is if I have hard lines or writing on the background – then I might use a PNG for the world background as well.
That’s it for now – if you have Greenfoot tips of your own, please feel free to leave them in the comments.
I have ! 🙂
You should use for loop if you have an increment.
because the increment was on the function
for(int a = 0; a >= 12; a++){} // the a++;
And use while() for function returns
while(i.hasNext()){}
while(f.eof() < 0){} // -1, i forget eof, read or something else
I just little afraid of Infinite loop 😀