HyperLap2D Wiki logo HyperLap2D Wiki

The Runtime needs to be included in your core project.

dependencies {
    //HyperLap2D Runtime
    api "games.rednblack.hyperlap2d:runtime-libgdx:$h2dVersion"

    //Mandatory
    api "com.badlogicgames.gdx:gdx:$gdxVersion"
    api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
    api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
    api "net.onedaybeard.artemis:artemis-odb:$artemisVersion"
}

Use the compatibility table to choose the right version for each dependency.

Box2D and FreeType extensions need additional configuration for platform specific modules

Architecture

HyperLap2D’s libGDX runtime is based on the Entity Component System (ECS) architecture using the Artemis-odb library. If you are not familiar with this kind of design pattern, please consider learning more before reading further.

SceneLoader

A SceneLoader is the object that helps you set up the minimal working configuration for HyperLap2D. It parses the JSON format to build the ECS Engine, Entities, and all required Components to render your scenes and assets.

//Create a viewport
mViewport = new ExtendViewport(360, 640, 0, 0, mCamera);

//Create a configuration to setup SceneLoader object
SceneConfiguration configuration = new SceneConfiguration();
//Add User defined systems
configuration.addSystem( ... );
//Tells Runtime to automatically attach a component to entites loaded with a specific TAG.
configuration.addTagTransmuter( ... );

//Initialize HyperLap2D's SceneLoader, all assets will be loaded here
mSceneLoader = new SceneLoader(configuration);
//Load the desired scene with custom viewport
mSceneLoader.loadScene("MainScene", mViewport);

If not specified, by default the SceneLoader creates a ScreenViewport. In many cases this is not what you want, especially if you target a Pixel per World Unit other than 1. You can measure the size of your world using guidelines in order to choose the best Viewport for your scene.

SceneConfiguration

The SceneConfiguration class is the configuration object used to initialize the SceneLoader. It allows you to customize the rendering pipeline (Batch size, Stencil, MSAA), inject external physics worlds, and manage the ECS systems before the engine starts.

Rendering & FrameBuffer Settings

You can customize the Batch used by the engine, enable the Stencil buffer, or configure Multi-Sample Anti-Aliasing (MSAA).

Note: Using MSAA (samples > 0) usually requires a GLES 3.0+ context.

// 1. Default setup (Batch size: 2000, No Stencil, No MSAA)
SceneConfiguration config = new SceneConfiguration();

// 2. Custom Batch size
// Useful to reduce draw calls in scenes with many sprites
SceneConfiguration config = new SceneConfiguration(4000);

// 3. Advanced Setup: Custom Batch, Stencil enabled, and 4x MSAA samples
SceneConfiguration config = new SceneConfiguration(new TextureArrayCpuPolygonSpriteBatch(), true, 4);
Systems Management

By default, SceneConfiguration adds all the standard HyperLap2D systems. You can inject your own Artemis-odb systems or replace existing ones.

// Add a custom logic system
config.addSystem(new PlayerControllerSystem());

// Disable or Replace a built-in system
// If you add a system of the same class as a built-in one, it replaces the original.
config.removeSystem(LightSystem.class);
Physics & Lighting Injection

If your game architecture manages the Box2D World or Box2DLights RayHandler externally (outside of the SceneLoader), you must inject them here. If not set, SceneLoader will create new instances automatically.

config.setWorld(myGameWorld);
config.setRayHandler(myRayHandler);
Tag Transmuters

Tag Transmuters allow you to automatically attach specific Components to entities based on the Tag assigned in the Editor. This is useful for binding game logic to entities without manual parsing.

// Automatically adds 'EnemyComponent' to any entity tagged "enemy_walker"
config.addTagTransmuter("enemy_walker", EnemyComponent.class);
Other Configuration Methods

Loading with AssetManager

libGDX’s AssetManager can be used to load a HyperLap2D project.

mAssetManager = new AssetManager();
mAssetManager.setLoader(AsyncResourceManager.class, new ResourceManagerLoader(mAssetManager.getFileHandleResolver()));
mAssetManager.load("project.dt", AsyncResourceManager.class);


mAssetManager.finishLoading();
//or
mAssetManager.update();

//When AssetManager finish loading
AsyncResourceManager mAsyncResourceManager = mAssetManager.get("project.dt", AsyncResourceManager.class);

SceneConfiguration configuration = new SceneConfiguration();
config.setResourceRetriever(mAsyncResourceManager);

...

mSceneLoader = new SceneLoader(config);

Rendering scene

The Runtime Engine already has all necessary Systems for rendering and basic entity manipulation. SceneLoader is a wrapper for all these features. This will make rendering very easy; just update the ECS Engine.

@Override
public void render() {
    //Clear screen
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    //Apply ViewPort and update SceneLoader's ECS engine
    mViewport.apply();
    mSceneLoader.getEngine().process();
}

Retrieve Entities and navigate through composites

Entities are represented as integers; any definition is provided by their Components. To help navigation and manipulation of elements, the ItemWrapper class can be used, which exposes some useful methods. By default, all objects are placed in a single root Composite.

ItemWrapper root = new ItemWrapper(mSceneLoader.getRoot(), mSceneLoader.getEngine());

Composites are groups of entities. They can be retrieved with the ItemWrapper#getChild method using the object’s unique identifier.

ItemWrapper foo = root.getChild("foo");

Default Components

There are several default components created for each Entity.

Specific components are created based on the entity’s type, for example TextureRegionComponent, LabelComponent, ActionComponent ,LightObjectComponent, ParticleComponent, SpriteAnimationComponent, PhysicsBodyComponent and much more. Full list

Actions System

HyperLap2D uses an Actions System similar to libGDX’s Scene2D actions but for the ECS pattern. You can manually create actions in Java, or use the Node Graph Editor.

ActionData rotation = Actions.sequence(
            Actions.delay(2),
            Actions.parallel(
                    Actions.moveBy(-30, -30, 5, Interpolation.pow2),
                    Actions.rotateBy(180, 2, Interpolation.exp5))
    );
ActionData repeatData = Actions.forever(rotation);

Actions.addAction(entity, repeatData, mSceneLoader.getEngine());

Load Actions from library

//Simple Actions can be loaded and attached
ActionData actionData = mSceneLoader.loadActionFromLibrary("testAction");
Actions.addAction(entity, actionData, mSceneLoader.getEngine());

//Complex actions can be loaded with params and event listener
ObjectMap<String, Object> params = new ObjectMap<>();
params.put("delay", 2f);

ActionData actionData = mSceneLoader.getActionFactory().loadFromLibrary("test", params, new ActionEventListener() {
    @Override
    public void onActionEvent(String s) {
        System.out.println("Triggered event: " + s);
    }
});

Actions.addAction(entity, actionData, mSceneLoader.getEngine());

Create entities at runtime with EntityFactory

EntityFactory helps you create objects ready to be used with this runtime. Before creating the real entity, you have to describe it using a VO class. Common VOs are: SimpleImageVO, Image9patchVO, LabelVO, CompositeItemVO, ParticleEffectVO, LightVO, SpriteAnimationVO, ColorPrimitiveVO, TalosVO, SpineVO. Full list

LabelVO labelVO = new LabelVO();
labelVO.itemIdentifier = "unique_id_name";
labelVO.text = "This is a runtime label";
labelVO.style = "Lato";
labelVO.size = 26;
labelVO.layerName = "Default";
labelVO.x = 10;
labelVO.y = 10;
labelVO.width = 100;
labelVO.height = 100;

int label = mSceneLoader.getEntityFactory().createEntity(root.getEntity(), labelVO);

Load Composite Item from HyperLap2D’s Library

int newEntity = mSceneLoader.loadFromLibrary("libraryName", "LayerName/Default", x, y);

Or if a more fine control on Composite creation is needed:

CompositeItemVO sheepData = mSceneLoader.loadVoFromLibrary("sheep");
sheepData.layerName = "Default";
sheepData.x = 100;
sheepData.y = 100;

int sheep = mSceneLoader.getEntityFactory().createEntity(root.getEntity(), sheepData);
mSceneLoader.getEntityFactory().initAllChildren(sheep, sheepData);

Attaching Scripts to Entities

Scripts are very helpful to handle events both from users and from other internal objects. As like any other Artemis object, scripts are automatically injected when created.

public class PlayerScript extends BasicScript {
    
    //Artemis and HyperLap2D objects will be injected with reflection
    //No needs to initialize them
    protected ComponentMapper<MainItemComponent> mainMapper;
    protected SceneLoader sceneLoader;

    @Override
    public void init(int item) {
        super.init(item);

        //Init scripts code here
        //`item` is the entity where the scripts is attached to.
    }

    @Override
    public void act(float delta) {
        //Called every frame
    }

    @Override
    public void dispose() {
        //Called when the script is removed from the entity
    }
}

And a script can be easily attached to any entity with:

ItemWrapper player = root.getChild("player");
PlayerScript playerScript = player.addScript(PlayerScript.class);

