← All posts

Put a little LÖVE into your game

Once you decide to remake a game, the engines start campaigning. I voted for less paperwork.

When you love trying new languages and engines, picking one for your next project is no small decision. It feels more like an election: every candidate makes promises they won’t keep, but you still hope this time will be different.

This time, though, the vote was over quickly. Faster than usual. Which is a shame, because I love this kind of election campaign.

But I wanted a government in place as soon as possible, with rapid prototyping at the top of its agenda. I think this political metaphor is getting away from me.

The other candidates

As usual, I gave the alternatives another look so nobody would feel left out. Partly to catch up on anything new, and partly so I could write this article say I’d considered other options.

Godot. It’s a great engine, with an editor, a scene system, and just about everything you could ask for. And that’s the problem: it gives me too much. For a single-screen game at 256×224 pixels with arcade physics, it felt like taking a truck to buy a loaf of bread. Besides, I have to admit that integrated development environments and I have never quite clicked.

C++ with raylib. Now we’re talking total control. And writing everything myself. And waiting for it to compile. And packaging it for three operating systems by hand. There’s a certain charm to that, but this is a project for fun, not for arguing with a compiler on a Sunday morning.

Go with Ebitengine. I like it. I like it a lot. I have several half-finished prototypes, and it nearly won. But I remembered that iterating on them hadn’t been as quick as I’d wanted. This time, I wanted to make changes quickly and keep moving.

With all that on the table, the decision was pretty much made before I started.

An old friend

I’d used LÖVE before. Nothing serious: prototypes and experiments. I hadn’t touched it in a while, but coming back was like riding a bike. You don’t forget how simple it is.

I knew what it would give me, and I knew it was exactly what this project needed. A cross-platform engine focused on 2D games, with a small, fast language and a community that supports it and keeps adding to it.

function love.load()
  hero = love.graphics.newImage("hero.png")
  angle = 0
end

function love.update(dt)
  angle = angle + dt
end

function love.draw()
  love.graphics.draw(hero, 128, 112, angle)
end

The community

I love the LÖVE community. There’s a ridiculous number of small, practical libraries made by people who had a specific problem and solved it. That saves the rest of us from reinventing the wheel yet again, so we can focus on what matters: making games.

There’s also a huge collection of games made with the engine that are a joy to play and show it’s more than up to the job.

I still go back to Soulstice, Slugcaster, and Blast Flock from time to time. Just a few of my favorites.

It’s an engine that encourages people to make things with care. And that comes through in the community.

What the game needed

Affection aside, Super Dungeon Cell has some very specific requirements:

  • A 256×224-pixel screen, the same resolution as the NES, scaled to fit the window without blurring anything. Integer scaling only: ×2, ×3, ×4. A pixel must always be a perfect square. At least until I add a shader that turns the whole thing inside out.
  • Arcade physics: boxes colliding with blocks. No need to simulate the real world.
  • Two players sharing a keyboard or using controllers, each with controls they can remap.
  • Everything running at 60 steps per second, exactly the same way every time, so what happens today is what happens tomorrow.
  • A way to test the game logic without opening a window.
  • A way to package it for macOS and Windows without dragging along a runtime the size of an operating system.
Level 9 heroes might need a little balancing.

Why it fits

LÖVE does a little, and does it well. It gives you a window, 2D graphics, sound, keyboard and controller input, and file access. It doesn’t impose an editor or tell you how to organize your characters. For someone as fussy as I am about organizing code, an engine with no opinions is a blessing.

Lua fits in your head. It’s a small, fast language (LÖVE uses LuaJIT) without much fuss.

Packaging and distribution are easy. A LÖVE game is basically a zip file with a .love extension. From there, you get a macOS app and a Windows folder with an .exe, icon and all.

And the feedback loop is tiny. Change a line, run the game, see the result. When your job is to tweak an archer’s jump until it feels right, that’s all that matters.

What LÖVE doesn’t give you

Now for the part they leave out of the brochure. LÖVE gives you the basics, and you build the rest yourself. Or, better yet, borrow it from the community.

With libraries like bump, hump, and anim8, you can have creatures that collide with the floor, feel the passage of time, and do more than stand there looking decorative.

Who doesn’t want hordes of creatures killing their heroes over and over? If they never suffered, they’d just be people with capes.

More to tell

I haven’t decided whether it’ll be another article or a whole series. But there’s plenty to tell about how LÖVE helped me remake a twelve-year-old prototype, and how I tried to keep it as faithful to the original as possible.

That can wait for another day. There are still features and bugs to add to the game.