
SCROLLING
Scrolling is the adjusting of the positions of most, if not all, actors in the world, often with a shifting of the background image. This is done to give the appearance of a shift in position of the viewer, thus enabling a fluid transition from one area of a larger-than-viewport world to another. Scrolling can be continuous (a constant flow in the same direction), it can be based on the position of an actor or group of actors in the world or it can be user-controlled via the mouse or keyboard. There are so many different situations for scrolling that it is difficult to cover everything easily. Beginners should not attempt to create a scrolling scenario as there is quite a bit involved where coding is concerned.
​
Before beginning, I feel it is best to cover the non-scrolling actors first. A non-scrolling actor could be a button or bar object, a score, level, lives or timer display, a mini-map, or any other actor that you would want to maintain at a specific location in your scenario viewport. To prevent them from being relocated when scrolling all actors, you can add the following line into their classes:
​
public void setLocation(int x, int y){}
This method overrides the one given by the Actor class and removes its implementation. The method could also be placed in a separate class that extends Actor that you can subclass with those classes that create those actors you do not want to have move. Now, scrolling is a behavior of a World object and each scrolling world should control its own scrolling. There are several places where you can place the scrolling code where a world can control it. The first is in the class of the scrolling world itself; the second is in a superclass of that world; finally, the scrolling code can be placed in a separate class where the scrolling world will create and keep a reference to an instance of that class to be used to control its scrolling. This tutorial will use a separate class for the scrolling to keep the World subclass codes given clean and consistent. Also, I can then show a complete reusable class for controlling the scrolling. When scrolling, it is best to use an unbounded world -- one where actors can be maintained beyond the viewable area of the world. This requires the use of the World constructor that has four parameters, the last being a boolean value that determines the bounded state of the new world. Also, if scrolling is to follow an actor (one that is to stay in view at all times), then a field to maintain a reference to that actor should be in the class of your scrolling world. The following is a skeleton world class for a scrolling world using a Scroller object to perform the scrolling:
​
import greenfoot.*;
public class MyWorld extends World
{
public static final int WIDE = 800; // world width (viewport)
public static final int HIGH = 600; // world height (viewport)
public static final int CELL = 1; // cell size for world
private Scroller scroller; // *** the Scroller object reference field ***
public MyWorld()
{
super(WIDE, HIGH, CELL, false); // create an unbounded world of size (WIDE, HIGH)
scroller = new Scroller(< parameter arguments >); // *** create Scroller object ***
// any other initialization codes
}
public void act()
{
// any other action codes
scroll(); // *** perform scrolling ***
}
// *** scroll method *** determines offsets and calls the Scroller object to scroll the world
private void scroll()
{
// code depends on type of scroller; the following line will be used somewhere
scroller.scroll(< parameter arguments >); // *** updates scroll position ***
}
}
Asterisks were used to point out the method and the important lines that were added for scrolling. The arguments were left out of the Scroller constructor call and to the 'scroll' method call of the Scroller class because their values would be specific to the type of scroller and to the project. The code for the 'scroll' method is also dependent on the conditions for scrolling. Since there are multiple types of scrolling and multiple conditions that can be used for scrolling, a decision was made to make one basic scroller class and provide various World subclass codes to control it in various ways. The scroller class comes with two constructors allowing it be used for both limited or unlimited. The scroller class constructor without the two int parameters is for unlimited scrolling. The two int parameters in the other one determine the size of the scrolling area. The universal scroller can be used for limited side or vertical scrolling as well by limiting one of the scroll area dimensions to the dimension of the world viewport along that axis. When creating a scrolling object, one has the option to provide an image that is to be used for the background of the world and which will be tiled, if needed, to fill the scrolling area. For infinite scrollers, the image will be wrapped as needed. Please bear in mind that image manipulation is a hog on CPU time -- the larger the image, the more of a hog, exponentially! There are several things one can do to reduce the risk of lag during runtime. Obviously, not having a scrolling image would help; but, if you do have one, try to keep it to a nominal size. The same goes with the size of the world itself when using a scrolling background image. Also, because the world is unbounded, take care that objects that leave the viewport are removed from the world if they are not needed anymore -- they could build up in number and bring your project to a virtual halt. The links that follow start with the Scroller class itself, followed by various World subclass codes that can be used to control the scrolling (including actor following, constant scroll, key controlled, mouse drag controlled and shaking, which is a "camera" movement action).
​
​
​
Continuous (constant) scrolling code\
​
Mouse drag controlled scrolling code
Actor follow scrolling code (center-screen actor and ranged movement actor)
​
Selectable actor follow scrolling code (key controlled w/o selected actor)
​