Skip to content

Game Library written in Java using AWT/Swing for rendering

License

Notifications You must be signed in to change notification settings

mschroeder-github/jasgl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JASGL - Java AWT/Swing Game Library

Logo

Game Library purely written in Java by using AWT/Swing canvas rendering. No external native libraries are used. In contrast to similar projects, this library tries to keep it simple and stupid (KISS principle).

Start your game loop with a one liner (title, window size, background color). This hides the following complexity: game loop thread, double-buffered 30 FPS active rendering on canvas, swing keyboard and mouse input processing and Swing frame setup.

GameLoopFrame.loop("Game Demo", 800, 450, Color.black, new MyGame());

Concentrate on your game containing the three major aspects: input handling, game state update and rendering which is called each frame of 30 frames in a second.

//hello world game
public class MyGame implements Game {

    private GameLoop gameLoop;

    /**
     * Store your game state using class attributes here.
     */

    /**
     * To access the game loop and change some aspects.
     * E.g.: use gameLoop.close() to close the game.
     */
    @Override
    public void init(GameLoop gameLoop) {
        this.gameLoop = gameLoop;
    }

    /**
     * Decide for a frame how input changes your game state.
     */
    @Override
    public void input(Keyboard keyboard, Mouse mouse) {
        //close when escape is pressed
        if (keyboard.pressed(KeyEvent.VK_ESCAPE)) {
            gameLoop.close();
            return;
        }
    }

    /**
     * Update the game state when given milliseconds are elapsed.
     */
    @Override
    public void update(double ms) {

    }

    /**
     * Render the frame of the current game state.
     */
    @Override
    public void render(Graphics2D g) {

    }

}

Using JASGL

Below some sections about game making and usage of this library. If you have special requirements and can not reuse implemented classes, it should always be possible to extend a library class.

Load Images

Images

Usually games need images. Put your images in maven's /src/main/resources folder and load the images in your Game class. This ensures that your images are shipped with the built jar.

import javax.imageio.ImageIO;
import java.awt.Image;

