Skip to content

moomoohk/grame

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grame

An easy to use, lightweight 2D grid based game engine!

Click here for the latest major release.

The JavaDocs can be downloaded here and can be viewed online here (although the online version might be outdated!).

#Getting started

On top of reading this documentation, I highly encourage you to have a look at the JavaDocs for a detailed list of classes and methods.

##Dependencies

Grame relies on two libraries I wrote:

  1. MooCommands
  2. MooConsole

Unfortunately I haven't yet found a way to bundle dependencies into one JAR file so you'll have to add all three to your classpath.

##Writing your game

Create a new main game class. This class will contain the starting point for your code as well as some metainfo for the engine and will also register your class as a main game class.

public class Game implements MainGrameClass
{
    public static void main(String[] args)
    {
        GrameManager.initialize(new MainGameClass());
    }

    @Override
    public void newGame()
    {
        System.out.println("Hello World!");
    }
    
    @Override
    public String getGameName()
    {
        return "Hello world";
    }
}

Running this code will produce a main menu which will display what the getGameName() method returns and will run the newGame() method when the player hits the play button.

The engine is split up into two parts:

  • The core: The core contains all the core classes which you'll have to use.
  • The basics: The basics are a collection of helpful classes I wrote which utilize the core and will probably save you a lot of time.

##The core

###IDs

The two main components of the engine are the Grids and the GrameObjects. Every instance of both of those components will automatically get a unique ID number associated with them by the GrameManager when they're created. The IDs are created successively. The ID successions for Grids and GrameObjects are independent (meaning you can have a Grid object with ID:1 and a GrameObject object with ID:1).

###GrameManager

The GrameManager class contains the central engine clock as well as the GrameObject and Base list. It also keeps tracks of user input so you don't have to.

GrameObjects and Grids can be retrieved by ID from the GrameManager's lists using GrameManager.findGrameObject(int goID) and GrameManager.findGrid(int gID) respectively.

###GrameObjects

GrameObjects are the entities that occupy spaces in your Base. They can be players, NPCs, walls, anything.

The GrameObject class is an abstract one. Instantiate one like so:

import java.awt.Color;

public class Example extends GrameObject
{
    private static final long serialVersionUID = 1L;

    private boolean collidable;

    public Example(String name, int speed, Color color, boolean paused, boolean collidable)
    {
        super(name, speed, color, paused);
        this.collidable = collidable;
    }

	@Override
	public boolean isCollidable()
	{
		return this.collidable; //Will normally be hardcoded
	}

	@Override
	public void tick(int gID)
	{
	}

	@Override
	public void consume(GrameObject go)
	{
	} 
}

The speed of GrameObjects will determine how often the GrameManager's clock will call their tick(int gID) method (in 60/ths of a second).

The tick(int gID) method should be used to calculate things like movement. The gID parameter represents one of the IDs of the Grids that this GrameObject has been added to. If your GrameObject has been added to more than one Grid, the GrameManager will call the tick(int bID) method using all of the Grid IDs one by one.

The consume(GrameObject go) method dictates to the GrameObject what to do in the event that it is collidable and it moves into a square that is occupied by a non collidable GrameObject. Leaving this method blank will simply overwrite the old non collidable GrameObject with your new collidable GrameObject.

###Grids

Grids are the map spaces of the engine. They will contain all your GrameObjects.

Grid g = new Grid(20, 20);

By default Grids start with one GrameObjectLayer but more can be added to create 3 dimensions:

g.addGrameObjectLayer(new GrameObjectLayer(20, 20));

GrameObjectLayers are organized in a list inside the Grid. Using the default addGrameObjectLayer(GrameObjectLayer gol) method will add the parameterized GrameObjectLayer to the end of the list. The overloaded addGrameObjectLayer(GrameObjectLayer gol, int place) lets you manually place GrameObjectLayers in specific places in the list. The lowest GrameObjectLayer is the one at place 0 and any other ones that get added later get stacked on top of it.

Adding a GrameObject to a Grid:

g.addGrameObject(new Example("example", 2, Color.blue, false, true), new Coordinates(0, 0));

###Coordinates

These do what their name suggests which is contain an x and y value. These are used extensively to reference squares in Grids.

Coordinates c = new Coordinates(0, 0);
System.out.println(g.isInGrid(c));

###Dirs

Dir objects represent directions. They contain x and y values which can be either -1, 0, 1.

Dir up = new Dir(0, -1);
Dir down = new Dir(0, 1);
Dir left = new Dir(-1, 0);
Dir right = new Dir(1, 0);

Alternatively:

Dir up = Dir.UP;
Dir down = Dir.DOWN;
Dir left = Dir.LEFT;
Dir right = Dir.RIGHT;

These make coding AI a lot easier.

##The basics

Can be found in the com.moomoohk.Grame.Basics package.

###MovementAI

The MovementAI abstract class lets you create AI classes for use with Entitys (and other GrameObjects).

Grame comes with five ready to use AIs (which can be found at com.moomoohk.Grame.Basics.AI):

  • AStartPathfindingMovementAI - Implementation of the A* pathfinding algorithm
  • PlayerMovementAI - Reads user input from the GrameManager and can be used to control Entitys using WASD or the arrow keys
  • (Debug) PlayerSimAI - Will pick a random direction and move in it for a random number of squares. If it hits an obstacle it will switch directions
  • SimpleChaseAI - "Stupid" pathfinding. Will try to move in a straight line between itself and its target. If it hits an obstacle it will attempt to "slide" along it
  • SimpleStrollAI - Will move in random directions. Useful for peaceful NPCs

Check out the source code for PlayerMovementAI for a simple MovementAI implementation.

###Entity

Entities are generic GrameObjects which support AI and a few other useful features.

Their AI system works with "stacking". You provide them with a list of MovementAIs (in order of preference) and every time they get ticked by the GrameManager they will go through the list (in the order of preference) and evaluate their MovementAIs using the isValid method. The first "valid" MovementAI in its list will be used to determine its next movement.

These following lines of code will produce a player Entity an Entity which will stroll randomly by default but will start chasing the player once the player enters its range:

Entity player = new Entity("player", 1); //name, speed
player.addAI(new PlayerMovementAI(1)); //1 for WASD, 2 for arrow keys

Entity monster = new Entity("monster", 2);
monster.addAI(new SimpleStrollAI());
monster.setRange(5); //Range is set to a 5 square radius
monster.addAI(new SimpleChaseAI());

The EntityGenerator interface lets you create Entity generation classes. These are useful when you'd like to procedurally generate them. Grame comes with one implementation of it. The DefaultRandomGen will randomly generate names based on some basic language heuristics and types by picking a random spot in an array containing "human", "orc" and "elf".

The Entity AI system makes creating player GrameObjects really easy:

ent.makePlayer(1, true, g.ID);

###Wall

Walls are what you'd expect them to be. They are collidable, static GrameObjects.

Wall w1 = new Wall(); //Default wall color is Color.black
Wall w2 = new Wall(Color.green);

#TODO

  • Add a way for the engine to detect when the game is finished
  • Flesh out the main menu system

I should probably include a picture of a sheep:

alt text