Scripts can intercept physics collision events if the entity is a physic object.

public class PhysicsTestScript extends PhysicsBodyScript {
    //No needs to init these fields because scripts are injected using artemis 
    protected ComponentMapper<PhysicsBodyComponent> physicMapper;
    protected com.artemis.World engine;

    //This has to be initialized!
    private PhysicsBodyComponent physicsBodyComponent;

    @Override
    public void init (int item) {
        super.init(item);

        //PhysicsBodyComponent#body is not null in `init` ONLY 
        //for PhysicsBodyScript which wait box2d before initialization
        physicsBodyComponent = physicMapper.get(item);
    }

    @Override
    public void act (float delta) {
        //act method is called each frame
        Body body = physicsBodyComponent.body;
    }

    @Override
    public void beginContact (int contactEntity, Fixture contactFixture, Fixture ownFixture, Contact contact) {

    }

    @Override
    public void endContact (int contactEntity, Fixture contactFixture, Fixture ownFixture, Contact contact) {

    }

    @Override
    public void preSolve (int contactEntity, Fixture contactFixture, Fixture ownFixture, Contact contact) {

    }

    @Override
    public void postSolve (int contactEntity, Fixture contactFixture, Fixture ownFixture, Contact contact) {

    }

    @Override
    public void dispose () {

    }
}

Systems

HyperLap2D logic is driven by the Artemis-odb Entity Component System. Systems are where the logic lives; they iterate over entities or perform global actions. You will primarily use IteratingSystem (for processing entities) and BaseSystem (for global logic).

Subscribing to Entities

To define which entities a System should process, you use Aspect Annotations above the class definition. This creates an “Aspect” that filters entities based on their components.

// Anotations can be combined.
// The entity MUST have ComponentA AND ComponentB
@All(ComponentA.class, ComponentB.class)
// The entity MUST have EITHER ComponentC OR ComponentD
@One(ComponentC.class, ComponentD.class)
// The entity MUST NOT have ComponentE
@Exclude(ComponentE.class)
public class MyGameSystem extends IteratingSystem {
    @Override
    protected void process(int entityId) {
        // Logic applied to matching entities
    }
}

Dependency Injection

Artemis-odb automatically handles dependency injection for your Systems during initialization. By declaring fields for ComponentMappers, other Systems, or registered managers, the engine will populate them for you.

@Wire(injectInherited = true) // Optional: allows injection into fields defined in superclasses
public class MovementSystem extends IteratingSystem {
    
    // Automatically injected Mappers to retrieve components efficiently
    protected ComponentMapper<TransformComponent> transformMapper;
    
    // Injects reference to another system
    protected AnimationSystem animationSystem;

    @Override
    protected void process(int entityId) {
         TransformComponent transform = transformMapper.get(entityId);
         // Logic using mappers...
    }
}

Fixed Timestep and Interpolation

For systems that require deterministic updates (like Physics or strict gameplay timers), you can use the @FixedTimestep annotation. However, to prevent visual stuttering when the rendering frame rate differs from the logic update rate, you should implement InterpolatingSystem.

// Configures the system to run logic at a fixed time step
@FixedTimestep
public class CameraSystem extends IteratingSystem implements InterpolatingSystem {

    @Override
    protected void process(int entityId) {
        // This code runs strictly at the fixed step rate
        // Ideal for physics simulation, systems that depends from physics, or deterministic logic
    }

    @Override
    public void interpolate(float alpha) {
        // This method is called every frame (variable timestep)
        // 'alpha' (0.0 to 1.0) represents the time accumulation between fixed steps.
        
        // Use this to smooth out visual positions:
        // visualPosition = previousPosition + (currentPosition - previousPosition) * alpha;
    }
}

The fixed time step can be configured via HyperLap2dInvocationStrategy.setFixedTimeStep(targetFps). This method should be invoked only once at startup and remain constant throughout execution. The fixed timestep will be set to 1/targetFps.

Engine Time Scaling

HyperLap2D provides built-in support for time scaling to create slow-motion or fast-forward effects. Scaling time acts globally and affects all systems, including physics simulation.

To change the engine’s time scale, use HyperLap2dInvocationStrategy#setTimeScale.

Examples:

Resource Management

Each asset (image, font, etc.) needs to be loaded and unloaded according to game needs. This can be done using IResourceRetriever interface and pass it to SceneConfiguration.

Methods in IResourceRetriever are invoked whenever EntityFactory needs an asset. You are free to implement this part according to needs of your game. You can use the default ResourceManager.