Skip to content

Instantly share code, notes, and snippets.

@nasser
Last active July 22, 2022 01:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nasser/28a8d57a69d8a742fb80cafdd53a2608 to your computer and use it in GitHub Desktop.
Save nasser/28a8d57a69d8a742fb80cafdd53a2608 to your computer and use it in GitHub Desktop.
Source code to the MAGIC boids iOS demo (http://nas.sr/magic/2017/12/28/early-ios.html)
using UnityEngine;
public class BoidBehaviour : MonoBehaviour
{
void Update()
{
Boids.Core.update(transform);
}
}
(ns boids.build
(:use arcadia.core
arcadia.linear)
(:require [magic
[api :as m]
[core :as magic]
[analyzer :as ana]]
[mage.core :as il])
(:import [UnityEngine Time Transform Vector3 Physics]))
(def passes
(disj ana/default-passes
#'ana/increment-arg-ids))
(def scheduled-passes
(clojure.tools.analyzer.passes/schedule passes))
(defn magic-method
([name f] (assoc (magic-method f) ::il/method name))
([f] (-> f
(ana/analyze (ana/empty-env) scheduled-passes)
magic/compile
::il/body
flatten
(->>
(filter #(= "invoke" (::il/method %)))
first)
(assoc ::il/attributes (enum-or System.Reflection.MethodAttributes/Public
System.Reflection.MethodAttributes/Static)))))
(defmacro static-methods [name & bodies]
`(il/type ~(str name)
~(mapv (fn [[name & body]]
`(magic-method ~(str name) '~(list* 'fn body)))
bodies)))
(defmacro transforms [arry]
`(let [arry# ~arry
trns# (make-array UnityEngine.Transform (count arry#))]
(loop [i# (int 0)]
(if (< i# (.Length arry#))
(do
(aset trns# i# (.transform (aget arry# i#)))
(recur (inc i#)))
trns#))))
(comment
(binding [*unchecked-math* true]
#_
(->> (static-methods Boids.Rules
(separation
^Vector3 [^Transform boid ^UnityEngine.Transform|[]| boids ^float space]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
bpos (.position b)
boidpos (.position boid)
distance (Vector3/Distance boidpos bpos)]
(if (< distance space)
(recur (inc i) (v3+ d (v3- boidpos bpos)))
(recur (inc i) d)))
d)))
(cohesion
^Vector3 [^Transform boid ^UnityEngine.Transform|[]| boids]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
bpos (.position b)
boidpos (.position boid)]
(recur (inc i) (v3+ d (v3* (v3- bpos boidpos) 0.05))))
d)))
(alignment
^Vector3 [^Transform boid ^UnityEngine.Transform|[]| boids]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
boidfwd (.forward boid)]
(recur (inc i) (v3+ d (v3* boidfwd 0.5))))
d))))
(il/assembly+module "rules")
il/emit!)
#_
(->> (static-methods Boids.Flocking
(flock
^Vector3 [^Transform boid ^UnityEngine.Transform|[]| boids]
(let [sep (Boids.Rules/separation boid boids 2)
coh (Boids.Rules/cohesion boid boids)
ali (Boids.Rules/alignment boid boids)]
(v3+ sep coh ali))))
(il/assembly+module "flocking")
il/emit!)
#_
(->> (static-methods Boids.Core
(update
^Vector3 [^Transform b]
(let [neighbours (transforms (Physics/OverlapSphere (.position b) 5))
p* (Vector3/Lerp (.position b) (Boids.Flocking/flock b neighbours) Time/deltaTime)
fwd* (Vector3/Lerp (.forward b) (v3- p* (.position b)) 0.75)]
(set! (.position b) p*)
(set! (.forward b) fwd*))))
(il/assembly+module "boids")
il/emit!)))
(ns boids.core
(:use arcadia.core
arcadia.linear)
(:require [magic.api :as m])
(:import [UnityEngine Time Transform Vector3 Physics]))
(m/defn separation [^Transform boid ^UnityEngine.Transform|[]| boids ^float space]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
bpos (.position b)
boidpos (.position boid)
distance (Vector3/Distance boidpos bpos)]
(if (< distance space)
(recur (inc i) (v3+ d (v3- boidpos bpos)))
(recur (inc i) d)))
d)))
(m/defn cohesion [^Transform boid ^UnityEngine.Transform|[]| boids]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
bpos (.position b)
boidpos (.position boid)]
(recur (inc i) (v3+ d (v3* (v3- bpos boidpos) 0.05))))
d)))
(m/defn alignment [^Transform boid ^UnityEngine.Transform|[]| boids]
(loop [i (int 0)
d (v3 0)]
(if (< i (.Length boids))
(let [b (aget boids i)
boidfwd (.forward boid)]
(recur (inc i) (v3+ d (v3* boidfwd 0.5))))
d)))
(m/defn flock [^Transform boid ^UnityEngine.Transform|[]| boids]
(let [sep (separation boid boids 2)
coh (cohesion boid boids)
ali (alignment boid boids)]
(v3+ sep coh ali)))
(defmacro transforms [arry]
`(let [arry# ~arry
trns# (make-array UnityEngine.Transform (count arry#))]
(loop [i# (int 0)]
(if (< i# (.Length arry#))
(do
(aset trns# i# (.transform (aget arry# i#)))
(recur (inc i#)))
trns#))))
(m/defn update-boid [^Transform b]
(let [neighbours (transforms (Physics/OverlapSphere (.position b) 5))
p* (Vector3/Lerp (.position b) (flock b neighbours) Time/deltaTime)
fwd* (Vector3/Lerp (.forward b) (v3- p* (.position b)) 0.75)]
(set! (.position b) p*)
(set! (.forward b) fwd*)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment