Skip to content
/ Lunar Public
forked from Vrekt/Lunar

Making games in Java is now easier than ever before!

License

Notifications You must be signed in to change notification settings

rickbau5/Lunar

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

About Lunar

This engine is good for:

  • creating casual 2D games.
  • create some sort of prototype fast.
  • hobby developers, etc!

Not good for:

  • 3D games, mobile, games with lots of physics

Tutorial

Getting Started!

To start you want to initialize the Lunar class.

Lunar lunar = new Lunar();

This class holds everything you will need for your game. Alternatively you can create a direct object for Game as well as the SoundManager and AssetManager.

Game game = new Game(title, width, height, tickRate);
Game game = new Game(title, width, height, GameState, tickRate);

SoundManager sm = new SoundManager();
AssetManager am = new AssetManager();

Using the lunar object starting the game is simple.

lunar.initializeGame(title, width, height, tickRate);
lunar.initializeGame(title, width, height, GameState, tickRate);

lunar.getGame().start();

Using the game object starting the game is just as easy.

game.start();

Lets go over the fields. title - This indicates the title of the window. width, height - the dimensions of the window.

tickRate indicates how fast the game is drawn/updated. A good tickrate is 64 or above.

gameState; this is not required when starting the game. Choosing to add this will not require you to add a gameState manually.

GameStates

GameStates are the base of your game. Each GameState will hold two methods onTick(); and onDraw(Graphics graphics);. In your gameState you may keep track of worlds, players and other entities. Here is an example:

public class MainState extends GameState {
	private Player player;
	private Level1 world;

	public MainState(int priority) {
		super(priority);

		player = new Player(params);
		world = new Level1("world1", 600, 400);
		world.addEntity(player);

	}

	@Override
	public void onDraw(Graphics graphics) {
		world.onDraw(graphics);
	}

	@Override
	public void onTick() {
		player.updateEntity();
		player.updateBoundingBox();

		world.onTick();

	}
}

priority indicates which GameState to draw/update first, this is useful for multiple GameStates. 0 will be the first to draw/update and then everything next.

Entities

Entities are for example your player or an enemy. To create a custom entity start by extending LivingEntity. LivingEntity indicates its 'living' and requires health/speed values.

Entity classes have the option to use a sprite, although not required be sure to remember using built in draw functions for entities use the sprite.

public class MyPlayer extends LivingEntity {
	public MyPlayer(int x, int y, int width, int height, int entityID, float health, double speed) {
		super(x, y, width, height, entityID, health, speed);
	}

	/**
	* Lets draw a simple red box that represents our player.
	*/
	@Override
	public void drawEntity(Graphics graphics) {
		graphics.setColor(Color.red);
		graphics.fillRect(x, y, width, height);
	}

	/**
	* Basic movement for our Player.
	*/
	@Override
	public void updateEntity() {
		boolean w, a, s, d;
		w = InputListener.isKeyDown(KeyEvent.VK_W);
		a = InputListener.isKeyDown(KeyEvent.VK_A);
		s = InputListener.isKeyDown(KeyEvent.VK_S);
		d = InputListener.isKeyDown(KeyEvent.VK_D);

		if (w) {
			y -= speed;
		}

		if (a) {
			x -= speed;
		}

		if (s) {
			y += speed;
		}

		if (d) {
			x += speed;
		}
	}
}

Lets go over the fields.

x, y - the position of the player. width, height - dimensions of the player.

entityID - in each world entities are managed by their ID. Think of this as a unique number for each entity. If we have a player and a mob its up to you which ID they're assigned.

health - the health of the entity. speed - the speed of the entity.

Sounds

To play a sound you want to create a new Sound object. Each sound has an ID and the audio file.

Sound sound = new Sound(int ID, File audio);

To play the sound simply get your SoundManager instance. Either via your lunar object or making a new instance.

SoundManager sm = lunar.getSoundManager();

sm.playAudio(sound);

You can also keep track of all your game sounds within the SoundManager. Alternatively if you don't want to create a new Sound object you can play the file directly.

sm.playAudio(file);

Input

Every game needs input and Lunar provides Mouse and Keyboard input. For example, to check if a certain key is pressed:

InputListener.isKeyPressed(KeyEvent.KEY);

MouseInput has many useful methods, as documented here:

/**
 * Gets the click coordinates.
 */
public static Point getLastClick() {
	return lastClick;
}

/**
 * @return true of the mouse is down, false otherwise.
 */
public static boolean isMouseDown() {
	return isMouseDown;
}

/**
 * Get the component the mouse entered. This can return null if the mouse
 * exited the component.
 */
public static Component getEnteredComponent() {
	return enteredComponent;
}

Worlds

Creating a custom world is very easy. Start by extending World.

public class MyWorld extends World {

	public Level1(String name, int width, int height) {
		super(name, width, height);
	}

	@Override
	public void onDraw(Graphics graphics) {

	}

	@Override
	public void onTick() {

	}
}

Each class extending World can use many useful methods within the World class to make things easier. These include:

adding entities adding tiles, adding multiple tiles at once in one method. drawing all entities and tiles getting an entity via their ID. and many more!

Tiles, Sprites

Tiles are essential for a textured game.

Each tile holds an ID, the texture, if its solid or not and their width/height. If we want a tile for a Wall this can be done easily.

To start lets load our SpriteSheet.

SpriteManager sm = new SpriteManager(SpriteManager.load("pathToSheet.png"));

Now we can easily get certain textures at certain points in our spritesheet. For example if we have the Wall texture at 0, 0 and its 64x64 we can get it using:

BufferedImage wall = sm.getSectionAt(0, 0, 64, 64);

Now we have our wall texture. Lets now create the tile.

Tile tile = new Tile(wall, 0, true);

As you can see we created the tile with our wall texture, an ID of 0 and the isSolid flag set to true. Now we can add this to our world

world.addTile(tile, x, y);

The AssetManager holds all of our game tiles. Simply get it using the lunar object or creating a new instance.

AssetManager am = new AssetManager();

Lets store our tile:

am.addTile(tile);

AssetManager includes the ability to get a tile via ID as well as remove and add tiles.

RayTracing

RayTracing can be used to find for example a wall or a certain tile. If we wanted to check if there is a solid tile in front of the player we can! Start by making new instance of the RayTracing.

RayTracing rayTrace = new RayTracing();

Now lets check if there are any solid blocks in front of us. Our direction is RIGHT and lets go to a distance of 4.

Tile tile = rayTrace.getNextSolidTile(myWorld, player.getX(), player.getY(), 4, Direction.RIGHT, 64, 64);

Now we have our tile. If the tile is null this indicates no tile was found.

AnimationManager

The AnimationManager is very useful in situations where you have many images (such as a player sprite walking each direction with each leg).

Lets create a new SpriteManager with our character spritesheet.

private SpriteManager characters = new SpriteManager(
			SpriteManager.load("C:\\Users\\Vrekt\\Desktop\\characters.png"));

Now we can start, lets create an animation for each direction.

private Animation up;
private Animation down;
private Animation left;
private Animation right;

Now with the SpriteManager we can put the getMultipleSprites method to use.

BufferedImage[] bup = characters.getMultipleSprites(0, 96, 32, 32, Direction.RIGHT, 3);
BufferedImage[] bdown = characters.getMultipleSprites(0, 0, 32, 32, Direction.RIGHT, 3);
BufferedImage[] bleft = characters.getMultipleSprites(0, 32, 32, 32, Direction.RIGHT, 3);
BufferedImage[] bright = characters.getMultipleSprites(0, 64, 32, 32, Direction.RIGHT, 3);

Now we can initialize the Animations.

up = new Animation(bup, 20, true, 0);
down = new Animation(bdown, 20, true, 1);
left = new Animation(bleft, 20, true, 2);
right = new Animation(bright, 20, true, 3);

Lets add them to a list.

List<Animation> animations = new ArrayList<Animation>();
animations.add(up);
animations.add(down);
animations.add(left);
animations.add(right);

Finally lets initialize the AnimationManager with the animations.

am = new AnimationManager(animations);

In our player class we have a field named 'playerDirection' which keeps track of which way the player is facing, lets use this for our animation.

Direction d = player.getDirectionFacing();

Now what we can do is start an animation based on which way we are facing.

am.startAnimation(d == Direction.UP ? up : d == Direction.DOWN ? down : d == Direction.LEFT ? left : right);

Now lets draw the current frame of the animation.

am.getCurrentPlayingAnimation().drawCurrentFrame(graphics, player.getX(), player.getY());

Now in our tick method we can update the animation.

if (am.getCurrentPlayingAnimation() != null) {
	am.getCurrentPlayingAnimation().updateAnimation();
}

Using the Capture utility.

The Capture class provides easy access to creating screenshots. To screenshot and save it simply use:

Capture.screenshotAndSave(int width, int height, File saveTo, String imageType);

imageType indicates what type the image is, eg: bmp, png, etc. There is also methods for capturing parts of the window.

Capture.screenshotPart(int x, int y, int width, int height);

About

Making games in Java is now easier than ever before!

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 100.0%