Engine Overview

Welcome to the Lisa Engine documentation. This guide covers the architecture and inner workings of the engine that powers games like CoolFox and NeonSignal.

Overview

Lisa Engine is a 2D platformer engine built on the libGDX framework. It implements a custom Entity-Component System (ECS) and ships as a Gradle library — consuming games add their own platform launchers (desktop, Android, iOS, …), player implementation, and game-specific entity factory.

What Lisa Engine provides

  • An ECS runtime with a spatial grid for collision

  • A library of ~50 platformer components (movement, hazards, switches, enemies, particles, …)

  • Level loading from Tiled TMX maps

  • A unified input abstraction across keyboard, touch, and gamepad

  • A set of menu / cutscene / dialog / settings screens

  • A JSON-based script system for cutscenes and abilities

  • Resource managers for textures, sounds, fonts, animations, levels, paths, secrets

What the consuming game provides

  • Platform launchers (desktop/android/ios/…)

  • A subclass of EngineConfig with the game’s name, resources, and physics constants

  • A subclass of EntityFactory with game-specific createX() methods (typically including the player)

  • The PlayerComponent (or equivalent) and any other game-specific components

  • Tiled maps, textures, sounds, scripts, fonts

Engine Architecture

The Big Picture

Game's Application entry point (e.g. DesktopLauncher)
    ↓
Engine (Lisa Engine core orchestrator)
    ├─ Resource Managers (Textures, Sounds, Fonts, Levels, …)
    ├─ Input System (Keyboard, Touch, Gamepad)
    ├─ Screen Manager (Game, Menu, Pause, …)
    └─ Entity-Component System
        ├─ GameScene (world container)
        ├─ EntityManager (lifecycle & spatial grid)
        └─ Entities (composed of components)

Core Classes

Engine (core/src/net/dynart/lisa/core/Engine.java)

  • The orchestrator that owns the asset manager, input multiplexer, screen lifecycle, and resource managers

  • Initialized by the consuming game with an EngineConfig

EngineConfig (core/src/net/dynart/lisa/core/EngineConfig.java)

  • Base configuration class. The consuming game subclasses it and supplies the game’s name, the EntityFactory, the FadeRenderer, and JSON-driven settings (physics, input, display).

EntityFactory (core/src/net/dynart/lisa/core/EntityFactory.java)

  • Base factory with createX() methods for the engine’s built-in entity types

  • Consuming games subclass it to add their own (player, custom enemies, etc.)

  • Uses reflection: when the level loader sees an object of type "player", it calls createPlayer().

GameScene / EntityManager

  • GameScene is the per-level world container.

  • EntityManager owns entity lifecycle and a spatial grid (160px cells) for collision queries; it also organizes entities by draw layer.

Entity-Component System

Game objects (entities) are built by composing reusable components.

  • Entity — a container that holds components and supports parent/child hierarchy for relative positioning. Components live in a HashMap for fast lookup.

  • Component — abstract base with lifecycle methods preUpdate(), update(), postUpdate(). Components can subscribe to messages via the MessageHandler for event-driven behavior.

Component Library

Lisa Engine ships ~50 platformer components, organized roughly by role:

Physics & collision

BodyComponent, VelocityComponent, GridCollisionComponent, EntityCollisionComponent, WaterCollisionComponent, ColliderComponent, PlatformComponent, BlockComponent, DisappearingBlockComponent, EnemyBlockComponent

Health & damage

HealthComponent, MiniBarComponent, OxygenComponent, OverlapAttackComponent, OverlapAttackableComponent, ReviveComponent

Enemies

EnemyComponent, WalkerComponent, JumperComponent, FrogComponent, RushComponent

Hazards

SpikeComponent, ElectricSpikeComponent, CrushComponent, FallingComponent, StartFallingInDistanceComponent, StartFallingOnMountComponent

Switches & interactives

ButtonComponent, SwitchComponent, SwitchableComponent, KillSwitchComponent, KnifeSwitchComponent

Movables & transport

MovableComponent, BoxComponent, PusherComponent, MountableComponent, ConveyorComponent, TramComponent, SpringboardComponent, RailEndComponent

Bullets

BulletComponent, BulletSpawnerComponent

Rendering & effects

ViewComponent, ParticleComponent, ParticleEmitterComponent, SplashComponent, ActionComponent

Collectibles, exits, scene triggers

ItemComponent, SecretComponent, ExitComponent, ActivateOnScreenComponent, CameraLimitTriggerComponent, SceneWarpComponent

Note: The player itself is not an engine component — each game implements its own player on top of these primitives.

Level Loading

GameSceneLoader (core/src/net/dynart/lisa/core/GameSceneLoader.java)

  • Loads Tiled TMX maps

  • Parses background, main, and foreground layers

  • Creates entities from object layers via the EntityFactory

  • Sets up music, camera limits, and player abilities for the scene

  • Handles layer separation for parallax effects

