Warning
Use the template at https://github.com/pfeodrippe/vybe-games as your start point, try to run the commands in that README. If you try to use the vybe
github project directly, you would have to build everything from scratch, but the deps used in vybe-games
use the clojars version, which contains all the dynamic libs you need. Have fun \o/
Getting Started
This is the minimal amount of code to have physics (with Jolt) + ECS (with Flecs) + rendering (with Raylib) using Vybe. We will talk about each of the parts later, check the code in full below.
(ns vybe.example.minimal
"Example with minimal setup, it will load a builtin GLTF (.glb) model with
which contains a cube."
(:require
[vybe.flecs :as vf]
[vybe.game :as vg]
[vybe.raylib.c :as vr.c]
[vybe.raylib :as vr]
[vybe.type :as vt]))
(defn draw
[w delta-time]
;; For debugging
#_(def w w)
;; Progress the systems (using Flecs).
(vf/progress w delta-time)
;; Update physics (using Jolt).
(vg/physics-update! w delta-time)
;; Add some lights (from the blender model).
(vg/draw-lights w)
;; Render stuff into the screen (using Raylib) using a built-in effect.
(vg/with-drawing-fx w (vg/fx-painting w)
(vr.c/clear-background (vr/Color [255 20 100 255]))
;; Here we do a query for the active camera (it's setup when loading the model).
(vf/with-query w [_ :vg/camera-active
camera vt/Camera]
(vg/with-camera camera
(vg/draw-scene w)))
(vr.c/draw-fps 510 570)))
(defn init
[]
(let [w (vf/make-world)]
;; If you want to enable debugging (debug messages + clerk + flecs explorer),
;; uncomment line below.
#_(vg/debug-init! w)
(vg/start! w 600 600 #'draw
(fn [w]
(-> w
;; Load model (as a resource).
;; We are going to load a bultin model, but you can use any .glb
;; resource you have.
(vg/model :my/model (vg/resource "com/pfeodrippe/vybe/model/minimal.glb")))))))
#_ (init)
(defn -main
"This is used for testing, don't bother."
[& _args]
;; We start `init` in a future so it's out of the main thread,
;; `vr/-main` will be in the main thread and it will loop the game draw
;; function for us.
(future (init))
;; Exit app after some time (for testing).
(future
(try
(Thread/sleep 5000)
(System/exit 0)
(catch Exception e
(println e))))
;; Start main thread.
(vr/-main))
draw
The draw
function receives a world (more on it later)
and a delta time (time since the last iteration). You won't call
this function directly, the Vybe runtime will be calling it for you.
;; Progress the systems (using Flecs).
(vf/progress w delta-time)
;; Update physics (using Jolt).
(vg/physics-update! w delta-time)
We are calling vf/progress
, which will advance
the Flecs (https://www.flecs.dev/flecs/) ECS system (w
is a Flecs
world), Flecs is a well-written C engine and the core of the Vybe
framework. vg/physics-update!
handles the physics using Jolt
(https://jrouwe.github.io/JoltPhysics/), a C++ physics engine (we
use a C wrapper to interact with it).
;; Add some lights (from the blender model).
(vg/draw-lights w)
;; Render stuff into the screen (using Raylib) using a built-in effect.
(vg/with-drawing-fx w (vg/fx-painting w)
(vr.c/clear-background (vr/Color [255 20 100 255]))
;; Here we do a query for the active camera (it's setup when loading the model).
(vf/with-query w [_ :vg/camera-active
camera vt/Camera]
(vg/with-camera camera
(vg/draw-scene w)))
(vr.c/draw-fps 510 570)))
Backed by Raylib (https://www.raylib.com/, we are able to draw some
simple lightning (using a custom shader, see the implementation),
apply some effects to the screen (vg/with-drawing-fx
will render the
result to a render texture and draw it into the screen,
vg/with-drawing
is the version of it that doesn't apply any
effect).
The namespaces with a 3rd party lib + .c
(e.g. vybe.raylib.c
,
vybe.flecs.c
, vybe.jolt.c
) are clj wrappers for the respective libs,
e.g. vr.c/clear-background
will call raylib's ClearBackground
(cheatsheet for raylib at
https://www.raylib.com/cheatsheet/cheatsheet.html). We use jextract
(https://github.com/openjdk/jextract) for these native libs and then
read the generated Java classes, it's a fantastic tool made by the
same people who have worked in the Panama project.
After clearing the background, we have that vf/with-query
there,
what is it for? We will go more in depth in one of the Flecs sections,
but it's iterating over all of the ECS entities that have a
:vg/camera-active
tag (an identifier, here managed by Vybe) and that have a
vt/Camera
component (components are like structs types in C, from CLJ
we have it reified and can inspect it type, construct an instance for
it, generating a native MemorySegment). A query can have as many terms
(a term is a binding) as you need, and we have 2 in the case here, we
use the retrieved camera (which is the active one and can there only
be one in any given time) and call game/raylib related functions to
draw a scece using the camera data.
Finally, we draw the FPS using raylib's DrawFPS
.
Yeah, I know, there is a lot to unpack here, but you will see that things integrate with each other very well and with CLJ.
init
This function will setup the world, the windows size, pass the draw
var to Vybe's runtime and have a initial function that's called from
the main thread.
Main thead
It's important that you initiate any raylib's functionality, specially drawing-related, inside this initial function as we may have (specially in OSX) some issues related to graphics being rendered outside the main thread.
The initial function is loading a GLTF model (.glb
is the binary
version of it), you can generate a .glb
from Blender, for example,
it should load things correctly, try it!