On this page:
1.1 Images
1.1.1 Basic image properties
1.1.2 Basic Images
1.1.3 Polygons
1.1.4 Overlaying Images
1.1.5 Rotating, Scaling, Shearing, Cropping, and Framing images
1.1.6 Bitmaps
1.1.7 Pinholes
1.2 World  Scenes
1.3 Worlds
1.3.1 make  Scene
1.3.2 big  Bang
1.3.3 get  Empty  Scene
1.3.4 Handlers
1.3.4.1 Key handlers
1.3.5 Ending the World
1.3.5.1 end  Of  World and last  Scene
1.3.5.2 world  Ends
1.3.6 Funworld versus Impworld
6.8

The Image Library

Related files:
  javalib.jar  

1.1 Images

The javalib library provides a number of basic image classes, along with combinators for building more complex images out of existing images. Basic images include various polygons, ellipses and circles, and text, as well as bitmaps. Existing images can be rotated, scaled, flipped, and overlaid on top of each other.

(In fact, the background is drawn 1 pixel larger in each direction, so that any outlines or edges are more clearly seen.)

Note that all images in this tutorial are drawn on a light-gray background, so that it’s apparent what the extent of the image actually is. This means that images drawn as outlines, for example, will appear to be filled with light-gray. To produce exactly the images seen here, you’ll need to overlay them onto a gray rectangle yourself.

1.1.1 Basic image properties

Every image has a width and height, that can be obtained via the getWidth() and getHeight() methods.

Every image also has a bounding box, obtained by getBB(), representing the top-left and bottom-right corners of the image, in that image’s own coordinate system, which is a Cartesian system whose origin is at the image’s center, and whose y-axis points down.

Finally, every image has a pinhole, described further below.

1.1.2 Basic Images

Constructs a circle with the given radius, mode, and color.

new CircleImage(30, OutlineMode.OUTLINE, Color.RED)
image
new CircleImage(20, OutlineMode.SOLID, Color.BLUE)
image

Constructs an ellipse with the given width, height, outline mode, and color.

new EllipseImage(60, 30, OutlineMode.OUTLINE, Color.BLACK)
image
new EllipseImage(30, 60, OutlineMode.SOLID, Color.BLUE)
image

Constructs a Line from the origin to the end point. The line will be the given color, and it will be recentered so that it’s internal "origin" is the center of the line.

new LineImage(new Posn(30, 30), Color.RED)
image

Constructs an image that draws the given string, using the font size and color.

new TextImage("Hello", 24, FontStyle.BOLD, Color.RED)
image
new TextImage("Hello", 18, Color.BLACK)
image
new TextImage("Hello", Color.BLUE)
image

Constructs an empty image (transparent image with no width or height). Useful as a base image to overlay onto.

1.1.3 Polygons

Constructs a triangle based on the three given points. The points are given relative to each other, and then the entire image is recentered so that its origin is the center of the triangle. The triangle will either be filled or an outline, and drawn with the specified color.

new TriangleImage(new Posn(0, 0), new Posn(0, 48), new Posn(36, 48),
OutlineMode.SOLID, Color.BLACK)
image

Constructs an equilateral triangle with the given side length. The triangle will either be filled or an outline, drawn with the specified color.

new EquilateralTriangleImage(40, OutlineMode.SOLID, Color.GREEN)
image

Constructs a rectangle with the given width, height, fill, and color.

new RectangleImage(40, 20, OutlineMode.OUTLINE, Color.BLACK)
image
new RectangleImage(40, 20, OutlineMode.SOLID, Color.BLUE)
image

Constructs an equilateral hexagon with the given side length. The hexagon will either be filled or an outline, drawn with the specified color.

new HexagonImage(40, OutlineMode.SOLID, Color.GREEN)
image

Constructs a regular equilateral polygon with the given side length. The polygon will either be filled or an outline, drawn with the specified color.

new RegularPolyImage(40, 5, OutlineMode.SOLID, Color.RED)
image
new RegularPolyImage(30, 8, OutlineMode.OUTLINE, Color.BLUE)
image