private static final Image sprite1;
static {
    try {
        sprite1 = ImageIO.read(MyGame.class.getResourceAsStream("/path/to/sprite1.png"));
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
}

If you need to access the image by attribute name, you could use reflection.

public static Image getImageByName(String name) {
    try {
        Field f = MyGame.class.getDeclaredField(name);
        return (Image) f.get(null);
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

Sprite Sheet

Spritesheet

Skeleton-pack by jesse-m.itch.io

Sprite sheets are used to put many images of a sprite into one image. But then we have to state where the subimages are and what they animate. A SpriteSheet gives a sequence of subimages a name (e.g. "killed" are the images where the skeleton collapses).

  • SpriteSheet a sheet of image sprites.
    • RpgMakerCharSpriteSheet in rpg maker 8 character are in one sprite. This class automatically and correctly cuts the subimages.

Sprite

Sprite

  • Sprite is a moveable object in the game. Thus, it basically has a position. It is updatable and renderable.
    • SpriteSheetSprite is a sprite that uses a SpriteSheet and an Animator to present its appearance using animated sequence of images.
      • RpgMakerCharSprite is a rpg marker character sprite. You have to state the character index because in one sprite 8 character are present. The animator is given with a configured SequentialFixedIntervalFrameAnimator.
    • TileSprite instead of a complex SpriteSheet you can take one Tile from a TiledLevelMap as a sprite.
      • MultiTileSprite the sprites holds multiple tiles and you can switch between them.

Note: ListOfSprites is a useful (array-)list of sprites with additional list based operations on sprites.

Interfaces

Sprites can implement interfaces when they have certain behavior.

  • Pivotable: sprites have a direction (left,up,right,down) which can be changed. This can be used by a Positioner.
  • Areaable: By default, sprites have a position point. Use this interface to specify an area they occupy in space.

Animator

Animation

An animator changes image frames to create an animation.

  • Animator
    • FrameAnimator is an animator that changes frames (int).
      • SequentialFixedIntervalFrameAnimator is an frame animator that changes frames in a fixed time interval and in a given sequence (e.g. 1,5,2,4).

Scene

Scene

In a scene you define what happens in your level. This is a usual way to tell a story in scenes.

  • Scene is just a list of SceneActs.
  • SceneAct is just a reference to a java method together with parameters.
  • SceneBuilder is used to build a Scene that is later played by the ScenePlayer.
  • ScenePlayer plays a Scene.

Inherit from SceneBuilder to define custom scene acts. Inherit from ScenePlayer to implement what will happen in your game when the act is played.

Positioner

Positioner

A positioner moves Sprites in the game, maybe based on input.

  • Positioner changes positions of given sprites. Can also start and stop animation based on positioning (e.g. walking).
    • InputBasedPositioner The positioner moves sprites based on input (e.g. key pressed or mouse clicked).
      • RpgMakerCharPositioner works like the one implemented in rpg maker. Moves the character left,up,right,down in a grid. While walking the correct animation of a RpgMakerCharSprite is played.

Intersection & Collision

Intersection & Collision

  • Intersectioner is used to calculate if something intersects another thing.
    • LevelMapIntersectioner takes a TiledLevelMap and checks what tiles are intersectioned.
  • CollisionDecisionMaker is used to specify when a sprite collides with something.
  • LevelMapTile is a data class that contains the Tile but also its position and layer.

Combine Intersectioner and CollisionDecisionMaker to tell a Positioner when the movement should stop.

LevelMapIntersectioner i = //(...)
RpgMakerCharPositioner p = //(...)
p.getCollisionDecisionMakers().add((sprite, area) -> {
    List<LevelMapTile> tiles = i.intersectsTiles(area);
    for(LevelMapTile lmt : tiles) {
        if("collision".equals(lmt.getTile().getType())) {
            return true;
        }
    }
    return false;
});

Tiled Map Basics

Map

A map (or level) is the world where your sprites will be placed. Building a map is easier with an editor where you can "draw" your levels. I recommend to use Tiled a map editor for tile-based maps.

Tileset

Tileset

Like a spritesheet is a set of sprites, a tileset is a set of tiles (building blocks). You "draw" the map by reusing and arranging the tiles to create an interesting level. In Tiled you can load tileset images and create a tileset (has file extension *.tsx). The tileset is XML-based and stores a relative path to the image file. Individual tiles can have string, int, float, boolean, file and color typed key-value-based properties.

Layers

Tiled allows you to create a map (file extension *.tmx) with multiple tile layers. This map format is also XML-based and stores relative paths to tilesets. One layer can use multiple tilesets.

ISO-Vs-Ortho

Usually, one of the two perspectives are used to render a map: isometric or orthogonal. Currently, JASGL supports mostly orthogonal rendering.

Map Objects

There are object layers that contain a set of objects instead of tiles. This can be used to define where sprites should be placed or events should be triggered.

Level Map

Map

Tiled has a library called libtiled to read and render maps in Java. JASGL uses this library and adds some utlity functions. In order to avoid name clashes with Map we call the base class in JASGL LevelMap.

  • LevelMap is the base class of all maps and just states that is can be rendered layer-wise. If you want to create your own map, you can inherit from this class.
    • TiledLevelMap represents an orthogonal map created by Tiled map editor.
public MyGame() {
    TiledLevelMap lvl01 = new TiledLevelMap(new File("/path/to/lvl01.tmx"));
    //or from maven's src/main/resources
    //TiledLevelMap lvl01 = new TiledLevelMap("/resource/path/to/lvl01.tmx");

    //access map data
    TileLayer foreground = lvl01.getTileLayerByName("foreground");
    ObjectGroup npcs = lvl01.getObjectGroupByName("NPCs");
    MapObject enemy01 = lvl01.getMapObjectByName(npcs, "enemy01");
}

Level Map Renderer

Renderer

A LevelMap is only a data class that holds what is in the map. Map Renderer draw maps in various ways depending on the effect.

  • LayerBasedOrthogonalLevelMapRenderer allows to render separate layers with render(String layerName, Graphics2D g).
  • TileBasedOrthogonalLevelMapRenderer allows to render each tile separately with a Consumer<DrawContext> tileRenderer.
  • StackRowBasedOrthogonalLevelMapRenderer renders tiles stacked and row based with map objects (having tiles) and sprites in between based on y-coordinate.

An simple layer-based example:

LayerBasedOrthogonalLevelMapRenderer r = new LayerBasedOrthogonalLevelMapRenderer(lvl01);

@Override
public void render(Graphics2D g) {
    //render all layers
    r.render(null, g);
    //or render layer-wise
    r.render("background", g);
    //here: render something in between the layers
    r.render("foreground", g);
}

Camera

Camera

Usually, the map is larger than the screen. Using a camera you can move the view port or follow a sprite.

  • Camera is the base class and contains the offset which can be changed to move the view port. Implementations decide how the offset is changed.
    • SpriteCamera is a camera that follows a given sprites.
private SpriteCamera camera;

public MyGame() {
    //...
    camera = new SpriteCamera();
    camera.setSprite(sprite);
}

@Override
public void init(GameLoop gameLoop) {
    //camera can access screen size
    camera.init(gameLoop);
}

@Override
public void update(double ms) {
    //update offset (after sprite was moved)
    camera.update(ms);
}

@Override
public void render(Graphics2D g) {
    //translate view port
    camera.render(g);
    //...
    camera.reset(g);
}

Game States

Game States

When you have more than one game state you can use the GameMultiplexer class. This is helpful when you want to switch between menu and gameplay, for example.

  • GameMultiplexer manages multiple games and let them switch between them. Because GameMultiplexer extends Game you could structure them recursively. GameStates can also instantiate new games on demand.
  • Game: the basic game class with the three major aspects: input handling, game state update and rendering.
    • GameState also adds methods for accessing GameMultiplexer as well as entering and leaving the state.

Example usage of the GameMultiplexer:

GameMultiplexer gameMultiplexer = new GameMultiplexer();
gameMultiplexer.addGame("1", new GameState1());
gameMultiplexer.addGame("2", new GameState2());
gameMultiplexer.switchTo("1");

GameLoopFrame.loop("Multi Game Demo", 800, 450, Color.white, gameMultiplexer);
private class GameState1 implements GameState {

    private GameLoop gameLoop;
    private GameMultiplexer gameMultiplexer;

    @Override
    public void init(GameMultiplexer gameMultiplexer) {
        this.gameMultiplexer = gameMultiplexer;
    }

    @Override
    public void init(GameLoop gameLoop) {
        this.gameLoop = gameLoop;
    }

    @Override
    public void enter(String predecessorName, Game predecessor) {
        //when entering this game state
    }

    @Override
    public void leave(String successorName, Game successor) {
        //before leaving this game state
    }

    @Override
    public void input(Keyboard keyboard, Mouse mouse) {
        //switch to second game state when right arrow is pressed
        if(keyboard.pressed(KeyEvent.VK_RIGHT)) {
            gameMultiplexer.switchTo("2");
        }
        //close game when escape is pressed
        if(keyboard.pressed(KeyEvent.VK_ESCAPE)) {
            gameLoop.close();
        }
    }

    //(...)
}

private class GameState2 implements GameState {
    //(...)
}

Game Memory

Memory Card

Model the memory to save the progess of the game for the player.

public MyGameMemory extends GameMemory {
    //attributes for player position or game progress
}

The GameMultiplexer holds the memory for all the games.

@Override
public void init(GameMultiplexer gameMultiplexer) {
    memory = (MyGameMemory) gameMultiplexer.getMemory();
}

By default, the memory is saved in a (working directory) save folder with yyyyMMddHHmmss date time pattern filename. The GameMemory.load() method loads the last saved memory. If not available, it returns a new instance of it (your "new game" state). Save the game by setting relevant information in memory and call save().

private void saveGame() {
    //update memory (where you are now)
    //memory.set(...)
    //save it
    memory.save();
    System.out.println("memory saved");
}

Scripting

Scripting

Allow to add game behavior via the script language JavaScript while designing the map.

In Tiled create MapObjects with properties representing scripts.

Scripting-Screenshot

Put bindings to access in JavaScript your Java instances. Later, retrieve the script from a MapObject's properties and call eval-method.

this.scriptEngine = new GameScriptEngine();
this.scriptEngine.putBinding("game", this);

//later
String script = mapObject.getProperties().getProperty("onPlayerTouch");
scriptEngine.eval(script, mapObject);

Game Overview

All game related classes in one diagram:

Game Diagram

A recap:

  • Use GameLoopFrame.loop to start your game
  • Loop relevant information can be accessed in the game via GameLoop interface
  • Implement in your game input, update, render method
  • More complex games could use the GameMultiplexer to switch between Games resp. GameStates
  • A good starting point could be TiledGame because it already implements usual behavior
  • GameMemory helps in saving and loading a game
  • GameScriptEngine can be used to enable scripting with JavaScript in your game

About

Game Library written in Java using AWT/Swing for rendering

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages