Making an RPG with Löve2D

Introduction

Making a role playing game, as most developers are aware, is not an easy thing. RPGs have dozens of complex systems and ideas that need to play well together seemlessly and typically hundreds of items, dialogue trees, monsters, and almost anything else you could think of. Luckilly, Löve2D makes making any game much easier by getting out of the way and letting you do what you need to without sacrificing any control. I've been using Löve2D for about as long as I've been programming so I think I have enough authority to say, without a doubt, that I have no idea what I'm doing. AS SUCH this will not be a tutorial, and will assume prior knowledge of Löve2D. Feel free to use this as one but I will not be held accountable for any injuries you incur as a result. The intention here is to learn some new tricks and try to teach myself how to better handle a larger project on my own (and also to force myself to keep better documentation). This is going to be a living post so check back every few weeks (likely) for updates and revisions.

This game will likely be fairly generic and by all accounts, standard. The story is not going to be the focus of this series but we'll do a little bit of world building as we go along. There will be (as one would expect) player movement and animation, varying tile-based maps, NPCs and interactions, quests, items and inventory management of some variety, player/party management with a leveling system, a combat system with animations, and (probably) more.

The Assets

As far as art goes, we'll be using almost entirely borrowed assets from places like OpenGameArt and Itch.io. Anything taken from any of the artists on these sites or any other source will be properly credited and the licences they use will be observed.

EDIT: I've decided to go with the Time Fantasty assets made by Finalbossblues because there is an absolute wealth of high quality content. Until I decide that it's worth the investment, I'm just going to be using some of the freebies.

When it comes to music, I'll probably be lifting tracks from OpenGameArt and Itch.io but I may also take tracks from some projects I have done in the past which are either of my own making or from a friend, these will also be credited properly and not used without permission.

Sound Effects (sfx) will likely be made myself using the program Bfxr or also lifted from one of the previously mentioned sites.

Direct download links or project page links will be provided for any assets I choose to use here:

Structure

Some time ago I came across this article which has the following chart:
This is going to be the basic development structure we're going to follow. Everything below the dotted line is handled by the game engine, in this instance Löve2D. We won't be following it exactly because I'm an impatient and fallible human being but it will represent the basic structure of the systems we create.

The Boring Stuff

Here we're going to put together the file structure of the project, assemble some assets, download and install any tools and libraries we need, and get everything ready for development.

The project is hosted in a git repo here. There you can see the file structure and take a peak at the config file, which is pretty standard. The only really important bits for right now are these lines here:


...
t.window.width  = 720
t.window.height = 1080
...
		
As we said before, we're using Löve2D which is Lua based. One of the few libraries I'll be using is Lurker (which depends upon Lume). Lurker is a development tool that will detect changes in our source files and automatically reload our project. To get that setup, in our main file just include Lume and include Lurker in our main update loop. As such:

lume = require("lib/lume")
...
Quad = love.graphics.newQuad
...
function love.update(dt)
	lurker = require("lib/lurker").update()
end
...
		
You can see we also created a global variable set to the function love.graphics.newQuad I generally would not do something like this, but we are going to be calling this function many many times and it is going to save us a little bit of time.

Some Fun Stuff, The Player

Next, I'm going to put together a basic player character. I am above all else, a lazy meat creature so I'm going to use a small library that I wrote, pms. It's just a simple and messy library to implement some basic movement for rapid prototyping, we'll change this later to a more permanent and fitting system. Before we set that up, let's load in the sprite sheet and setup some quads for animation. For our player we're going to be using this sprite sheet:

The source for which is listed above.


local player = {}

function player.load()

	player.img = love.graphics.newImage("res/img/knights.png")
	player.frames = {
		["down"] = {
			Quad(81,7,  19,29, player.img:getDimensions()),
			Quad(107,7, 19,29, player.img:getDimensions()),
			Quad(133,7, 19,29, player.img:getDimensions()),
			Quad(107,7, 19,29, player.img:getDimensions()),
		},
		["left"] = {
			Quad(81,43,  19,29, player.img:getDimensions()),
			Quad(107,43, 19,29, player.img:getDimensions()),
			Quad(133,43, 19,29, player.img:getDimensions()),
			Quad(107,43, 19,29, player.img:getDimensions()),
		},
		["right"] = {
			Quad(81,79,  19,29, player.img:getDimensions()),
			Quad(107,79, 19,29, player.img:getDimensions()),
			Quad(133,79, 19,29, player.img:getDimensions()),
			Quad(107,79, 19,29, player.img:getDimensions()),
		},
		["up"] = {
			Quad(81,115,  19,29, player.img:getDimensions()),
			Quad(107,115, 19,29, player.img:getDimensions()),
			Quad(133,115, 19,29, player.img:getDimensions()),
			Quad(107,115, 19,29, player.img:getDimensions()),
		}
	}
	--Init the movement system, starting X, starting Y, movement speed.
	player.ms = pms.init(100,100, 150) 
end
...
return player
		

Stay tuned...