Add Render Engine to your project
package com.example.game
import org.lwjgl.glfw.GLFW.*
import ua.terra.renderengine.RenderEngineCore
class Game : RenderEngineCore(
windowName = "My Game",
windowX = -1, // -1 = centered
windowY = -1,
windowWidth = 1280,
windowHeight = 720,
tickRate = 60
) {
override fun onEnable() {
// Load resources, setup input
keyboard.onKeyPress(GLFW_KEY_ESCAPE) { window.close() }
}
override fun tick() {
// Game logic (60 times/sec)
}
override fun onRender() {
// Rendering
renderEngine.flush()
}
}
package com.example.game
import org.lwjgl.glfw.GLFW.glfwInit
fun main() {
check(glfwInit()) { "Failed to initialize GLFW" }
Game().enable()
}
src/main/resources/
├── textures/
│ ├── player.png
│ └── tiles/
│ └── grass.png
├── fonts/
│ └── main.ttf
└── shaders/
├── custom.vert
└── custom.frag
// Single press (fires once)
keyboard.onKeyPress(GLFW_KEY_SPACE) {
player.jump()
}
// Held down (fires every frame)
keyboard.onKeyPressed(GLFW_KEY_W) {
player.moveForward()
}
// Released
keyboard.onKeyRelease(GLFW_KEY_SPACE) {
player.endJump()
}
// Text input
keyboard.onCharInput { char ->
textField.append(char)
}
// Check state directly
if (keyboard.isKeyPressed(GLFW_KEY_LEFT_SHIFT)) {
player.run()
}
// Click (fires once)
mouse.onMouseClick(GLFW_MOUSE_BUTTON_LEFT) { x, y ->
shoot(x, y)
}
// Held (fires every frame)
mouse.onMousePressed(GLFW_MOUSE_BUTTON_RIGHT) { x, y, lastX, lastY ->
camera.pan(lastX - x, lastY - y)
}
// Scroll
mouse.onMouseScroll { offset ->
if (offset > 0) camera.zoomIn()
else camera.zoomOut()
}
// Movement
mouse.onMouseMove { x, y, lastX, lastY ->
cursor.moveTo(x, y)
}
// Current position
val mx = mouse.x
val my = mouse.y
// Make player followable
class Player : CameraTarget {
var x = 0f
var y = 0f
override fun getCameraPoint() = Point(x, y)
}
// Setup
val player = Player()
camera.initialize(player)
camera.bounds = CameraBounds(0f, 0f, worldWidth, worldHeight)
camera.minZoom = 0.5f
camera.maxZoom = 4f
// In tick()
override fun tick() {
camera.tick()
player.update()
}
// In onRender()
override fun onRender() {
// Convert screen to world coordinates
val worldX = camera.screenToSceneX(mouse.x)
val worldY = camera.screenToSceneY(mouse.y)
// Camera offset for rendering
val offset = camera.getOffset()
renderEngine.flush()
}
// In onEnable()
override fun onEnable() {
// Register textures for atlas
listOf(
"textures/player.png",
"textures/enemy.png",
"textures/tiles/grass.png"
).forEach { path ->
val fullPath = ResourcePackManager.getResourcePath(path)
textureRegistry.registerForAtlas(fullPath)
}
// Build atlas (combines into one texture)
textureRegistry.buildAtlas()
}
// In onRender()
override fun onRender() {
val tex = textureRegistry.getFromAtlas("textures/player.png")
renderEngine.spriteRenderer.renderSprite(
x = player.x,
y = player.y,
width = 64f,
height = 64f,
texture = tex
)
renderEngine.flush()
}
// In onEnable()
override fun onEnable() {
fontRegistry.register("ui", "fonts/Inter.ttf", 18)
fontRegistry.register("title", "fonts/Inter.ttf", 36)
fontRegistry.initialize()
}
// In onRender()
override fun onRender() {
val uiFont = fontRegistry.get("ui")
val titleFont = fontRegistry.get("title")
renderEngine.textRenderer.renderText(
text = "My Game",
x = 50f,
y = 50f,
font = titleFont,
color = 0xFFFFFFFF.toInt()
)
renderEngine.textRenderer.renderText(
text = "Score: ${score}",
x = 50f,
y = 100f,
font = uiFont
)
renderEngine.flush()
}
game_folder/
├── resourcepacks/
│ ├── MyPack/
│ │ ├── pack.json
│ │ └── textures/
│ │ └── player.png
│ └── AnotherPack/
│ └── ...
└── resourcepacks.json
{
"name": "My Resource Pack",
"version": "1.0",
"description": "Custom textures"
}
// Get resource (checks packs first, then JAR)
val path = ResourcePackManager.getResourcePath("textures/player.png")
// Pack management
ResourcePackManager.enablePack("MyPack")
ResourcePackManager.disablePack("MyPack")
ResourcePackManager.movePackUp("MyPack")
ResourcePackManager.movePackDown("MyPack")
// Get lists
val available = ResourcePackManager.getAvailablePacks()
val active = ResourcePackManager.getActivePacks()
// Rescan for new packs
ResourcePackManager.rescan()