If you're feeling lazy you can just import clojure as a library and use its collections to represent s-expressions like it does internally for itself, then maybe hack clojure.tools.emitter to spit bytecode out from that. "transformed into objects that implement a function interface" is how clojure implemented lambdas, interestingly.
I'm also intrigued by the idea of generally embedding an interpreter on top of a program in a dynamic environment, which the jvm is. Please update on whatever you do with it, very interesting.
Naw, 1. that'd be packaged with all the flaws of the JVM, 2. where's the fun in that? Thing is, more than a language I'm trying to create a framework (.Net-esque), I suppose I could wrangle some of my ideas onto the JVM but a lot of them just don't fit. The big one is the ability to actually control how objects are allocated, if I choose JVM I'm stuck with where they want to put things (the GC heap 200% of the time).
I'll definitely post some updates along the way. I'm hoping to have basic functionality rounded out by the end of the month, optimistic for sure but I've got to get back to work on other more urgent things after that so it's a deadline lol
On a semi related note, have you run any sort of profiling on your game? Got pretty flame graphs?
I'll be honest, I've been focusing on performance to the detriment of finishing the game. Here's an example run, keep in mind that the game runs about 10-20 times better when not profiling. Library names have been blanked out as they're somewhat identifying.
At the moment the game's running on two threads and though I could scale that up as much as I want, two is probably realistic for most android hardware. The basic gist is that tasks are posted to the "TaskSystem" which then executes the work across any threads subscribed as workers. Synchronization is accomplished through "SyncFilters" which define which tasks may be run together.
Highlighted in
blue is collision testing, highlighted in
green is lazy octree rebuild, and highlighted in
turquoise is physics calculation and physics event dispatch, for this test there were ~120 physics objects on screen, but I've seen the game do 500 before at ~30fps, that's without profiling active of course.
The major cost here is plane-sphere collision testing because planes are tested regardless of likelihood —infinite planes don't fit in the octree lol. Once I get around to implementing continuous collisions I'll be able to use finite planes, and that should lower the cost significantly. Another thing that needs to be done is adding some kind of sleeping awareness to the CollisionSystem. Currently the PhysicsSystem does partially suspend physics for low energy objects, but the CollisionSystem still does it's calculations. It'll be tricky to get right though.
Highlighted in
yellow is rendering preparation. Rendering is actually done on a different thread (android opengl api requires this), but a simplified copy of the scene is created on one of the worker threads and passed to the render thread to prevent race conditions. There's lots of resource reuse here, so under normal conditions there're minimal allocations from this.
Highlighted in
red is logic dispatch. Entities are assigned Behaviors, which are activated by events sent to the BehaviorSystem, the BehaviorSystem then posts these coupled with the event as a closure to the task system which executes them asynchronously. Behaviors are vectorized in the sense that a single call to the behavior applies it to all the entities it effects, thus reducing some of the overhead.
Finally, those last two waits are the synchronization wait and the vsync wait respectively. The sync wait is the time that one thread has to yield to another thread due to SyncFilters, and the vysnc is of course a good sign and basically just represents free processor time. At the moment a fair number of behaviors run synchronously, so once I loosen their requirements they'll take a good chunk out of the sync wait.