85 lines
3.9 KiB
Markdown
85 lines
3.9 KiB
Markdown
## Introduction
|
|
|
|
A Clojure library that provides a wrapper for [LibGDX](http://libgdx.badlogicgames.com/), allowing you to write 2D and 3D games that run on desktop OSes (Windows, OS X, and Linux) and mobile OSes (Android and iOS) with the same Clojure codebase.
|
|
|
|
## Getting Started
|
|
|
|
There are several different ways to create a project:
|
|
|
|
* [Leiningen](https://github.com/technomancy/leiningen): `lein new play-clj hello-world`
|
|
* [Nightcode](https://nightcode.info/): Click "New Project", provide a name, and choose the "Game" option
|
|
* [Nightmod](https://nightmod.net/): Easiest option for beginners
|
|
|
|
## Justification
|
|
|
|
The best thing about making a game in Clojure is that you can modify it in a REPL while it's running. By simply reloading a namespace, your code will be injected into the game, uninhibited by the restrictions posed by tools like HotSwap. Additionally, a REPL lets you read and modify the _state_ of your game at runtime, so you can quickly experiment and diagnose problems.
|
|
|
|
Clojure also brings the benefits of functional programming. This is becoming a big topic of discussion in gamedev circles, including by [John Carmack](http://www.altdevblogaday.com/2012/04/26/functional-programming-in-c/). Part of this is due to the prevalence of multi-core hardware, making concurrency more important. Additionally, there is a general difficulty of maintaining object-oriented game codebases as they grow, due to complicated class hierarchies and state mutations.
|
|
|
|
## Documentation
|
|
|
|
* Check out [the example games](https://github.com/oakes/play-clj-examples)
|
|
* Read [the tutorial](TUTORIAL.md)
|
|
* Read [the generated docs](http://oakes.github.io/play-clj)
|
|
* Join the discussion on [/r/playclj](http://www.reddit.com/r/playclj/)
|
|
* Look at this commented example:
|
|
|
|
```clojure
|
|
(ns game-test.core
|
|
(:require [play-clj.core :refer :all]
|
|
[play-clj.g2d :refer :all]))
|
|
|
|
; define a screen, where all the action takes place
|
|
(defscreen main-screen
|
|
; all the screen functions get a map called "screen" containing various
|
|
; important values, and a vector called "entities" for storing game objects
|
|
|
|
; the entities vector is immutable, so in order to update it you must simply
|
|
; return a new vector at the end of each screen function
|
|
|
|
; this function runs only once, when the screen is first shown
|
|
:on-show
|
|
(fn [screen entities]
|
|
; update the screen map to hold a tiled map renderer and a camera
|
|
(update! screen
|
|
:renderer (orthogonal-tiled-map "level1.tmx" (/ 1 8))
|
|
:camera (orthographic))
|
|
(let [; load a sprite sheet from your resources dir
|
|
sheet (texture "tiles.png")
|
|
; split the sheet into 16x16 tiles
|
|
; (the texture! macro lets you call TextureRegion methods directly)
|
|
tiles (texture! sheet :split 16 16)
|
|
; get the tile at row 6, col 0
|
|
player-image (texture (aget tiles 6 0))
|
|
; add position and size to the player-image map so it can be drawn
|
|
player-image (assoc player-image :x 0 :y 0 :width 2 :height 2)]
|
|
; return a new entities vector with player-image inside of it
|
|
[player-image]))
|
|
|
|
; this function runs every time a frame must be drawn (about 60 times per sec)
|
|
:on-render
|
|
(fn [screen entities]
|
|
; make the screen completely black
|
|
(clear!)
|
|
; render the tiled map, draw the entities and return them
|
|
(render! screen entities))
|
|
|
|
; this function runs when the screen dimensions change
|
|
:on-resize
|
|
(fn [screen entities]
|
|
; make the camera 20 tiles high, while maintaining the aspect ratio
|
|
(height! screen 20)
|
|
; you can return nil if you didn't change any entities
|
|
nil))
|
|
|
|
; define the game itself, and immediately hand off to the screen
|
|
(defgame game-test
|
|
:on-create
|
|
(fn [this]
|
|
(set-screen! this main-screen)))
|
|
```
|
|
|
|
## Licensing
|
|
|
|
All files that originate from this project are dedicated to the public domain. I would love pull requests, and will assume that they are also dedicated to the public domain.
|