Skip to main content

Videos

FlixelGDX includes a first-party video extension that lets you play video files directly inside your game. It works on desktop (via libvlc), Android (via the platform MediaPlayer), and web (via the browser's built-in decoder). The video object behaves like any other FlixelBasic: you add it to a state, it updates and draws itself, and you call destroy() when you are done.


Installation

The extension is split into a platform-agnostic core and one backend per platform. Add the core to your core subproject so the shared API is available to all your game code, then add the matching backend to each platform subproject.

core/build.gradle

dependencies {
api "org.flixelgdx:flixelgdx-core:${flixelVersion}"
api "org.flixelgdx:flixelgdx-video-core:${flixelVersion}" // add this
}

lwjgl3/build.gradle (desktop)

dependencies {
implementation project(":core")
implementation "org.flixelgdx:flixelgdx-lwjgl3:${flixelVersion}"
implementation "org.flixelgdx:flixelgdx-video-lwjgl3:${flixelVersion}" // add this
}

For the other platforms the pattern is the same: add flixelgdx-video-android to your Android subproject and flixelgdx-video-teavm to your web (TeaVM) subproject.

JitPack users

If you are pulling FlixelGDX from JitPack instead of Maven Central, replace org.flixelgdx with com.github.flixelgdx.flixelgdx in the dependency coordinates above.


Registering the backend

Each platform backend must be installed once in its launcher, before the game starts. The install call is a no-op if called more than once, so it is safe to leave it unconditionally.

Desktop (lwjgl3)

public static void main(String[] args) {
FlixelVlcVideoHandler.install(); // register the desktop video backend
FlixelLwjgl3Launcher.launch(new MyGame());
}

Android

public class MyAndroidLauncher extends AndroidApplication {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FlixelAndroidVideoHandler.install(); // register the Android video backend
FlixelAndroidLauncher.launch(new MyGame(), this);
}
}

Web (TeaVM)

public static void main(String[] args) {
FlixelTeaVMVideoHandler.install(); // register the web video backend
FlixelTeaVMLauncher.launch(new MyGame());
}

Creating and playing a video

Create a video through FlixelVideos.create(), configure it, add it to the state, then call play(). The video starts decoding immediately and the first frame appears within a few milliseconds.

@Override
public void create() {
FlixelVideo cutscene = FlixelVideos.create("videos/intro.mp4");
cutscene.setSize(Flixel.getWidth(), Flixel.getHeight());
cutscene.setLooped(false);
cutscene.onComplete.add(() -> Flixel.switchState(new MenuState()));
add(cutscene);
cutscene.play();
}

The path is relative to your assets/ folder. The extension supports any container and codec that the underlying platform decoder handles (MP4 and WebM are the safest cross-platform choices).


Playback controls

FlixelVideo has four basic transport methods, all of which return this for chaining.

video.play(); // start from the beginning (default)
video.play(false); // resume without restarting if already playing
video.play(true, 5000f); // restart and begin at 5 000 ms

video.pause(); // freeze at the current position
video.resume(); // continue from where it was paused
video.stop(); // stop and reset to the beginning

boolean playing = video.isPlaying();
boolean ready = video.isReady(); // true once the first frame is decoded
isReady()

width, height, getLength(), getVideoWidth(), and getVideoHeight() all return 0 until isReady() returns true. If you need the native dimensions at the start of your state, check isReady() in update() before reading them.


Position and size

Set x and y directly, or use setPosition(). Set the draw size with setSize(). If width or height is left at 0, the decoded frame dimensions are used instead.

// Place the video at (100, 50) and draw it at 640x360.
video.setPosition(100f, 50f);
video.setSize(640f, 360f);

// Stretch to fill the entire screen.
video.setSize(Flixel.game.getWidth(), Flixel.game.getHeight());

// Use the decoded frame dimensions (the default).
video.setSize(0f, 0f);

Volume

Volume ranges from 0 (silent) to 1 (full). Values outside the range are clamped by the backend.