1.1.4 Overlaying Images

Constructs a combined image with top image overlaid over the bottom image. The top image will be placed such that its pinhole aligns with the bottom image’s pinhole. For more information about pinholes, see Pinholes.

new OverlayImage(new RectangleImage(30, 60, OutlineMode.SOLID, Color.GREEN),
new EllipseImage(60, 30, OutlineMode.SOLID, Color.PURPLE))
image

Constructs a combined image with top image overlaid over the bottom image. The top image will be placed such that its pinhole aligns with the bottom image’s pinhole. For more information about pinholes, see Pinholes. The bottom image will then be offset by dx and dy.

new OverlayOffsetImage(new CircleImage(40, OutlineMode.SOLID, Color.RED),
10, 10,
new CircleImage(40, OutlineMode.SOLID, Color.BLUE))
image

Constructs a combined image with top image overlaid over the bottom image. AlignX and alignY are used as starting points for the overlay, then the bottom image will be offset by dx and dy.

new OverlayOffsetAlign(AlignModeX.RIGHT, AlignModeY.BOTTOM,
new RectangleImage(40, 20, OutlineMode.SOLID, Color.RED),
10, 10,
new CircleImage(40, OutlineMode.SOLID, Color.BLUE))
image

Constructs an image by placing all of the image arguments in a horizontal row, aligned along their pinholes.

new BesideImage(new EllipseImage(20, 70, OutlineMode.SOLID, Color.GRAY),
new EllipseImage(20, 50, OutlineMode.SOLID, Color.DARK_GRAY),
new EllipseImage(20, 30, OutlineMode.SOLID, Color.BLACK))
image

Constructs an image by placing all of the image arguments in a horizontal row, lined up as indicated by the align mode of the Y axis.

new BesideAlignImage(AlignModeY.BOTTOM,
new EllipseImage(20, 70, OutlineMode.SOLID, Color.GRAY),
new EllipseImage(20, 50, OutlineMode.SOLID, Color.DARK_GRAY),
new EllipseImage(20, 30, OutlineMode.SOLID, Color.BLACK))
image

Constructs an image by placing all of the image arguments in a vertical column, aligned along their pinholes.

new AboveImage(new EllipseImage(70, 20, OutlineMode.SOLID, Color.GRAY),
new EllipseImage(50, 20, OutlineMode.SOLID, Color.DARK_GRAY),
new EllipseImage(30, 20, OutlineMode.SOLID, Color.BLACK))
image
  • new AboveAlignImage(AlignModeX mode, WorldImage im1, WorldImage... ims)
    Arguments:
    • AlignModeX mode:   Alignment along the X axis. Left, right, center, pinhole

    • WorldImage im1:   the top image for the combined image

    • WorldImage... ims:   the bottom image(s) for the combined image

  • new AboveAlignImage(String mode, WorldImage im1, WorldImage... ims)
    Arguments:
    • String mode:   Alignment along the X axis. Left, right, center, pinhole

    • WorldImage im1:   the top image for the combined image

    • WorldImage... ims:   the bottom image(s) for the combined image

Constructs an image by placing all of the image arguments in a vertical column, aligned along the X axis as indicated by the specified mode.

new AboveAlignImage(AlignModeX.RIGHT,
new EllipseImage(70, 20, OutlineMode.SOLID, Color.GRAY),
new EllipseImage(50, 20, OutlineMode.SOLID, Color.DARK_GRAY),
new EllipseImage(30, 20, OutlineMode.SOLID, Color.BLACK))
image

A "phantom" image that has a default width and height of 0. In all respects other than width and height it delegates to the underlying image. The width and height can be specified with the full constructor.

1.1.5 Rotating, Scaling, Shearing, Cropping, and Framing images

Rotate the image by rotationDegrees in a clockwise direction.

new RotateImage(new EllipseImage(60, 20, OutlineMode.SOLID, Color.CYAN), 45)
image

Scale the image by the given factor.

new ScaleImage(new EllipseImage(20, 40, OutlineMode.OUTLINE, Color.BLACK), 1.5)
image

