Core Concepts
This page walks through the 6 essential classes and systems that form the foundation of every FlixelGDX game. Each section includes practical code examples in both Java and Kotlin.
1. Flixel — the global manager system
Flixel is the static gateway to every major subsystem in the framework. Think of it as the equivalent
of FlxG in HaxeFlixel — one central place that holds references to the active state, cameras, input,
audio, assets, the debugger, and more.
Common access points:
| Field / method | What it gives you |
|---|---|
Flixel.sound | Audio manager (FlixelAudioManager) |
Flixel.assets | Asset manager (FlixelAssetManager) |
Flixel.debug | Debug manager (FlixelDebugManager) |
Flixel.watch | Watch panel manager (FlixelDebugWatchManager) |
Flixel.keys | Keyboard input |
Flixel.mouse | Mouse input |
Flixel.gamepads | Gamepad(s) input |
Flixel.switchState(state) | Transition to a new state |
Flixel.cameras | The live list of all active cameras |
Flixel.cameras.first() | The main (first) camera |
2. FlixelGame — the heart of every game
FlixelGame is the root and core part of your game. You extend it once, configure your window title, screen size,
and initial state, and the framework handles the rest: the game loop, input routing, camera management, the
debug overlay, and the lifecycle of your states.
- Java
- Kotlin
public class MyGame extends FlixelGame {
public MyGame() {
super(
"My Game", // Window title.
1280, 720, // World dimensions (virtual resolution).
new PlayState() // Initial state.
);
}
}
class MyGame : FlixelGame(
"My Game", // Window title.
1280, 720, // World dimensions (virtual resolution).
PlayState() // Initial state.
)
Then use a simple, dedicated platform launcher:
- Java
- Kotlin
public static void main(String[] args) {
FlixelLwjgl3Launcher.launch(new MyGame());
}
fun main() = FlixelLwjgl3Launcher.launch(MyGame())
The world dimensions define the virtual resolution your game logic works in. When your game launches, the world size
will match your window's starting size, too. In the example above, when the initial size is set to be 1280x720, your
game's window will start at 1280x720 pixels, and your game's world view will stay at that size regardless when your
window size changes.
3. FlixelState — organizing different parts of your game
FlixelState is the container for everything in a single "screen" of your game — a menu, a level, or a
cutscene. You add sprites, groups, and other objects to a state, and the framework calls update(float) and
draw(Batch) on all of them every frame. Override create() to build the screen and update(float) for
per-frame logic.
- Java
- Kotlin
public class PlayState extends FlixelState {
private FlixelSprite player;
@Override
public void create() {
super.create();
player = new FlixelSprite(100, 100);
player.loadGraphic("player.png"); // Assuming it's from the assets folder!
add(player);
}
@Override
public void update(float elapsed) {
super.update(elapsed);
// Game logic here!
}
}
class PlayState : FlixelState() {
private lateinit var player: FlixelSprite
override fun create() {
super.create()
player = FlixelSprite(100f, 100f).apply {
loadGraphic("player.png") // Assuming it's from the assets folder!
}
add(player)
}
override fun update(elapsed: Float) {
super.update(elapsed)
// Game logic here!
}
}
Switch between states with Flixel.switchState(new YourState()); (or Flixel.switchState(YourState()) for Kotlin).
The old state is destroyed automatically. FlixelSubState lets you overlay a temporary state (pause menu, inventory screen)
on top of the current one without destroying it.
4. FlixelSprite — visual objects in your game
FlixelSprite is the workhorse of any FlixelGDX game. It represents a visual object in the world
with position, size, texture, animation, velocity, and a hitbox. Most visible game objects extend
FlixelSprite or hold one as a field.
- Java
- Kotlin
FlixelSprite sprite = new FlixelSprite(x, y);
// Load a static image (this is assumed it's stored in the assets folder!).
sprite.loadGraphic("tile.png");
// Or make a solid-color rectangle (useful for prototyping).
sprite.makeGraphic(32, 32, FlixelColor.RED);
// Move with velocity on the X axis (pixels per second).
sprite.setVelocityX(200f);
// Scale, rotate, flip.
sprite.setScale(2f); // Scales the sprite twice as large both horizontally and vertically.
sprite.setAngle(45f);
sprite.flip(true, false); // Flip horizontally.
val sprite = FlixelSprite(x, y)
// Load a static image (this is assumed it's stored in the assets folder!).
sprite.loadGraphic("tile.png")
// Or make a solid-color rectangle (useful for prototyping).
sprite.makeGraphic(32, 32, FlixelColor.RED)
// Move with velocity on the X axis (pixels per second).
sprite.velocityX = 200f
// Scale, rotate, flip.
sprite.setScale(2f) // Scales the sprite twice as large both horizontally and vertically.
sprite.angle = 45f
sprite.flip(true, false) // Flip horizontally.
Sprite animation (frame-based clips, Sparrow atlases) lives in FlixelAnimationController, which is
allocated on demand via sprite.ensureAnimation() to keep memory usage low for large sprite counts.
5. FlixelText — text objects and custom fonts
FlixelText renders a string inside the game world as a sprite. It extends FlixelSprite, so it shares
the same positioning, scaling, and lifecycle, and you can add it to any state or group. The constructor
takes the position, a field width, and the text.
- Java
- Kotlin
FlixelText label = new FlixelText(10, 10, 200, "Hello, world!");
label.setTextSize(24);
label.setColor(FlixelColor.WHITE);
add(label);
// Update the text any time.
label.setText("Score: " + score);
val label = FlixelText(10f, 10f, 200f, "Hello, world!").apply {
textSize = 24
setColor(FlixelColor.WHITE)
}
add(label)
// Update the text any time.
label.text = "Score: $score"
In the JVM, there's a very subtle and sneaky thing that can add pressure to the garbage collector and ruin your
consistent framerate: string concatenation. When you use the example above, "Score: " + score / "Score: $score"
seem pretty harmless on the surface, but it secretly creates new String objects. When inside an update loop, this can be fatal for
a game's framerate.
You can avoid this problem using the framework's built-in utility FlixelString. Not only does it solve the per-frame
allocation problem, but it also doesn't create additional String objects when primitives (like the int score below)
are concatenated to a FlixelString!
Example usage:
- Java
- Kotlin
// 16 is the initial capacity (in characters) of the backing CharArray.
// Sizing it up front matters: if the text ever grows past the current capacity,
// the FlixelString has to allocate a bigger array and copy everything over. Pick a
// number a little larger than your longest expected string and that copy never happens.
FlixelString labelText = new FlixelString(16);
FlixelText label = new FlixelText(10, 10, 200);
// Reuse the same FlixelString every frame. set(...) replaces the contents (no need to
// clear() first), and each concat(...) appends without allocating a new String.
label.setText(labelText
.set("Score: ")
.concat(score));
// 16 is the initial capacity (in characters) of the backing CharArray.
// Sizing it up front matters: if the text ever grows past the current capacity,
// the FlixelString has to allocate a bigger array and copy everything over. Pick a
// number a little larger than your longest expected string and that copy never happens.
val labelText = FlixelString(16)
val label = FlixelText(10f, 10f, 200f)
// Reuse the same FlixelString every frame. set(...) replaces the contents (no need to
// clear() first), and each concat(...) appends without allocating a new String.
label.setText(labelText
.set("Score: ")
.concat(score))
Custom fonts
Load and register a TrueType or OpenType font file on FlixelFontRegistry, then apply it on a FlixelText object:
- Java
- Kotlin
final String MY_FONT = "my_font_id";
FlixelFontRegistry.register(MY_FONT, Gdx.files.internal("path/to/my/font.ttf")); // Assumes it's from the assets folder!
FlixelText label = new FlixelText(10, 10, 200);
label.setFont(MY_FONT); // Applies it from your ID!
label.setTextSize(16);
val MY_FONT = "my_font_id"
FlixelFontRegistry.register(MY_FONT, Gdx.files.internal("path/to/my/font.ttf")) // Assumes it's from the assets folder!
val label = FlixelText(10f, 10f, 200f).apply {
font = MY_FONT // Applies it from your ID!
textSize = 16
}
FlixelGDX uses libGDX's FreeType extension under the hood, so any .ttf or .otf file is supported.
The font is rasterized at the exact pixel size you request, which keeps text crisp at any resolution.
6. FlixelGroup / FlixelBasicGroup / FlixelSpriteGroup — organizing objects
Groups are containers that hold objects, making it easy to organize your game. A FlixelSpriteGroup (or your own
FlixelBasicGroup subclass) is itself a FlixelBasic, so you can add it straight to a state and pass it to
Flixel.collide(group, other) to check every member at once.
| Class | Holds | Notes |
|---|---|---|
FlixelGroup<T> | Any type T | A plain container for organizing objects. It is not part of the scene graph: it does not update, draw, or collide on its own. Its constructor needs an array factory (e.g. Actor[]::new) because Java cannot create generic arrays. |
FlixelBasicGroup<T> | Any IFlixelBasic | An abstract base. Extend it to build a custom group whose members are updated, drawn, and collided automatically. (FlixelState itself is a FlixelBasicGroup.) |
FlixelSpriteGroup | FlixelSprite (and subclasses) | The ready-to-use, concrete group most games reach for. Add it to a state, collide it, and it propagates position, scale, alpha, tint, and rotation to its members. |
- Java
- Kotlin
// FlixelGroup is a plain container. It needs an array factory because Java cannot
// allocate generic arrays, and it does not update, draw, or collide on its own.
FlixelGroup<Actor> actors = new FlixelGroup<>(Actor[]::new);
actors.add(new MyActorClass());
// FlixelSpriteGroup is the ready-to-use group: it updates, draws, and collides.
FlixelSpriteGroup enemies = new FlixelSpriteGroup();
for (int i = 0; i < 10; i++) {
EnemySprite e = new EnemySprite();
e.loadGraphic("enemy.png");
enemies.add(e);
}
add(enemies);
// Collide the player against every member in one call.
Flixel.collide(player, enemies);
// FlixelGroup is a plain container. It needs an array factory (the lambda) and does
// not update, draw, or collide on its own.
val actors = FlixelGroup<Actor>() { arrayOfNulls<Actor>(it) }
actors.add(MyActorClass())
// FlixelSpriteGroup is the ready-to-use group: it updates, draws, and collides.
val enemies = FlixelSpriteGroup()
repeat(10) {
val e = EnemySprite()
e.loadGraphic("enemy.png")
enemies.add(e)
}
add(enemies)
// Collide the player against every member in one call.
Flixel.collide(player, enemies)
FlixelSpriteGroup and advanced rotation
FlixelSpriteGroup propagates its own position, scale, alpha, color tint, and rotation to all member
sprites. Its RotationMode enum (nested in FlixelSpriteGroup) supports three modes:
INDIVIDUAL(default) — the rotation delta is applied to each sprite's own rotation; positions are unchanged.ORBIT— sprites orbit the group origin as a rigid body; both position and sprite rotation update.WHEEL— sprites are arranged radially at a fixed radius from the group origin; useful for circular formations.
- Java
- Kotlin
FlixelSpriteGroup formation = new FlixelSpriteGroup();
formation.setX(400);
formation.setY(300);
formation.changeAngle(90f);
formation.setRotationMode(FlixelSpriteGroup.RotationMode.ORBIT); // Rotate all sprites around the group's origin. (400, 300).
val formation = FlixelSpriteGroup().apply {
x = 400f
y = 300f
angle += 90f
rotationMode = FlixelSpriteGroup.RotationMode.ORBIT // Rotate all sprites around the group's origin. (400, 300).
}