Levels are TMX files designed in Tiled, stored in the consuming game’s assets/data/levels/ and registered in resources.json.

Input System

A unified abstraction across keyboard, touch, and gamepad.

  • GameController (core/src/net/dynart/lisa/core/controller/GameController.java) — central input hub with a logical button set: LEFT, RIGHT, UP, DOWN, A, B, X, Y, MENU.

  • KeyboardListener — desktop keyboard input.

  • TouchListener — mobile touch with on-screen buttons.

  • GamepadListener — console-style gamepad / joystick.

Bindings are user-customizable via the engine’s customize-controls screens.

Screens

The engine ships 16 screens for common game states:

Core gameplay: GameScreen, GameFadeInScreen, PauseScreen, GameOverScreen

Menus: MenuScreen, SettingsScreen

Customization: CustomizeButtonsScreen, CustomizeKeyboardScreen, CustomizeGamepadScreen, CustomizeTouchScreen

Narrative: CutsceneScreen, DialogScreen

System: LoadingScreen, LogoScreen, EmptyScreen

GameStage provides the in-game HUD overlay (score, health, pause button) on top of GameScreen.

Script System

A JSON-based command system used for cutscenes and special abilities.

  • Command pattern — each command implements act(delta) and returns true when finished.

  • Composition: SequenceCommand, ParallelCommand, SkippableCommand

  • Dialog & timing: SayCommand (via DialogStage), DelayCommand

  • Movement: WalkToCommand, WalkToExitCommand, SetMovementActive

  • Animation: SetAnimationCommand, SetVisibleCommand

  • Camera: MoveCameraToCommand, SetCameraTargetCommand, SetCameraLimitCommand

  • Game logic: TriggerCommand, PlayMusicCommand, SetParentCommand

Scripts are stored as JSON in the consuming game’s assets/data/scripts/ and loaded via ScriptLoader.

Resource Management

Resource managers, owned by Engine:

  • TextureManager — texture atlases and individual textures

  • SoundManager — sound effects and music with volume control

  • FontManager — bitmap fonts

  • SpriteAnimationManager — animation caching

  • LevelManager — level registration and retrieval

  • PathManager — movement paths for entities

  • SecretManager — secret-collectible tracking

Configuration files (provided by the consuming game)

  • config.json — physics constants, input mappings, platform-specific overrides

  • resources.json — asset registry (sounds, music, textures, levels, animations)

Platform-specific sections in config.json override base values; arrays in platform sections replace rather than append.

Architecture Patterns

Composition over inheritance

Entities are not defined by class hierarchies but by the components they contain. A moving, animated, collectible object is just the right combination of components.

Spatial grid

EntityManager divides the world into 160px grid cells. Collision checks only consider entities in nearby cells, keeping detection fast even with many entities on screen.

Message / event bus

Components publish and subscribe to events through MessageHandler. This loose coupling lets systems react to events (e.g. a collectible being picked up) without hard-wiring references to each other.

Reflection-based factory

EntityFactory uses reflection to dispatch object types from Tiled to createX() methods. Add a new entity type by adding a createMyType() method to your subclass — no registration code required.

Pooling

Particles and bullets use object pools (ParticlePool, BulletPool) to reduce GC pressure in tight inner loops.

Adding a new entity type (in your game)

  1. Define the component in your game’s components package:

    public class MyComponent extends Component {
        @Override public void update(float delta) { /* ... */ }
    }
    
  2. Add a factory method to your game’s EntityFactory subclass:

    public Entity createMyEntity(Parameters parameters) {
        Entity entity = new Entity();
        entity.addComponent(new BodyComponent());
        entity.addComponent(new ViewComponent());
        entity.addComponent(new MyComponent());
        return entity;
    }
    
  3. Place it in Tiled — set the object type to "myEntity" (matches the factory method name, sans create); add custom properties as needed.

  4. Define animations in resources.json if needed.

Key File Reference

Purpose

File Path

Engine core

core/src/net/dynart/lisa/core/Engine.java

Engine config (base)

core/src/net/dynart/lisa/core/EngineConfig.java

Entity factory (base)

core/src/net/dynart/lisa/core/EntityFactory.java

Entity / component

core/src/net/dynart/lisa/core/Entity.java, Component.java

Entity manager

core/src/net/dynart/lisa/core/EntityManager.java

Level loader

core/src/net/dynart/lisa/core/GameSceneLoader.java

Script loader

core/src/net/dynart/lisa/core/script/ScriptLoader.java

Game controller

core/src/net/dynart/lisa/core/controller/GameController.java

Version

Current Lisa Engine version: 0.1.0 (libGDX 1.14.0). Defined in the root build.gradle.