System design and component overview
Render Engine is a 2D graphics library built on OpenGL and LWJGL. It provides a complete framework for games and interactive applications with a clean separation between logic updates (tick) and rendering.
Base class for all applications. Manages the game loop, window, and provides access to all subsystems.
onEnable() — initializationtick() — logic update (fixed rate, default 60/sec)onRender() — rendering (variable rate)onDisable() — cleanupKeyboard and mouse handling with three event types:
keyboard.onKeyPress(GLFW_KEY_SPACE) { jump() }
keyboard.onKeyPressed(GLFW_KEY_W) { moveForward() }
mouse.onMouseClick(GLFW_MOUSE_BUTTON_LEFT) { x, y -> shoot(x, y) }
mouse.onMouseScroll { offset -> zoom(offset) }
2D camera with target following, zoom, and coordinate transformation.
camera.initialize(player) // Follow player
camera.bounds = CameraBounds(0f, 0f, worldWidth, worldHeight)
camera.minZoom = 0.5f
camera.maxZoom = 3f
// In onRender:
val worldPos = camera.screenToScene(screenX, screenY)
Minecraft-style resource packs with priority ordering and fallback to JAR resources.
// Automatically checks resource packs first, then JAR
val path = ResourcePackManager.getResourcePath("textures/player.png")
// Manage packs
ResourcePackManager.enablePack("MyPack")
ResourcePackManager.movePackUp("MyPack")
Automatic texture atlas generation for draw call optimization.
textureRegistry.registerForAtlas("textures/player.png")
textureRegistry.registerForAtlas("textures/enemy.png")
textureRegistry.buildAtlas()
val tex = textureRegistry.getFromAtlas("textures/player.png")
TrueType/OpenType fonts with Unicode support.
fontRegistry.register("main", "fonts/Inter.ttf", 24)
fontRegistry.register("title", "fonts/Inter.ttf", 48)
fontRegistry.initialize()
val font = fontRegistry.get("main")
Low-level rendering with sprite, geometry, and text renderers.
renderEngine.spriteRenderer.renderSprite(x, y, w, h, texture)
renderEngine.geometryRenderer.renderRectangle(x, y, w, h, color)
renderEngine.textRenderer.renderText("Score: 100", x, y, font)
renderEngine.flush() // Send to GPU
// Cooldown timer
val attackCooldown = Cooldown(500) // 500ms
if (attackCooldown.isEnded()) {
attack()
attackCooldown.start()
}
// 2D Point
val pos = Point(100f, 200f)
// Colors
val color = Color.RED.rgba
The engine separates logic updates and rendering. Logic is updated at a fixed rate (tick), while rendering can happen more frequently. Interpolation is used for smooth transitions between states.
Main parameters:
For smooth animation, use the interpolation pattern:
val interpolated = lerp(statePrev, stateNext, partialTick)
In the Interpolatable class, store two states (current and previous) and use getInterpolatedState() for rendering.
onKeyPress, onKeyPressed, onKeyRelease and similar for mouse are called automaticallytick() and onRender() via subscriptionsclass MyEngine : RenderEngineCore(...) {
override fun setupRenderEngines() {
super.setupRenderEngines()
myRenderer = MyCustomRenderer()
myRenderer.register()
}
}
object MyResources : ResourceProvider {
override fun getResourcePath(path: String): String {
// Custom resolution logic
}
}
ResourceProvider.register(MyResources)