Scale the image by the given factors in both the X and Y direction.

new ScaleImage(new EllipseImage(20, 40, OutlineMode.OUTLINE, Color.BLACK), 1.5, 0.5)
image

Shear the image by the given factors in both the X and Y direction.

new ShearedImage(new RectangleImage(60, 30, OutlineMode.SOLID, Color.BLUE), 0.5, 0.5)
image

Crops img to the rectangle with the upper left at the point (x,y) and with width and height.

new CropImage(0, 0, 40, 40, new Circle(40, OutlineMode.SOLID, Color.BROWN))
image

Returns an image just like image, except with a single pixel frame drawn around the bounding box of the image. By default the frame is drawn in black, but you may specify an alternate color.

new FrameImage(new CircleImage(40, OutlineMode.SOLID, Color.GRAY))
image
new FrameImage(new CircleImage(40, OutlineMode.SOLID, Color.GRAY), Color.RED)
image

1.1.6 Bitmaps

Constructs an image from a source jpg or png. It reads the file from the root directory of the project.

Freezing an image internally builds a bitmap, draws the image into the bitmap and then uses the bitmap to draw that image afterwards. Typically this is used as a performance hint. When an image both contains many sub-images and is going to be drawn many times, using freeze on the image can substantially improve performance without changing how the image draws.

1.1.7 Pinholes

Pinholes are used as guidelines for overlaying images. By default, the pinhole is located at the image’s center. OverlayImage will align each image’s pinhole, and OverlayAlignImage can be specified to align along pinholes. The pinhole can be moved through movePinholeTo and movePinhole. Both functions will create a new image with the pinhole moved as indicated by the function’s description.

Note: You can use movePinholeTo(new Posn(0, 0)) to reset the pinhole at the center of the current image.

This constructs an image that overlays a cross over the pinhole of the img. The resulting image has its pinhole in the same place, and is the same size as the underlying image, so that one can easily add or remove visible pinholes while debugging how images are drawn. By default, the pinhole is drawn in black, but you may specify an alternate color.

new CircleImage(30, OutlineMode.OUTLINE, Color.RED)
image
new VisiblePinholeImage(new CircleImage(30, OutlineMode.OUTLINE, Color.RED))
image
new VisiblePinholeImage(new CircleImage(30, OutlineMode.OUTLINE, Color.RED).movePinhole(10, 10))
image
new VisiblePinholeImage(new CircleImage(30, OutlineMode.OUTLINE, Color.RED).movePinhole(10, 10), Color.BLUE)
image

1.2 WorldScenes

  • new WorldScene(int width, int height)
    Arguments:
    • int width:   The width of the scene

    • int height:   The height of the scene

A WorldScene is a canvas on which to draw WorldImages. It is used by Worlds to be drawn on each tick. WorldScene supports only a single method:

WorldScene placeImageXY(WorldImage img, int x, int y)

that places the given image with its pinhole on the specified coordinates. It returns the enhanced scene. Parts of the image that extend beyond the scene boundaries will be cropped.

Use this method in sequence to place multiple images on a scene:

new WorldScene(width, height)
.placeImageXY(image1, x1, y2)
.placeImageXY(image2, x2, y2)
...
.placeImageXY(imageN, xN, yN);

Or, build up a composite image (using any of the image constructions above) and place everything on the scene at once.

1.3 Worlds

  • new World()
    Arguments:

    World is an abstract class that must be extended to implement any particular game. The only method that must be overridden is makeScene; other methods may be overridden if needed.

    1.3.1 makeScene

    WorldScene makeScene()

    This method must return the WorldScene to be shown on each clock tick.

    1.3.2 bigBang
    boolean bigBang(int width, int height, double speed)

    Invoke bigBang on a World, passing in the intended width and height of the window to be opened. (This may be distinct from the size of the WorldScene being displayed; if so, the scene will be drawn in the upper-left corner of the window.)

    Additionally, pass in a double representing the speed (in seconds) of the tick-rate. Only positive numbers will work; zero or negative numbers will be ignored and the clock will not tick.

    As a convenience, merely to test that your code compiles and can display anything, bigBang is overridden to take just a width and height, and assumes a clock speed of zero.

    1.3.3 getEmptyScene

    WorldScene getEmptyScene()

    This convenience method will return an empty scene sized to fit the current window. This may be easier to use than keeping the sizes of the window and the scene in synch in multiple places in your code.

    1.3.4 Handlers

    There are several handlers you can override to provide behavior for your game:
    • onTick() handles ticking the clock and updating the world.

    • onKeyEvent(String key) handles key input and is given the key that has been pressed.

    • onKeyReleased(String key) handles key released and is given the key that has been released.

    • onMouseClicked(Posn pos) handles mouse clicks and is given the mouse location.

    • onMouseEntered, onMouseExited, onMousePressed and onMouseReleased are analogous to onMouseClicked, but cover additional mouse behaviors.

    You will almost always override onTick, and will likely override onKeyEvent and/or onMouseClicked.

    1.3.4.1 Key handlers

    Both the onKeyEvent and onKeyReleased events receive a key name describing the key that has been pressed or released. Key events may happen repeatedly, if the key is pressed and held down and that key isn’t just a modifier key (like Shift or Control).

    Most keys are described as themselves: e.g., pressing the A key will result in the key "a" being sent; likewise pressing the Z key will result in the key "z" being sent. All key names are always lowercase; if you wish to distinguish upper and lowercase letters, you will need to keep track of whether the shift or capslock keys have been pressed. Typing @ by pressing the shift key, then 2, then releasing the shift key, then releasing 2, will generate several key events:
    • A key press of "shift" or "right-shift"

    • A key press of "@"

    • A key release of "shift" or "right-shift"

    • A key release of "2"

    If keys appear in both left and right forms (e.g. the shift keys), then they will be named "shift" and "right-shift", "control" and "right-control" etc. If keys appear both on the normal keyboard and the number pad, they will be named "0" and "numpad-0", etc.

    The following keys are given special descriptive names:
    • "enter"

    • "delete"

    • "tab"

    • "shift"

    • "insert"

    • "home"

    • "page-up"

    • "page-down"

    • "delete"

    • "begin"

    • "end"

    • "num-lock"

    • "scroll-lock"

    • "escape"

    • "caps-lock"

    • "context-menu"

    • "f1"

    • "f2"

    • "f3"

    • "f4"

    • "f5"

    • "f6"

    • "f7"

    • "f8"

    • "f9"

    • "f10"

    • "f11"

    • "f12"

    • "up"

    • "down"

    • "left"

    • "right"

    1.3.5 Ending the World

    When the game is over, you have two mechanisms for signaling the end of the world.

    1.3.5.1 endOfWorld and lastScene

    The easier alternative is to return this.endOfWorld("A message") from any of your handlers (tick, keyboard, mouse, etc.). If this method is used, you should override

    WorldScene lastScene(String msg)

    to return the appropriate final scene to display to the user of your game. The msg parameter is whatever String is passed to endOfWorld. This approach is easier to use when deciding that the world has ended is cleanly split into each relevant handler.

    1.3.5.2 worldEnds

    For more isolated control, you can override

    WorldEnd worldEnds()

    This method returns a WorldEnd object, whose constructor takes two parameters: a boolean indicating whether the world has ended or not, and a WorldScene to be displayed (when the boolean flag is true). Typical overrides of this method will look roughly like

    public WorldEnd worldEnds() {
    if (theGameIsOver) {
    return new WorldEnd(true, this.makeAFinalScene());
    } else {
    return new WorldEnd(false, this.makeScene());
    }
    }

    (Note that the scene currently is ignored when the boolean flag is false.)

    This approach is easier to use when deciding that the world has ended is better expressed in a single, consolidated place. However, the code must produce a WorldEnd object even when the world hasn’t ended.

    1.3.6 Funworld versus Impworld

    There are two variants of the World library supplied to you:

    Be sure to use the version of the library requested by each assignment!