Building my next 2D game engine

Juriën MeerloJuriën Meerlo
4 min read

I have made small 2D game engines in my free time for a few years. I went from simple game engines to complex macro-generated ECS ones with dependency injection. My latest game engine is the most complex one. When I finished a game using it, I decided that all that complexity was unnecessary for the games I made. I spent a lot of time trying to make simple things work. This new iteration should be much less complex.

I have decided to use the LÖVE framework as a base for my next engine. I will use TypeScript as the scripting language using TypeScriptToLua.

I'm calling it Lumi2d for now. That might change later.

Before starting, I want to write down the features I want to have in the engine and the structure of it.

Features

These are some of the features I would like to have in Lumi2d:

  • Scene Management

    There should be a way to switch from one scene to another and stack them on top of each other. This will make things like pause overlays easy.

  • Asset Management

    There should be a way to load, store, and unload assets like images, sounds, text, tilemaps, etc.

  • Event System

    Sending events between different parts of the engine and inside games is very useful. There should be a generic event system. It should be extendable by users of the engine. It will also be used for input handling. Sending events will be synchronous.

  • Tweening

    There should be tweening functions that can transform the properties of objects over time. They should be reusable. There should be a way to make a sequence of multiple tweens easily.

  • Entities and Components

    In the past, I went overboard with the whole ECS architecture. I don't need that complexity for the games I make. This engine will have a simpler version with logic inside entities and components. I want to be able to reuse logic, but not everything needs to be separated. An entity is a base object that can have an update and or render function. Components can be updated or rendered inside those functions. There is no need to overcomplicate it.

  • Rendering System with Layers and Cameras

    There should be a rendering system that orders entities by layer. Entities can be reordered inside the layers if needed. Multiple cameras can be added to a scene. Each camera renders in the order they were added.

  • Tilemap support for Tiled and Ldtk

    There should be support for loading and rendering Tiled and Ldtk tilemaps.

  • AABB Physics

    LÖVE has Box2d physics. This is great, but sometimes you don't need to simulate real-world physics. There should be simple box physics with quadtree broad-phase collision checking. There should be gravity, forces interaction callbacks, and simple raycasting.

Structure

In my previous engine, I would use dependency injection to inject services. Those are like global variables with extra steps. I will use some static classes for things used in many different places. This is not really best practice, but I don't see the need to overcomplicate this.

Static class plan:

  • Asset Manager - loading and storing assets.

  • Scene Manager - change scenes.

  • Event System - send events.

  • View System - window size info, view size info, scaling.

  • Tween Manager - create and manage all tweens.

  • Timer Manager - create and manage timers and delays.

The event system will have global and scene events. The scene events will have to be set and activated per scene. Tweens and Timers will also be per scene.

Entities will have a layer field. Entities can be added and removed from a scene and will be updated and drawn by it.

Components are flexible. They can have just data or have logic in them. They can be used to reuse code between entities.

One of the goals is to make it flexible and make a lot of systems optional so they can be replaced without changing the engine itself.

View System

Scaling to each resolution can be an issue when making mobile games. There should be a way to set the design resolution and scale modes to scale that resolution up or down to fit the window. Some of the scale modes could be:

  • Letterbox with black bars.

  • Fit width

  • Fit height

  • Fit screen

  • No scale

Next Steps

I have set up a new GitHub repo here https://github.com/codescapade/lumi2d.
I will start building Lumi2d and posting about the process and design decisions.

0
Subscribe to my newsletter

Read articles from Juriën Meerlo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Juriën Meerlo
Juriën Meerlo

I'm a senior software engineer using TypeScript, C#, and Python in web and application development. As a hobby, I make games using custom game engines. You can find my latest game Gravity Golfing on iOS. I'm Working on and posting about my new engine called Lilo2d.