video.setVolume(0.5f); // 50% volume
video.setVolume(0f); // muted
float vol = video.getVolume();

Playback rate

The rate multiplier controls playback speed. 1 is normal, 2 is double speed, 0.5 is half speed. All values must be greater than 0.

video.setRate(2f); // double speed
video.setRate(0.5f); // half speed
video.setRate(1f); // normal speed

float rate = video.getRate();

Looping and seeking

setLooped(true) makes the video restart automatically when it ends. Seeking with setTime() works on both playing and paused videos.

// Loop a background video indefinitely.
video.setLooped(true);

// Seek to 3 seconds in.
video.setTime(3000f);

// Read the current position and total duration (both in milliseconds).
float position = video.getTime();
float duration = video.getLength();

// Jump to 80% through the video.
video.setTime(video.getLength() * 0.8f);

Decode quality

FlixelVideoQuality trades visual sharpness for CPU and memory cost. The draw size on screen never changes; only the resolution the decoder produces internally does.

PresetDecode resolutionBest for
FULLSource resolution (default)Cutscenes, HD content
HALF1/2 width and height (1/4 pixels)Background loops, low-end devices
QUARTER1/4 width and height (1/16 pixels)Heavily stylized or very blurry content
// Use half-resolution decode for a looping background.
video.setQuality(FlixelVideoQuality.HALF);

FlixelVideoQuality q = video.getQuality();
Desktop quality changes

On desktop the decoder pipeline is rebuilt when the quality changes. If the video is already playing, the backend automatically restarts it and seeks back to where it was. On web the change applies immediately without interrupting playback.


Scroll factor

The scroll factor controls how much a video moves when the camera scrolls, using the same contract as sprites. 1 (the default) means the video moves with the world; 0 pins it to the screen regardless of camera position, which is the right choice for fullscreen cutscenes.

// Pin to the screen (cutscene or UI layer).
video.setScrollFactor(0f, 0f);

// Parallax: move at half the camera speed (background layer).
video.setScrollFactor(0.5f, 0.5f);

// Default: follows the world like a normal sprite.
video.setScrollFactor(1f, 1f);

float sx = video.getScrollX();
float sy = video.getScrollY();

Lifecycle signals

FlixelVideo exposes four signals you can listen to for playback events.

SignalFires when
onPlayplay() is called
onPausepause() is called
onResumeresume() is called
onCompleteA non-looping video reaches its end
// Switch to the menu after the intro cutscene finishes.
video.onComplete.add(() -> Flixel.switchState(new MenuState()));

// Log when the video is paused (e.g. for debugging).
video.onPause.add(() -> Flixel.info("CutsceneState", "Video paused."));

// Use addOnce() to fire a listener only one time.
video.onPlay.addOnce(() -> showSkipHint());

Auto-destroy

Set autoDestroy = true to have the video clean itself up automatically when playback completes. This is the right choice for one-shot cutscenes where you do not need to reuse the object:

FlixelVideo intro = FlixelVideos.create("videos/intro.mp4");
intro.setAutoDestroy(true);
intro.onComplete.add(() -> Flixel.switchState(new MenuState()));
add(intro);
intro.play();
// No need to call destroy() manually; it is called when playback ends.

Using the raw texture

getTexture() returns the Texture holding the most recently decoded frame. Use this when you want to feed the video into your own drawing code — a custom shader, a sprite's texture region, or a 3D mesh — instead of relying on the default draw:

Texture frame = video.getTexture();
if (frame != null) {
// Draw using your own batch call or shader.
batch.draw(frame, 0, 0);
}
Do not dispose the texture

The backend owns the frame texture and replaces it every frame. Do not call dispose() on it yourself, or you will corrupt the decoder pipeline.


Auto-pause on focus loss

When FlixelGame.autoPause is true (the default), videos pause automatically when the OS suspends or backgrounds the application and resume when it comes back to the foreground. On desktop the focus hooks are wired up by FlixelVlcVideoHandler.install(). No extra setup is needed.