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:
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 algorithmPlayerMovementAI- Reads user input from theGrameManagerand can be used to controlEntitys 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 itSimpleStrollAI- 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:
