Using libgdx with Clojure

Clojure is a dialect of Lisp, written for the JVM and with functional programming in mind. Clojure comes with native Java interoperability, making it able to leverage the powerful existing libraries in the Java ecosystem. ClojureTV on YouTube has a lot of good videos, specifically Clojure for Java Programmers (Part 2).

project setup

Your project’s directory structure should look something like

- android
- desktop
  - resources
  - src
    - demo
      - core
        - desktop_launcher.clj
  - src-common
    - demo
      - core.clj
  - project.clj


(defproject demo "0.0.1-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[com.badlogicgames.gdx/gdx "1.9.3"]
                 [com.badlogicgames.gdx/gdx-backend-lwjgl "1.9.3"]
                 [com.badlogicgames.gdx/gdx-box2d "1.9.3"]
                 [com.badlogicgames.gdx/gdx-box2d-platform "1.9.3"
                  :classifier "natives-desktop"]
                 [com.badlogicgames.gdx/gdx-bullet "1.9.3"]
                 [com.badlogicgames.gdx/gdx-bullet-platform "1.9.3"
                  :classifier "natives-desktop"]
                 [com.badlogicgames.gdx/gdx-platform "1.9.3"
                  :classifier "natives-desktop"]
                 [org.clojure/clojure "1.7.0"]]
  :source-paths ["src" "src-common"]
  :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
  :aot [demo.core.desktop-launcher]
  :main demo.core.desktop-launcher)


(ns demo.core.desktop-launcher
  (:require [demo.core :refer :all])
  (:import [com.badlogic.gdx.backends.lwjgl LwjglApplication]
           [org.lwjgl.input Keyboard])

(defn -main []
  (LwjglApplication. (demo.core.Game.) "demo" 800 600)
  (Keyboard/enableRepeatEvents true))


(ns demo.core
  (:import [com.badlogic.gdx Game Gdx Graphics Screen]
           [ Color GL20]
           [ BitmapFont]
           [com.badlogic.gdx.scenes.scene2d Stage]
           [com.badlogic.gdx.scenes.scene2d.ui Label Label$LabelStyle]))

  :name demo.core.Game
  :extends com.badlogic.gdx.Game)

(def main-screen
  (let [stage (atom nil)]
    (proxy [Screen] []
      (show []
        (reset! stage (Stage.))
        (let [style (Label$LabelStyle. (BitmapFont.) (Color. 1 1 1 1))
              label (Label. "Hello world!" style)]
          (.addActor @stage label)))
      (render [delta]
        (.glClearColor (Gdx/gl) 0 0 0 0)
        (.glClear (Gdx/gl) GL20/GL_COLOR_BUFFER_BIT)
        (doto @stage
          (.act delta)
      (hide [])
      (pause [])
      (resize [w h])
      (resume []))))

(defn -create [^Game this]
  (.setScreen this main-screen))

you can launch the window with lein run in the project.clj directory, or the repl of your choice by calling (demo.core.desktop-launcher/-main).

For repl based dev have your main-screen call fns for each lifecycle method you wish to re-evaluate.


The play-clj library provides a Clojure wrapper for libGDX. To get started, install Leiningen and run the following command:

lein new play-clj hello-world

A directory called hello-world should appear, and inside you’ll find directories for android and desktop. Inside the desktop directory, you’ll find a src-common directory, which contains the game code that both projects will read from. Navigate inside of it to find core.clj, which looks like this:

(ns hello-world.core
  (:require [play-clj.core :refer :all]
            [play-clj.ui :refer :all]))

(defscreen main-screen
  (fn [screen entities]
    (update! screen :renderer (stage))
    (label "Hello world!" (color :white)))

  (fn [screen entities]
    (render! screen entities)))

(defgame hello-world
  (fn [this]
    (set-screen! this main-screen)))

This will display a label on the bottom left corner, which you can see by running lein run inside the desktop directory. To generate a JAR file that you can distribute to other people, run lein uberjar and grab the file in the target directory that contains the word “standalone”.

  • The play-clj tutorial provides a more in-depth walk-through on how to use the library.
  • The Nightmod game tool provides an easier way to use play-clj by integrating the game and the text editor together so you can see instant results when you save your code.