├── .gitignore ├── Amplitude.cs ├── Bone.cs ├── Curve.cs ├── Helper.cs ├── LICENSE ├── PerlinNoise.cs ├── PointOctree.cs ├── PointOctreeNode.cs ├── Pooled.cs ├── README.md ├── animation.clj ├── boiled.clj ├── core.clj ├── edit.clj ├── gobpool.clj ├── input.clj ├── math.clj ├── mesh.clj ├── physics.clj ├── seed.clj └── sound.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /*.meta -------------------------------------------------------------------------------- /Amplitude.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | //https://answers.unity.com/questions/1167177/how-do-i-get-the-current-volume-level-amplitude-of.html 4 | public class Amplitude : MonoBehaviour { 5 | 6 | public AudioSource audioSource; 7 | public float updateStep = 0.1f; 8 | public int sampleDataLength = 512; 9 | 10 | private float currentUpdateTime = 0f; 11 | 12 | public float amplitude; 13 | private float[] clipSampleData; 14 | 15 | // Use this for initialization 16 | void Awake () { 17 | 18 | if (!audioSource) { 19 | Debug.LogError(GetType() + ".Awake: there was no audioSource set."); 20 | } 21 | clipSampleData = new float[sampleDataLength]; 22 | 23 | } 24 | 25 | // Update is called once per frame 26 | void Update () { 27 | 28 | if (audioSource.isPlaying && audioSource.time < (audioSource.clip.length - 0.2)) { 29 | currentUpdateTime += Time.deltaTime; 30 | if (currentUpdateTime >= updateStep) { 31 | currentUpdateTime = 0f; 32 | try { 33 | audioSource.clip.GetData(clipSampleData, audioSource.timeSamples); 34 | } catch (Exception e) { 35 | 36 | } 37 | //I read 1024 samples, which is about 80 ms on a 44khz stereo clip, beginning at the current sample position of the clip. 38 | amplitude = 0f; 39 | foreach (var sample in clipSampleData) { 40 | amplitude += Mathf.Abs(sample); 41 | } 42 | amplitude /= sampleDataLength; 43 | 44 | } 45 | } else { 46 | amplitude = 0f; 47 | } 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /Bone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | 5 | public class Bone : MonoBehaviour{ 6 | public double length = 1.0; 7 | public string role = "spine"; 8 | public void Start(){ 9 | 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Curve.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | 5 | public class Curve : MonoBehaviour{ 6 | public AnimationCurve curve; 7 | } 8 | -------------------------------------------------------------------------------- /Helper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace Hard{ 5 | public static class Helper{ 6 | public static GameObject ChildNamed(GameObject o, string n) { 7 | Transform[] ts = o.transform.GetComponentsInChildren(true); 8 | foreach (Transform t in ts) if (t.gameObject.name == n) return t.gameObject; 9 | return null; 10 | } 11 | 12 | public static int Mod(int a, int b){ 13 | return a % b; 14 | } 15 | 16 | 17 | 18 | public static Vector3 Aget(Vector3[] coll, int i) 19 | { 20 | return coll[i]; 21 | } 22 | 23 | public static Quaternion Aget(Quaternion[] coll, int i) 24 | { 25 | return coll[i]; 26 | } 27 | 28 | public static int Layer(int i) 29 | { 30 | return 1 << i; 31 | } 32 | 33 | public static AnimationState GetAnimationState(Animation animation, string s) 34 | { 35 | return animation[s]; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Joseph Parker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /PerlinNoise.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | //namespace ImageTools.Core 4 | namespace Hard 5 | { 6 | 7 | /* Perlin noise class. ( by Tom Nuydens (tom@delphi3d.net) ) 8 | * Converted to C# by Mattias Fagerlund, Mattias.Fagerlund@cortego.se 9 | 10 | ****************************************************************************** 11 | 12 | I used the following references for my implementation: 13 | http://students.vassar.edu/mazucker/code/perlin-noise-math-faq.html 14 | Darwin Peachey's chapter in "Texturing & Modeling: A Procedural Approach" 15 | Another good resource is 16 | http://freespace.virgin.net/hugo.elias/models/m_perlin.htm 17 | 18 | ****************************************************************************** 19 | 20 | This class generates 3D Perlin noise. The demo that comes with this is 2D, but 21 | uses the 3rd dimension to create animated noise. The noise does not tile, 22 | although it could be made to do so with a few small modifications to the 23 | algorithm. 24 | 25 | Perlin noise can be used as a starting point for all kinds of things, 26 | including terrain generation, cloud rendering, procedural textures, and more. 27 | Most of these techniques involve rendering multiple "octaves" of noise. This 28 | means you generate multiple noise values for every pixel (each with different 29 | X, Y and/or Z coordinates), and then sum them. There's an example of this in 30 | the accompanying demo. 31 | */ 32 | 33 | public class PerlinNoise 34 | { 35 | private const int GradientSizeTable = 256; 36 | private readonly Random _random; 37 | private readonly double[] _gradients = new double[GradientSizeTable * 3]; 38 | /* Borrowed from Darwyn Peachey (see references above). 39 | The gradient table is indexed with an XYZ triplet, which is first turned 40 | into a single random index using a lookup in this table. The table simply 41 | contains all numbers in [0..255] in random order. */ 42 | private readonly byte[] _perm = new byte[] { 43 | 225,155,210,108,175,199,221,144,203,116, 70,213, 69,158, 33,252, 44 | 5, 82,173,133,222,139,174, 27, 9, 71, 90,246, 75,130, 91,191, 45 | 169,138, 2,151,194,235, 81, 7, 25,113,228,159,205,253,134,142, 46 | 248, 65,224,217, 22,121,229, 63, 89,103, 96,104,156, 17,201,129, 47 | 36, 8,165,110,237,117,231, 56,132,211,152, 20,181,111,239,218, 48 | 170,163, 51,172,157, 47, 80,212,176,250, 87, 49, 99,242,136,189, 49 | 162,115, 44, 43,124, 94,150, 16,141,247, 32, 10,198,223,255, 72, 50 | 53,131, 84, 57,220,197, 58, 50,208, 11,241, 28, 3,192, 62,202, 51 | 18,215,153, 24, 76, 41, 15,179, 39, 46, 55, 6,128,167, 23,188, 52 | 106, 34,187,140,164, 73,112,182,244,195,227, 13, 35, 77,196,185, 53 | 26,200,226,119, 31,123,168,125,249, 68,183,230,177,135,160,180, 54 | 12, 1,243,148,102,166, 38,238,251, 37,240,126, 64, 74,161, 40, 55 | 184,149,171,178,101, 66, 29, 59,146, 61,254,107, 42, 86,154, 4, 56 | 236,232,120, 21,233,209, 45, 98,193,114, 78, 19,206, 14,118,127, 57 | 48, 79,147, 85, 30,207,219, 54, 88,234,190,122, 95, 67,143,109, 58 | 137,214,145, 93, 92,100,245, 0,216,186, 60, 83,105, 97,204, 52}; 59 | 60 | public PerlinNoise(int seed) 61 | { 62 | _random = new Random(seed); 63 | InitGradients(); 64 | } 65 | 66 | public double Noise(double x, double y, double z) 67 | { 68 | /* The main noise function. Looks up the pseudorandom gradients at the nearest 69 | lattice points, dots them with the input vector, and interpolates the 70 | results to produce a single output value in [0, 1] range. */ 71 | 72 | int ix = (int)Math.Floor(x); 73 | double fx0 = x - ix; 74 | double fx1 = fx0 - 1; 75 | double wx = Smooth(fx0); 76 | 77 | int iy = (int)Math.Floor(y); 78 | double fy0 = y - iy; 79 | double fy1 = fy0 - 1; 80 | double wy = Smooth(fy0); 81 | 82 | int iz = (int)Math.Floor(z); 83 | double fz0 = z - iz; 84 | double fz1 = fz0 - 1; 85 | double wz = Smooth(fz0); 86 | 87 | double vx0 = Lattice(ix, iy, iz, fx0, fy0, fz0); 88 | double vx1 = Lattice(ix + 1, iy, iz, fx1, fy0, fz0); 89 | double vy0 = Lerp(wx, vx0, vx1); 90 | 91 | vx0 = Lattice(ix, iy + 1, iz, fx0, fy1, fz0); 92 | vx1 = Lattice(ix + 1, iy + 1, iz, fx1, fy1, fz0); 93 | double vy1 = Lerp(wx, vx0, vx1); 94 | 95 | double vz0 = Lerp(wy, vy0, vy1); 96 | 97 | vx0 = Lattice(ix, iy, iz + 1, fx0, fy0, fz1); 98 | vx1 = Lattice(ix + 1, iy, iz + 1, fx1, fy0, fz1); 99 | vy0 = Lerp(wx, vx0, vx1); 100 | 101 | vx0 = Lattice(ix, iy + 1, iz + 1, fx0, fy1, fz1); 102 | vx1 = Lattice(ix + 1, iy + 1, iz + 1, fx1, fy1, fz1); 103 | vy1 = Lerp(wx, vx0, vx1); 104 | 105 | double vz1 = Lerp(wy, vy0, vy1); 106 | return Lerp(wz, vz0, vz1); 107 | } 108 | 109 | private void InitGradients() 110 | { 111 | for (int i = 0; i < GradientSizeTable; i++) 112 | { 113 | double z = 1f - 2f * _random.NextDouble(); 114 | double r = Math.Sqrt(1f - z * z); 115 | double theta = 2 * Math.PI * _random.NextDouble(); 116 | _gradients[i * 3] = r * Math.Cos(theta); 117 | _gradients[i * 3 + 1] = r * Math.Sin(theta); 118 | _gradients[i * 3 + 2] = z; 119 | } 120 | } 121 | 122 | private int Permutate(int x) 123 | { 124 | const int mask = GradientSizeTable - 1; 125 | return _perm[x & mask]; 126 | } 127 | 128 | private int Index(int ix, int iy, int iz) 129 | { 130 | // Turn an XYZ triplet into a single gradient table index. 131 | return Permutate(ix + Permutate(iy + Permutate(iz))); 132 | } 133 | 134 | private double Lattice(int ix, int iy, int iz, double fx, double fy, double fz) 135 | { 136 | // Look up a random gradient at [ix,iy,iz] and dot it with the [fx,fy,fz] vector. 137 | int index = Index(ix, iy, iz); 138 | int g = index*3; 139 | return _gradients[g] * fx + _gradients[g + 1] * fy + _gradients[g + 2] * fz; 140 | } 141 | 142 | private double Lerp(double t, double value0, double value1) 143 | { 144 | // Simple linear interpolation. 145 | return value0 + t * (value1 - value0); 146 | } 147 | 148 | private double Smooth(double x) 149 | { 150 | /* Smoothing curve. This is used to calculate interpolants so that the noise 151 | doesn't look blocky when the frequency is low. */ 152 | return x * x * (3 - 2 * x); 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /PointOctree.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | // A Dynamic Octree for storing any objects that can be described as a single point 5 | // See also: BoundsOctree, where objects are described by AABB bounds 6 | // Octree: An octree is a tree data structure which divides 3D space into smaller partitions (nodes) 7 | // and places objects into the appropriate nodes. This allows fast access to objects 8 | // in an area of interest without having to check every object. 9 | // Dynamic: The octree grows or shrinks as required when objects as added or removed 10 | // It also splits and merges nodes as appropriate. There is no maximum depth. 11 | // Nodes have a constant - numObjectsAllowed - which sets the amount of items allowed in a node before it splits. 12 | // T: The content of the octree can be anything, since the bounds data is supplied separately. 13 | 14 | // Originally written for my game Scraps (http://www.scrapsgame.com) but intended to be general-purpose. 15 | // Copyright 2014 Nition, BSD licence (see LICENCE file). http://nition.co 16 | // Unity-based, but could be adapted to work in pure C# 17 | public class PointOctree where T : class { 18 | // The total amount of objects currently in the tree 19 | public int Count { get; private set; } 20 | 21 | // Root node of the octree 22 | PointOctreeNode rootNode; 23 | // Size that the octree was on creation 24 | readonly float initialSize; 25 | // Minimum side length that a node can be - essentially an alternative to having a max depth 26 | readonly float minSize; 27 | 28 | /// 29 | /// Constructor for the point octree. 30 | /// 31 | /// Size of the sides of the initial node. The octree will never shrink smaller than this. 32 | /// Position of the centre of the initial node. 33 | /// Nodes will stop splitting if the new nodes would be smaller than this. 34 | public PointOctree(float initialWorldSize, Vector3 initialWorldPos, float minNodeSize) { 35 | if (minNodeSize > initialWorldSize) { 36 | Debug.LogWarning("Minimum node size must be at least as big as the initial world size. Was: " + minNodeSize + " Adjusted to: " + initialWorldSize); 37 | minNodeSize = initialWorldSize; 38 | } 39 | Count = 0; 40 | initialSize = initialWorldSize; 41 | minSize = minNodeSize; 42 | rootNode = new PointOctreeNode(initialSize, minSize, initialWorldPos); 43 | } 44 | 45 | // #### PUBLIC METHODS #### 46 | 47 | /// 48 | /// Add an object. 49 | /// 50 | /// Object to add. 51 | /// Position of the object. 52 | public void Add(T obj, Vector3 objPos) { 53 | // Add object or expand the octree until it can be added 54 | int count = 0; // Safety check against infinite/excessive growth 55 | while (!rootNode.Add(obj, objPos)) { 56 | Grow(objPos - rootNode.Center); 57 | if (++count > 20) { 58 | Debug.LogError("Aborted Add operation as it seemed to be going on forever (" + (count - 1) + ") attempts at growing the octree."); 59 | return; 60 | } 61 | } 62 | Count++; 63 | } 64 | 65 | /// 66 | /// Remove an object. Makes the assumption that the object only exists once in the tree. 67 | /// 68 | /// Object to remove. 69 | /// True if the object was removed successfully. 70 | public bool Remove(T obj) { 71 | bool removed = rootNode.Remove(obj); 72 | 73 | // See if we can shrink the octree down now that we've removed the item 74 | if (removed) { 75 | Count--; 76 | Shrink(); 77 | } 78 | 79 | return removed; 80 | } 81 | 82 | /// 83 | /// Return objects that are within maxDistance of the specified ray. 84 | /// If none, returns an empty array (not null). 85 | /// 86 | /// The ray. Passing as ref to improve performance since it won't have to be copied. 87 | /// Maximum distance from the ray to consider. 88 | /// Objects within range. 89 | public T[] GetNearby(Ray ray, float maxDistance) { 90 | List collidingWith = new List(); 91 | rootNode.GetNearby(ref ray, ref maxDistance, collidingWith); 92 | return collidingWith.ToArray(); 93 | } 94 | 95 | 96 | public T[] GetWithout(Ray ray, float maxDistance) { 97 | List collidingWith = new List(); 98 | rootNode.GetWithout(ref ray, ref maxDistance, collidingWith); 99 | return collidingWith.ToArray(); 100 | } 101 | 102 | /// 103 | /// Draws node boundaries visually for debugging. 104 | /// Must be called from OnDrawGizmos externally. See also: DrawAllObjects. 105 | /// 106 | public void DrawAllBounds() { 107 | rootNode.DrawAllBounds(); 108 | } 109 | 110 | /// 111 | /// Draws the bounds of all objects in the tree visually for debugging. 112 | /// Must be called from OnDrawGizmos externally. See also: DrawAllBounds. 113 | /// 114 | public void DrawAllObjects() { 115 | rootNode.DrawAllObjects(); 116 | } 117 | 118 | // #### PRIVATE METHODS #### 119 | 120 | /// 121 | /// Grow the octree to fit in all objects. 122 | /// 123 | /// Direction to grow. 124 | void Grow(Vector3 direction) { 125 | int xDirection = direction.x >= 0 ? 1 : -1; 126 | int yDirection = direction.y >= 0 ? 1 : -1; 127 | int zDirection = direction.z >= 0 ? 1 : -1; 128 | PointOctreeNode oldRoot = rootNode; 129 | float half = rootNode.SideLength / 2; 130 | float newLength = rootNode.SideLength * 2; 131 | Vector3 newCenter = rootNode.Center + new Vector3(xDirection * half, yDirection * half, zDirection * half); 132 | 133 | // Create a new, bigger octree root node 134 | rootNode = new PointOctreeNode(newLength, minSize, newCenter); 135 | 136 | // Create 7 new octree children to go with the old root as children of the new root 137 | int rootPos = GetRootPosIndex(xDirection, yDirection, zDirection); 138 | PointOctreeNode[] children = new PointOctreeNode[8]; 139 | for (int i = 0; i < 8; i++) { 140 | if (i == rootPos) { 141 | children[i] = oldRoot; 142 | } 143 | else { 144 | xDirection = i % 2 == 0 ? -1 : 1; 145 | yDirection = i > 3 ? -1 : 1; 146 | zDirection = (i < 2 || (i > 3 && i < 6)) ? -1 : 1; 147 | children[i] = new PointOctreeNode(rootNode.SideLength, minSize, newCenter + new Vector3(xDirection * half, yDirection * half, zDirection * half)); 148 | } 149 | } 150 | 151 | // Attach the new children to the new root node 152 | rootNode.SetChildren(children); 153 | } 154 | 155 | /// 156 | /// Shrink the octree if possible, else leave it the same. 157 | /// 158 | void Shrink() { 159 | rootNode = rootNode.ShrinkIfPossible(initialSize); 160 | } 161 | 162 | /// 163 | /// Used when growing the octree. Works out where the old root node would fit inside a new, larger root node. 164 | /// 165 | /// X direction of growth. 1 or -1. 166 | /// Y direction of growth. 1 or -1. 167 | /// Z direction of growth. 1 or -1. 168 | /// Octant where the root node should be. 169 | static int GetRootPosIndex(int xDir, int yDir, int zDir) { 170 | int result = xDir > 0 ? 1 : 0; 171 | if (yDir < 0) result += 4; 172 | if (zDir > 0) result += 2; 173 | return result; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /PointOctreeNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | // A node in a PointOctree 5 | // Copyright 2014 Nition, BSD licence (see LICENCE file). http://nition.co 6 | public class PointOctreeNode where T : class { 7 | // Centre of this node 8 | public Vector3 Center { get; private set; } 9 | // Length of the sides of this node 10 | public float SideLength { get; private set; } 11 | 12 | // Minimum size for a node in this octree 13 | float minSize; 14 | // Bounding box that represents this node 15 | Bounds bounds = default(Bounds); 16 | // Objects in this node 17 | readonly List objects = new List(); 18 | // Child nodes, if any 19 | PointOctreeNode[] children = null; 20 | // bounds of potential children to this node. These are actual size (with looseness taken into account), not base size 21 | Bounds[] childBounds; 22 | // If there are already numObjectsAllowed in a node, we split it into children 23 | // A generally good number seems to be something around 8-15 24 | const int NUM_OBJECTS_ALLOWED = 8; 25 | // For reverting the bounds size after temporary changes 26 | Vector3 actualBoundsSize; 27 | 28 | // An object in the octree 29 | class OctreeObject { 30 | public T Obj; 31 | public Vector3 Pos; 32 | } 33 | 34 | /// 35 | /// Constructor. 36 | /// 37 | /// Length of this node, not taking looseness into account. 38 | /// Minimum size of nodes in this octree. 39 | /// Centre position of this node. 40 | public PointOctreeNode(float baseLengthVal, float minSizeVal, Vector3 centerVal) { 41 | SetValues(baseLengthVal, minSizeVal, centerVal); 42 | } 43 | 44 | // #### PUBLIC METHODS #### 45 | 46 | /// 47 | /// Add an object. 48 | /// 49 | /// Object to add. 50 | /// Position of the object. 51 | /// 52 | public bool Add(T obj, Vector3 objPos) { 53 | if (!Encapsulates(bounds, objPos)) { 54 | return false; 55 | } 56 | SubAdd(obj, objPos); 57 | return true; 58 | } 59 | 60 | /// 61 | /// Remove an object. Makes the assumption that the object only exists once in the tree. 62 | /// 63 | /// Object to remove. 64 | /// True if the object was removed successfully. 65 | public bool Remove(T obj) { 66 | bool removed = false; 67 | 68 | for (int i = 0; i < objects.Count; i++) { 69 | if (objects[i].Obj.Equals(obj)) { 70 | removed = objects.Remove(objects[i]); 71 | break; 72 | } 73 | } 74 | 75 | if (!removed && children != null) { 76 | for (int i = 0; i < 8; i++) { 77 | removed = children[i].Remove(obj); 78 | if (removed) break; 79 | } 80 | } 81 | 82 | if (removed && children != null) { 83 | // Check if we should merge nodes now that we've removed an item 84 | if (ShouldMerge()) { 85 | Merge(); 86 | } 87 | } 88 | 89 | return removed; 90 | } 91 | 92 | /// 93 | /// Return objects that are within maxDistance of the specified ray. 94 | /// 95 | /// The ray. 96 | /// Maximum distance from the ray to consider. 97 | /// List result. 98 | /// Objects within range. 99 | public void GetNearby(ref Ray ray, ref float maxDistance, List result) { 100 | // Does the ray hit this node at all? 101 | // Note: Expanding the bounds is not exactly the same as a real distance check, but it's fast. 102 | // TODO: Does someone have a fast AND accurate formula to do this check? 103 | bounds.Expand(new Vector3(maxDistance * 2, maxDistance * 2, maxDistance * 2)); 104 | bool intersected = bounds.IntersectRay(ray); 105 | bounds.size = actualBoundsSize; 106 | if (!intersected) { 107 | return; 108 | } 109 | 110 | // Check against any objects in this node 111 | for (int i = 0; i < objects.Count; i++) { 112 | if (DistanceToRay(ray, objects[i].Pos) <= maxDistance) { 113 | result.Add(objects[i].Obj); 114 | } 115 | } 116 | 117 | // Check children 118 | if (children != null) { 119 | for (int i = 0; i < 8; i++) { 120 | children[i].GetNearby(ref ray, ref maxDistance, result); 121 | } 122 | } 123 | } 124 | 125 | 126 | public void GetWithout(ref Ray ray, ref float maxDistance, List result) { 127 | // Does the ray hit this node at all? 128 | // Note: Expanding the bounds is not exactly the same as a real distance check, but it's fast. 129 | // TODO: Does someone have a fast AND accurate formula to do this check? 130 | bounds.Expand(new Vector3(maxDistance * 2, maxDistance * 2, maxDistance * 2)); 131 | bool intersected = true; //bounds.IntersectRay(ray); 132 | bounds.size = actualBoundsSize; 133 | if (!intersected) { 134 | return; 135 | } 136 | 137 | // Check against any objects in this node 138 | for (int i = 0; i < objects.Count; i++) { 139 | if (DistanceToRay(ray, objects[i].Pos) >= maxDistance) { 140 | result.Add(objects[i].Obj); 141 | } 142 | } 143 | 144 | // Check children 145 | if (children != null) { 146 | for (int i = 0; i < 8; i++) { 147 | children[i].GetWithout(ref ray, ref maxDistance, result); 148 | } 149 | } 150 | } 151 | 152 | /// 153 | /// Set the 8 children of this octree. 154 | /// 155 | /// The 8 new child nodes. 156 | public void SetChildren(PointOctreeNode[] childOctrees) { 157 | if (childOctrees.Length != 8) { 158 | Debug.LogError("Child octree array must be length 8. Was length: " + childOctrees.Length); 159 | return; 160 | } 161 | 162 | children = childOctrees; 163 | } 164 | 165 | /// 166 | /// Draws node boundaries visually for debugging. 167 | /// Must be called from OnDrawGizmos externally. See also: DrawAllObjects. 168 | /// 169 | /// Used for recurcive calls to this method. 170 | public void DrawAllBounds(float depth = 0) { 171 | float tintVal = depth / 7; // Will eventually get values > 1. Color rounds to 1 automatically 172 | Gizmos.color = new Color(tintVal, 0, 1.0f - tintVal); 173 | 174 | Bounds thisBounds = new Bounds(Center, new Vector3(SideLength, SideLength, SideLength)); 175 | Gizmos.DrawWireCube(thisBounds.center, thisBounds.size); 176 | 177 | if (children != null) { 178 | depth++; 179 | for (int i = 0; i < 8; i++) { 180 | children[i].DrawAllBounds(depth); 181 | } 182 | } 183 | Gizmos.color = Color.white; 184 | } 185 | 186 | /// 187 | /// Draws the bounds of all objects in the tree visually for debugging. 188 | /// Must be called from OnDrawGizmos externally. See also: DrawAllBounds. 189 | /// NOTE: marker.tif must be placed in your Unity /Assets/Gizmos subfolder for this to work. 190 | /// 191 | public void DrawAllObjects() { 192 | float tintVal = SideLength / 20; 193 | Gizmos.color = new Color(0, 1.0f - tintVal, tintVal, 0.25f); 194 | 195 | foreach (OctreeObject obj in objects) { 196 | Gizmos.DrawIcon(obj.Pos, "marker.tif", true); 197 | } 198 | 199 | if (children != null) { 200 | for (int i = 0; i < 8; i++) { 201 | children[i].DrawAllObjects(); 202 | } 203 | } 204 | 205 | Gizmos.color = Color.white; 206 | } 207 | 208 | /// 209 | /// We can shrink the octree if: 210 | /// - This node is >= double minLength in length 211 | /// - All objects in the root node are within one octant 212 | /// - This node doesn't have children, or does but 7/8 children are empty 213 | /// We can also shrink it if there are no objects left at all! 214 | /// 215 | /// Minimum dimensions of a node in this octree. 216 | /// The new root, or the existing one if we didn't shrink. 217 | public PointOctreeNode ShrinkIfPossible(float minLength) { 218 | if (SideLength < (2 * minLength)) { 219 | return this; 220 | } 221 | if (objects.Count == 0 && children.Length == 0) { 222 | return this; 223 | } 224 | 225 | // Check objects in root 226 | int bestFit = -1; 227 | for (int i = 0; i < objects.Count; i++) { 228 | OctreeObject curObj = objects[i]; 229 | int newBestFit = BestFitChild(curObj.Pos); 230 | if (i == 0 || newBestFit == bestFit) { 231 | if (bestFit < 0) { 232 | bestFit = newBestFit; 233 | } 234 | } 235 | else { 236 | return this; // Can't reduce - objects fit in different octants 237 | } 238 | } 239 | 240 | // Check objects in children if there are any 241 | if (children != null) { 242 | bool childHadContent = false; 243 | for (int i = 0; i < children.Length; i++) { 244 | if (children[i].HasAnyObjects()) { 245 | if (childHadContent) { 246 | return this; // Can't shrink - another child had content already 247 | } 248 | if (bestFit >= 0 && bestFit != i) { 249 | return this; // Can't reduce - objects in root are in a different octant to objects in child 250 | } 251 | childHadContent = true; 252 | bestFit = i; 253 | } 254 | } 255 | } 256 | 257 | // Can reduce 258 | if (children == null) { 259 | // We don't have any children, so just shrink this node to the new size 260 | // We already know that everything will still fit in it 261 | SetValues(SideLength / 2, minSize, childBounds[bestFit].center); 262 | return this; 263 | } 264 | 265 | // We have children. Use the appropriate child as the new root node 266 | return children[bestFit]; 267 | } 268 | 269 | /* 270 | /// 271 | /// Get the total amount of objects in this node and all its children, grandchildren etc. Useful for debugging. 272 | /// 273 | /// Used by recursive calls to add to the previous total. 274 | /// Total objects in this node and its children, grandchildren etc. 275 | public int GetTotalObjects(int startingNum = 0) { 276 | int totalObjects = startingNum + objects.Count; 277 | if (children != null) { 278 | for (int i = 0; i < 8; i++) { 279 | totalObjects += children[i].GetTotalObjects(); 280 | } 281 | } 282 | return totalObjects; 283 | } 284 | */ 285 | 286 | // #### PRIVATE METHODS #### 287 | 288 | /// 289 | /// Set values for this node. 290 | /// 291 | /// Length of this node, not taking looseness into account. 292 | /// Minimum size of nodes in this octree. 293 | /// Centre position of this node. 294 | void SetValues(float baseLengthVal, float minSizeVal, Vector3 centerVal) { 295 | SideLength = baseLengthVal; 296 | minSize = minSizeVal; 297 | Center = centerVal; 298 | 299 | // Create the bounding box. 300 | actualBoundsSize = new Vector3(SideLength, SideLength, SideLength); 301 | bounds = new Bounds(Center, actualBoundsSize); 302 | 303 | float quarter = SideLength / 4f; 304 | float childActualLength = SideLength / 2; 305 | Vector3 childActualSize = new Vector3(childActualLength, childActualLength, childActualLength); 306 | childBounds = new Bounds[8]; 307 | childBounds[0] = new Bounds(Center + new Vector3(-quarter, quarter, -quarter), childActualSize); 308 | childBounds[1] = new Bounds(Center + new Vector3(quarter, quarter, -quarter), childActualSize); 309 | childBounds[2] = new Bounds(Center + new Vector3(-quarter, quarter, quarter), childActualSize); 310 | childBounds[3] = new Bounds(Center + new Vector3(quarter, quarter, quarter), childActualSize); 311 | childBounds[4] = new Bounds(Center + new Vector3(-quarter, -quarter, -quarter), childActualSize); 312 | childBounds[5] = new Bounds(Center + new Vector3(quarter, -quarter, -quarter), childActualSize); 313 | childBounds[6] = new Bounds(Center + new Vector3(-quarter, -quarter, quarter), childActualSize); 314 | childBounds[7] = new Bounds(Center + new Vector3(quarter, -quarter, quarter), childActualSize); 315 | } 316 | 317 | /// 318 | /// Private counterpart to the public Add method. 319 | /// 320 | /// Object to add. 321 | /// Position of the object. 322 | void SubAdd(T obj, Vector3 objPos) { 323 | // We know it fits at this level if we've got this far 324 | // Just add if few objects are here, or children would be below min size 325 | if (objects.Count < NUM_OBJECTS_ALLOWED || (SideLength / 2) < minSize) { 326 | OctreeObject newObj = new OctreeObject { Obj = obj, Pos = objPos }; 327 | //Debug.Log("ADD " + obj.name + " to depth " + depth); 328 | objects.Add(newObj); 329 | } 330 | else { // Enough objects in this node already: Create new children 331 | // Create the 8 children 332 | int bestFitChild; 333 | if (children == null) { 334 | Split(); 335 | if (children == null) { 336 | Debug.Log("Child creation failed for an unknown reason. Early exit."); 337 | return; 338 | } 339 | 340 | // Now that we have the new children, see if this node's existing objects would fit there 341 | for (int i = objects.Count - 1; i >= 0; i--) { 342 | OctreeObject existingObj = objects[i]; 343 | // Find which child the object is closest to based on where the 344 | // object's center is located in relation to the octree's center. 345 | bestFitChild = BestFitChild(existingObj.Pos); 346 | children[bestFitChild].SubAdd(existingObj.Obj, existingObj.Pos); // Go a level deeper 347 | objects.Remove(existingObj); // Remove from here 348 | } 349 | } 350 | 351 | // Now handle the new object we're adding now 352 | bestFitChild = BestFitChild(objPos); 353 | children[bestFitChild].SubAdd(obj, objPos); 354 | } 355 | } 356 | 357 | /// 358 | /// Splits the octree into eight children. 359 | /// 360 | void Split() { 361 | float quarter = SideLength / 4f; 362 | float newLength = SideLength / 2; 363 | children = new PointOctreeNode[8]; 364 | children[0] = new PointOctreeNode(newLength, minSize, Center + new Vector3(-quarter, quarter, -quarter)); 365 | children[1] = new PointOctreeNode(newLength, minSize, Center + new Vector3(quarter, quarter, -quarter)); 366 | children[2] = new PointOctreeNode(newLength, minSize, Center + new Vector3(-quarter, quarter, quarter)); 367 | children[3] = new PointOctreeNode(newLength, minSize, Center + new Vector3(quarter, quarter, quarter)); 368 | children[4] = new PointOctreeNode(newLength, minSize, Center + new Vector3(-quarter, -quarter, -quarter)); 369 | children[5] = new PointOctreeNode(newLength, minSize, Center + new Vector3(quarter, -quarter, -quarter)); 370 | children[6] = new PointOctreeNode(newLength, minSize, Center + new Vector3(-quarter, -quarter, quarter)); 371 | children[7] = new PointOctreeNode(newLength, minSize, Center + new Vector3(quarter, -quarter, quarter)); 372 | } 373 | 374 | /// 375 | /// Merge all children into this node - the opposite of Split. 376 | /// Note: We only have to check one level down since a merge will never happen if the children already have children, 377 | /// since THAT won't happen unless there are already too many objects to merge. 378 | /// 379 | void Merge() { 380 | // Note: We know children != null or we wouldn't be merging 381 | for (int i = 0; i < 8; i++) { 382 | PointOctreeNode curChild = children[i]; 383 | int numObjects = curChild.objects.Count; 384 | for (int j = numObjects - 1; j >= 0; j--) { 385 | OctreeObject curObj = curChild.objects[j]; 386 | objects.Add(curObj); 387 | } 388 | } 389 | // Remove the child nodes (and the objects in them - they've been added elsewhere now) 390 | children = null; 391 | } 392 | 393 | /// 394 | /// Checks if outerBounds encapsulates the given point. 395 | /// 396 | /// Outer bounds. 397 | /// Point. 398 | /// True if innerBounds is fully encapsulated by outerBounds. 399 | static bool Encapsulates(Bounds outerBounds, Vector3 point) { 400 | return outerBounds.Contains(point); 401 | } 402 | 403 | /// 404 | /// Find which child node this object would be most likely to fit in. 405 | /// 406 | /// The object's position. 407 | /// One of the eight child octants. 408 | int BestFitChild(Vector3 objPos) { 409 | return (objPos.x <= Center.x ? 0 : 1) + (objPos.y >= Center.y ? 0 : 4) + (objPos.z <= Center.z ? 0 : 2); 410 | } 411 | 412 | /// 413 | /// Checks if there are few enough objects in this node and its children that the children should all be merged into this. 414 | /// 415 | /// True there are less or the same abount of objects in this and its children than numObjectsAllowed. 416 | bool ShouldMerge() { 417 | int totalObjects = objects.Count; 418 | if (children != null) { 419 | foreach (PointOctreeNode child in children) { 420 | if (child.children != null) { 421 | // If any of the *children* have children, there are definitely too many to merge, 422 | // or the child woudl have been merged already 423 | return false; 424 | } 425 | totalObjects += child.objects.Count; 426 | } 427 | } 428 | return totalObjects <= NUM_OBJECTS_ALLOWED; 429 | } 430 | 431 | // Returns true if this node or any of its children, grandchildren etc have something in them 432 | bool HasAnyObjects() { 433 | if (objects.Count > 0) return true; 434 | 435 | if (children != null) { 436 | for (int i = 0; i < 8; i++) { 437 | if (children[i].HasAnyObjects()) return true; 438 | } 439 | } 440 | 441 | return false; 442 | } 443 | 444 | /// 445 | /// Returns the closest distance to the given ray from a point. 446 | /// 447 | /// The ray. 448 | /// The point to check distance from the ray. 449 | /// Distance from the point to the closest point of the ray. 450 | public static float DistanceToRay(Ray ray, Vector3 point) { 451 | return Vector3.Cross(ray.direction, point - ray.origin).magnitude; 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /Pooled.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | #if UNITY_EDITOR 3 | using UnityEditor; 4 | #endif 5 | using System.Collections; 6 | using clojure.lang; 7 | 8 | 9 | public class Pooled : MonoBehaviour{ 10 | public IFn recycler; 11 | 12 | public void onDestroy(){ 13 | } 14 | 15 | public static void addTag(string name){ 16 | #if UNITY_EDITOR 17 | 18 | SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); 19 | SerializedProperty tagsProp = tagManager.FindProperty("tags"); 20 | SerializedProperty layersProp = tagManager.FindProperty("layers"); 21 | 22 | bool found = false; 23 | for (int i = 0; i < tagsProp.arraySize; i++) 24 | { 25 | SerializedProperty t = tagsProp.GetArrayElementAtIndex(i); 26 | if (t.stringValue.Equals(name)) { found = true; break; } 27 | } 28 | 29 | if (!found) 30 | { 31 | tagsProp.InsertArrayElementAtIndex(0); 32 | SerializedProperty n = tagsProp.GetArrayElementAtIndex(0); 33 | n.stringValue = name; 34 | } 35 | 36 | 37 | SerializedProperty _spasdf = layersProp.GetArrayElementAtIndex(10); 38 | if (_spasdf != null) _spasdf.stringValue = name; 39 | tagManager.ApplyModifiedProperties(); 40 | 41 | #endif 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hard.core 2 | ==== 3 | 4 | for ```arcadia -b develop``` and Unity 5 5 | 6 | docs coming soon -------------------------------------------------------------------------------- /animation.clj: -------------------------------------------------------------------------------- 1 | (ns hard.animation 2 | (:import [UnityEngine])) 3 | 4 | ;mechanim animator 5 | 6 | (defn ->animator [^UnityEngine.GameObject o] 7 | (.GetComponentInChildren o UnityEngine.Animator)) 8 | 9 | (defn state-info [o] 10 | (.GetCurrentAnimatorStateInfo (->animator o) 0)) 11 | 12 | (defn is-name [o s] 13 | (.IsName (state-info o) s)) 14 | 15 | (defn play-state [o s] (.Play (->animator o) s)) 16 | 17 | (defn cross-fade [o s t] (.CrossFade (->animator o) s t)) 18 | 19 | (defn param-bool 20 | ([o s] (.GetBool (->animator o) s)) 21 | ([o s v] (.SetBool (->animator o) s v))) 22 | 23 | (defn param-float 24 | ([^UnityEngine.GameObject o s] (.GetFloat (->animator o) s)) 25 | ([^UnityEngine.GameObject o s v] (.SetFloat (->animator o) s v))) 26 | 27 | 28 | ;legacy animations 29 | 30 | (defn ->animation [o] 31 | (.GetComponentInChildren o UnityEngine.Animation)) -------------------------------------------------------------------------------- /boiled.clj: -------------------------------------------------------------------------------- 1 | 2 | (ns hard.boiled 3 | (:require 4 | arcadia.core 5 | ;[clojure.string :as string] 6 | ;[clojure.pprint :as pprint] 7 | ) 8 | (:use arcadia.core hard.core) 9 | (:import [UnityEngine] 10 | ArcadiaState)) 11 | 12 | 13 | 14 | (comment 15 | 16 | (def serial-fields (atom {})) 17 | 18 | (defprotocol ISerializable 19 | (serialize [this]) 20 | (deserialize [this s])) 21 | 22 | (defn type-name [sym] (.Name ^MonoType (resolve sym))) 23 | 24 | (defmacro fun-printer [t] 25 | (let [v (with-meta (gensym "value") {:tag t}) 26 | w (with-meta (gensym "writer") {:tag 'System.IO.TextWriter})] 27 | `(fn [~v ~w] 28 | (.Write ~w (str "#" ~t " " (serialize ~v)))))) 29 | 30 | (defmacro install-fun-printer [t] 31 | `(. ~(with-meta 'print-method {:tag 'clojure.lang.MultiFn}) 32 | ~'addMethod ~t (fun-printer ~t))) 33 | 34 | (defn constructor-arguments [^MonoType t] 35 | (get @serial-fields t)) 36 | 37 | (defmacro vector-constructor [t] 38 | (let [ctor (constructor-arguments (resolve t)) 39 | params (map #(gensym %) ctor)] 40 | (list 'fn [(vec params)] 41 | (list* 'list ''new (list 'quote t) params)))) 42 | 43 | (defmacro install-type-parser [t] 44 | `(def ~(symbol (str "parse-" (type-name t))) 45 | (vector-constructor ~t))) 46 | 47 | (deftype Bird [^{:volatile-mutable true :tag int} age ^String plumage]) 48 | (reset! serial-fields {Bird '[age plumage]}) 49 | 50 | (extend-protocol ISerializable 51 | Bird 52 | (serialize [this] (str "[" (.age this) " " (.plumage this)"]")) 53 | (deserialize [this s] 54 | (let [[a p] (read-string s)] 55 | (Bird. a p)))) 56 | 57 | (install-type-parser Bird) 58 | (install-fun-printer Bird) 59 | #_(read-string (prn-str (hard.boiled.Bird. 7 "feathers"))) 60 | 61 | #_(let [go (clone! :sphere) 62 | c (cmpt+ go ArcadiaState)] 63 | (rotation! go (rand-vec 360 360 360)) 64 | (set! (.state c) (Bird. 2048 "feathers"))) 65 | 66 | 67 | 68 | (comment 69 | (use 'hard.core) 70 | (import 'ArcadiaState) 71 | 72 | 73 | 74 | 75 | 76 | 77 | (macroexpand-1 '(fun-printer Bird)) 78 | (install-fun-printer Bird) 79 | (deserialize (Bird. 0) (serialize (Bird. 56))) 80 | 81 | (read-string (prn-str (Bird. 156))) 82 | 83 | 84 | (deserialize (Bird. 1) "[45]")) 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | (defn longest-constructor-signature 112 | "Returns the longest parameter list for all constructors in type t" 113 | [^System.MonoType t] 114 | (->> (.GetConstructors t) 115 | (map #(.GetParameters ^ConstructorInfo %)) 116 | (sort (fn [a b] (compare (count a) 117 | (count b)))) 118 | last)) 119 | 120 | 121 | 122 | 123 | (defmacro reconstructor [targetsym t] 124 | (mapv 125 | (fn [arg] 126 | `(. ~targetsym 127 | ~(symbol arg))) 128 | (constructor-arguments (resolve t)))) 129 | 130 | (defmacro type-printer [t] 131 | (let [v (with-meta (gensym "value") {:tag t}) 132 | w (with-meta (gensym "writer") {:tag 'System.IO.TextWriter})] 133 | `(fn [~v ~w] 134 | (.Write ~w (str "#" ~(str t) " " (reconstructor ~v ~t)))))) 135 | 136 | (defmacro install-type-printer [t] 137 | `(. ~(with-meta 'print-method {:tag 'clojure.lang.MultiFn}) 138 | ~'addMethod ~t (type-printer ~t))) 139 | 140 | (defmacro serializability [types] 141 | `(do 142 | ~@(mapcat 143 | (fn [t] 144 | [`(install-type-printer ~t) 145 | `(install-type-parser ~t)]) 146 | types))) 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | (comment 155 | 156 | (install-type-parser fun.core.fart) 157 | 158 | 159 | ((juxt (comp read-string prn-str) prn) (fun.core.fart. false "bad")) 160 | 161 | (read-string "#fun.core.fart [false \"big\"]\r\n") 162 | (prn-str (fun.core.fart. false "bad")) 163 | 164 | ((juxt (comp read-string prn-str) prn) (Vector3. 1 2 3)) 165 | 166 | ((vector-constructor fun.core.fart) [false "bad"]) 167 | 168 | (constructor-arguments fun.core.fart)) 169 | 170 | 171 | ) -------------------------------------------------------------------------------- /core.clj: -------------------------------------------------------------------------------- 1 | (ns hard.core 2 | (:require arcadia.core arcadia.linear clojure.string) 3 | (:import 4 | [UnityEngine Debug Resources GameObject PrimitiveType 5 | Application Color Input Screen Gizmos Camera Component Vector3 Mathf Quaternion] 6 | ArcadiaState 7 | Hard.Helper)) 8 | 9 | (declare position!) 10 | 11 | (defn playing? [] (. Application isPlaying)) 12 | 13 | (defn load-scene [sn] (Application/LoadLevel sn)) 14 | 15 | (defn loaded-scene [] Application/loadedLevel) 16 | 17 | (defn quit [] (Application/Quit)) 18 | 19 | (defn screen-size [] [(Screen/width)(Screen/height)]) 20 | 21 | (defn main-camera [] (UnityEngine.Camera/main)) 22 | 23 | (defn resource [s] (UnityEngine.Resources/Load s)) 24 | 25 | (defn vector2? [x] (instance? UnityEngine.Vector2 x)) 26 | (defn vector3? [x] (instance? UnityEngine.Vector3 x)) 27 | (defn vector4? [x] (instance? UnityEngine.Vector4 x)) 28 | (defn transform? [x] (instance? UnityEngine.Transform x)) 29 | (defn quaternion? [x] (instance? UnityEngine.Quaternion x)) 30 | (defn color? [x] (instance? UnityEngine.Color x)) 31 | (defn gameobject? [x] (instance? UnityEngine.GameObject x)) 32 | (defn component? [x] (instance? UnityEngine.Component x)) 33 | 34 | (defn- get-or [col idx nf] (or (get col idx) nf)) 35 | 36 | 37 | (def ->go arcadia.core/gobj) 38 | (defn ->transform [v] (arcadia.core/cmpt v UnityEngine.Transform)) 39 | 40 | (defmacro >v3 [o] 41 | `(.position (.transform ~o))) 42 | 43 | (defn X [o] (.x (>v3 o))) 44 | (defn Y [o] (.y (>v3 o))) 45 | (defn Z [o] (.z (>v3 o))) 46 | 47 | 48 | (defn destroy! [o] 49 | (if (sequential? o) 50 | (dorun (map #(UnityEngine.Object/Destroy %) o)) 51 | (UnityEngine.Object/Destroy o))) 52 | 53 | (defonce CLONED (atom [])) 54 | (defonce DATA (atom {})) 55 | 56 | (defn clear-cloned! [] 57 | (destroy! @CLONED) 58 | (reset! CLONED []) 59 | (reset! DATA {})) 60 | 61 | (defmacro clone! [kw] 62 | (if (keyword? kw) 63 | (let [source (clojure.string/replace (subs (str kw) 1) #"[:]" "/")] 64 | `(let [^UnityEngine.GameObject source# (~'UnityEngine.Resources/Load ~source) 65 | ^UnityEngine.GameObject gob# (~'UnityEngine.GameObject/Instantiate source#)] 66 | (~'set! (.name gob#) (.name source#)) 67 | (swap! ~'hard.core/CLONED #(cons gob# %)) 68 | gob#)) 69 | `(-clone! ~kw))) 70 | 71 | 72 | (defn ^UnityEngine.GameObject -clone! 73 | ([ref] (-clone! ref nil)) 74 | ([ref pos] 75 | (when (playing?) 76 | (when-let [^UnityEngine.GameObject source 77 | (cond (string? ref) (resource ref) 78 | (keyword? ref) (resource (clojure.string/replace (subs (str ref) 1) #"[:]" "/")) 79 | :else nil)] 80 | 81 | (let [pos (or pos (.position (.transform source))) 82 | quat (.rotation (.transform source)) 83 | ^UnityEngine.GameObject gob (arcadia.core/instantiate source pos quat)] 84 | (set! (.name gob) (.name source)) 85 | (swap! CLONED #(cons gob %)) gob))))) 86 | 87 | 88 | (defn data! 89 | ([^UnityEngine.GameObject o v] 90 | (swap! DATA assoc o v) o) 91 | ([^UnityEngine.GameObject o k v] 92 | (swap! DATA assoc-in [o k] v) o)) 93 | 94 | (defn data 95 | ([^UnityEngine.GameObject o] 96 | (get @DATA o)) 97 | ([^UnityEngine.GameObject o k] 98 | (get-in @DATA [o k]))) 99 | 100 | (defn update-data! 101 | ([^UnityEngine.GameObject o f] 102 | (swap! DATA update o f) o) 103 | ([^UnityEngine.GameObject o k f] 104 | (swap! DATA update-in [o k] f) o)) 105 | 106 | 107 | (defn state! [^UnityEngine.GameObject o v] 108 | (reset! (.state (arcadia.core/ensure-cmpt o ArcadiaState)) v)) 109 | 110 | 111 | 112 | (defn color 113 | ([col] (if (> (count col) 2) (apply color (take 4 col)) (color 0 0 0 0))) 114 | ([r g b] (UnityEngine.Color. r g b 1.0)) 115 | ([r g b a] (UnityEngine.Color. r g b a))) 116 | 117 | 118 | (defn clamp-v3 [v lb ub] 119 | (let [lb (float lb) ub (float ub)] 120 | (Vector3. 121 | (Mathf/Clamp (.x v) lb ub) 122 | (Mathf/Clamp (.y v) lb ub) 123 | (Mathf/Clamp (.z v) lb ub)))) 124 | 125 | 126 | 127 | 128 | (defn name! [o s] (set! (.name o) (str s)) o) 129 | 130 | (defn ^GameObject parent! [^GameObject a ^GameObject b] 131 | (set! (.parent (.transform a)) (.transform b)) a) 132 | 133 | (defn unparent! ^GameObject [^GameObject child] 134 | (set! (.parent (.transform child)) nil) child) 135 | 136 | (defn world-position [o] 137 | (when-let [o (->go o)] (.TransformPoint (.transform o) (>v3 o)))) 138 | 139 | (defn position! [^UnityEngine.GameObject o ^UnityEngine.Vector3 pos] 140 | (set! (.position (.transform o)) pos) o) 141 | 142 | (defn ^UnityEngine.Vector3 143 | local-position [^UnityEngine.GameObject o] 144 | (.localPosition (.transform o))) 145 | 146 | (defn ^UnityEngine.Vector3 147 | local-position! [^UnityEngine.GameObject o pos] 148 | (set! (.localPosition (.transform o)) pos) o) 149 | 150 | (defn ^UnityEngine.Vector3 151 | local-direction [^GameObject o ^UnityEngine.Vector3 v] 152 | (.TransformDirection (.transform o) v)) 153 | 154 | (defn ^UnityEngine.Vector3 155 | transform-point [o v] 156 | (when-let [o (->go o)] 157 | (.TransformPoint (.transform o) v))) 158 | 159 | (defn ^UnityEngine.Vector3 160 | inverse-transform-point [o v] 161 | (when-let [o (->go o)] 162 | (.InverseTransformPoint (.transform o) v))) 163 | 164 | (defn ^UnityEngine.Vector3 165 | inverse-transform-direction [o v] 166 | (when-let [o (->go o)] 167 | (.InverseTransformDirection (.transform o) v))) 168 | 169 | (defn move-towards [v1 v2 step] 170 | (Vector3/MoveTowards v1 v2 step)) 171 | 172 | (defn ^UnityEngine.Vector3 lerp [^UnityEngine.Vector3 v1 ^UnityEngine.Vector3 v2 ratio] 173 | (Vector3/Lerp v1 v2 ratio)) 174 | 175 | (defn ^UnityEngine.GameObject local-scale [^UnityEngine.GameObject o] 176 | (when-let [o (->go o)] (.localScale (.transform o) ))) 177 | 178 | (defn ^UnityEngine.GameObject local-scale! [^UnityEngine.GameObject o ^UnityEngine.Vector3 v] 179 | (when-let [o (->go o)] (set! (.localScale (.transform o)) v) o)) 180 | 181 | (defn rotate-around! [o point axis angle] 182 | (when-let [o (->go o)] 183 | (. (.transform o) (RotateAround point axis angle)))) 184 | 185 | (defn rotation [o] 186 | (when-let [o (->go o)] (.rotation (.transform o) ))) 187 | 188 | (defn local-rotation [o] 189 | (when-let [o (->go o)] (.localRotation (.transform o) ))) 190 | 191 | (defn rotate! ^GameObject [^GameObject o ^Vector3 rot] 192 | (.Rotate (.transform o) rot) o) 193 | 194 | (defn rotation! ^GameObject [^GameObject o ^UnityEngine.Quaternion rot] 195 | (set! (.rotation (.transform o)) rot) o) 196 | 197 | (defn local-rotation! [o ^UnityEngine.Quaternion rot] 198 | (when-let [o (->go o)] 199 | (set! (.localRotation (.transform o)) rot)) o) 200 | 201 | (defn look-at! 202 | ([a b] (.LookAt (->transform a) b)) 203 | ([a b c] (.LookAt (->transform a) b c))) 204 | 205 | (defn look-quat [a b] 206 | (Quaternion/LookRotation (arcadia.linear/v3- b (>v3 a)))) 207 | 208 | (defn lerp-look! [^UnityEngine.GameObject a b ^double v] 209 | (let [^UnityEngine.Transform at (.transform a) 210 | aq (.rotation at) 211 | lq (look-quat a b) 212 | res (Quaternion/Lerp aq lq (float v))] 213 | (set! (.rotation at) res))) 214 | 215 | 216 | (defn parent-component [thing sym] 217 | (when-not (string? sym) 218 | (when-let [gob (->go thing)] 219 | (.GetComponentInParent gob sym)))) 220 | 221 | (defn child-component [thing sym] 222 | (when-not (string? sym) 223 | (when-let [gob (->go thing)] 224 | (.GetComponentInChildren gob sym)))) 225 | 226 | (defn parent-components [thing sym] 227 | (when-not (string? sym) 228 | (when-let [gob (->go thing)] 229 | (.GetComponentsInParent gob sym)))) 230 | 231 | (defn child-components [thing sym] 232 | (when-not (string? sym) 233 | (when-let [gob (->go thing)] 234 | (.GetComponentsInChildren gob sym)))) 235 | 236 | (defn child-transforms [go] 237 | (rest (child-components go UnityEngine.Transform))) 238 | 239 | 240 | (defn direct-children [go] 241 | (butlast 242 | (loop [^UnityEngine.Transform o (->transform go) col '()] 243 | (if-not (.parent o) (cons o col) 244 | (recur (.parent o) (cons o col)))))) 245 | 246 | 247 | (defn ^UnityEngine.GameObject child-named [^UnityEngine.GameObject go ^System.String s] 248 | (Hard.Helper/ChildNamed go s)) 249 | 250 | (defn ^UnityEngine.GameObject direct-child-named [^UnityEngine.GameObject go ^System.String s] 251 | (if-let [^UnityEngine.Transform t (.Find (.transform go) s)] 252 | (.gameObject t))) 253 | 254 | 255 | ;MACROS 256 | 257 | (defmacro >v2 [o] 258 | `(UnityEngine.Vector2. 259 | (.x (.position (.transform ~o))) 260 | (.y (.position (.transform ~o))))) 261 | 262 | ;@pjago 263 | (defmacro v3map [f & v3s] 264 | (let [vs (repeatedly (count v3s) #(gensym "v")) 265 | xs (map #(list '.x %) vs) 266 | ys (map #(list '.y %) vs) 267 | zs (map #(list '.z %) vs)] 268 | `(let [~@(interleave vs v3s)] 269 | (v3 (~f ~@xs) (~f ~@ys) (~f ~@zs))))) 270 | 271 | (defmacro <> [o [f & xs]] `(let [o# ~o] (~f o# ~@xs) o#)) 272 | 273 | #_(-> (GameObject.) 274 | (<> (cmpt+ UnityEngine.Rigidbody2D)) 275 | (<> (set-state! :dog 'good)) 276 | (<> (cmpt+ UnityEngine.BoxCollider2D))) 277 | 278 | 'nasser 279 | (defmacro ∆ [x] `(* UnityEngine.Time/deltaTime ~x)) 280 | 281 | (defmacro pow [a b] `(UnityEngine.Mathf/Pow ~a ~b)) 282 | (defmacro abs [a] `(UnityEngine.Mathf/Abs ~a)) 283 | (defmacro sin [a] `(UnityEngine.Mathf/Sin ~a)) 284 | (defmacro cos [a] `(UnityEngine.Mathf/Cos ~a)) 285 | 286 | (defmacro prop* [s] 287 | `(fn [o#] (~(symbol (str "." s)) o#))) 288 | 289 | (defmacro ?f 290 | ([] `(~'UnityEngine.Random/value)) 291 | ([n] `(* ~'UnityEngine.Random/value ~n)) 292 | ([a b] `(~'UnityEngine.Random/Range ~a ~b))) 293 | 294 | (defmacro ?sphere 295 | ([] `(~'UnityEngine.Random/insideUnitSphere)) 296 | ([n] `(arcadia.linear/v3* ~'UnityEngine.Random/insideUnitSphere ~n))) 297 | 298 | (defmacro ?circle 299 | ([] `(~'UnityEngine.Random/insideUnitCircle)) 300 | ([n] `(arcadia.linear/v2* ~'UnityEngine.Random/insideUnitCircle ~n))) 301 | 302 | (defmacro ?on-sphere 303 | ([] `(~'UnityEngine.Random/onUnitSphere)) 304 | ([n] `(arcadia.linear/v3* ~'UnityEngine.Random/onUnitSphere ~n))) 305 | 306 | (defmacro ?rotation [] `(~'UnityEngine.Random/rotation)) 307 | 308 | ;thanks @nasser 309 | (defmacro foreach [[local-sym arr] & body] 310 | `(let [len# (.Length ~arr)] 311 | (loop [i# (int 0)] 312 | (when (< i# len#) 313 | (let [~local-sym (aget ~arr i#)] 314 | ~@body 315 | (recur (inc i#))))))) 316 | 317 | (defmacro ? [& body] 318 | (if (> 4 (count body)) 319 | `(if ~@body) 320 | (let [ 321 | body (if (even? (count body)) 322 | body 323 | (concat (butlast body) (list :else (last body))))] 324 | `(do (prn [~@body]) 325 | (cond ~@body))))) 326 | 327 | 328 | (defn- un-dot [syms] 329 | (loop [col syms] 330 | (if (> (count col) 2) 331 | (let [[obj op field] (take 3 col) 332 | form (cond (= '. op) (list op obj field) 333 | (= '> op) (list '.GetComponent obj (str field)))] 334 | (recur (cons form (drop 3 col)))) 335 | (first col)))) 336 | 337 | (defmacro .* [& more] 338 | (let [address (last more) 339 | matcher (re-matcher #"[\>\.]|[^\>\.]+" (str address)) 340 | broken (loop [col []] (if-let [res (re-find matcher)] (recur (conj col res)) col)) 341 | s-exp (un-dot (concat (butlast more) (map symbol broken)))] 342 | `(~@s-exp))) 343 | 344 | 345 | (defn- ->name [m] 346 | (or (first (filter #(instance? System.Text.RegularExpressions.Regex %) m)) 347 | (apply str (interpose " " m)))) 348 | 349 | (defmacro the [& m] 350 | (let [k (->name m)] 351 | (if (string? k) 352 | `(arcadia.core/object-named ~k) 353 | `(first (arcadia.core/objects-named ~k))))) 354 | 355 | (defmacro every [& m] `(arcadia.core/objects-named ~(->name m))) 356 | 357 | 358 | (defn gizmo-color [c] (set! Gizmos/color c)) 359 | (defn gizmo-line [^Vector3 from ^Vector3 to] (Gizmos/DrawLine from to)) 360 | (defn gizmo-ray [^Vector3 from ^Vector3 dir] (Gizmos/DrawRay from dir)) 361 | (defn gizmo-cube [^Vector3 v ^Vector3 s] (Gizmos/DrawWireCube v s)) 362 | (defn gizmo-point 363 | ([^Vector3 v] (Gizmos/DrawSphere v 0.075)) 364 | ([^Vector3 v r] (Gizmos/DrawSphere v r))) 365 | 366 | 367 | (defn material-color! [^UnityEngine.GameObject o ^UnityEngine.Color c] 368 | (let [^UnityEngine.Renderer r (.GetComponent o UnityEngine.Renderer)] 369 | (set! (.color (.material r)) c))) 370 | 371 | (defn text! [^UnityEngine.GameObject o ^System.String s] 372 | (let [^UnityEngine.TextMesh tm (.GetComponent o UnityEngine.TextMesh)] 373 | (set! (.text tm) s))) 374 | 375 | 376 | '(hard.core) 377 | 378 | -------------------------------------------------------------------------------- /edit.clj: -------------------------------------------------------------------------------- 1 | (ns ^:editor hard.edit 2 | (:use [hard.core]) 3 | (:import [UnityEngine HideFlags])) 4 | 5 | '(import [UnityEditor Selection]) 6 | 7 | '(defn active [] (UnityEditor.Selection/activeGameObject)) 8 | 9 | '(defn sel [] (UnityEditor.Selection/objects)) 10 | 11 | '(defn sel! 12 | ([v] (cond (gameobject? v) (set! (Selection/objects) (into-array [v])) 13 | (sequential? v) (set! (Selection/objects) (into-array v)))) 14 | ([v & more] (set! (Selection/objects) (into-array (cons v more))))) 15 | 16 | (defn clear-flags! [go] 17 | (import '[UnityEngine HideFlags]) 18 | (set! (.hideFlags go) HideFlags/None)) 19 | 20 | (defn not-editable! [go] 21 | (import '[UnityEngine HideFlags]) 22 | (set! (.hideFlags go) HideFlags/NotEditable)) 23 | 24 | (defn editable! [go] 25 | (import '[UnityEngine HideFlags]) 26 | (set! (.hideFlags go) HideFlags/None)) 27 | 28 | (defn hide! [go] 29 | (import '[UnityEngine HideFlags]) 30 | (set! (.hideFlags go) HideFlags/HideInHierarchy)) 31 | -------------------------------------------------------------------------------- /gobpool.clj: -------------------------------------------------------------------------------- 1 | (ns hard.gobpool 2 | (:import 3 | [UnityEngine HideFlags GameObject] 4 | [Pooled])) 5 | 6 | (Pooled/addTag "pooled") 7 | (Pooled/addTag "clone") 8 | 9 | (defn ^UnityEngine.GameObject -tag-clone [^UnityEngine.GameObject o ^System.String n] 10 | (set! (.name o) n) 11 | (set! (.tag o) "clone") o) 12 | 13 | (defmacro ^UnityEngine.GameObject -clone [^clojure.lang.Keyword k] 14 | (let [] 15 | `(hard.gobpool/-tag-clone (UnityEngine.Object/Instantiate (~'UnityEngine.Resources/Load ~(name k))) ~(name k)))) 16 | 17 | (defn destroy-tagged [tag] 18 | (dorun (map #(UnityEngine.Object/DestroyImmediate %) (GameObject/FindGameObjectsWithTag tag)))) 19 | 20 | (defprotocol IGobPool 21 | (-reuse [a]) 22 | (-recycle [a b]) 23 | (-stats [a])) 24 | 25 | (deftype GobPool [^|System.Object[]| pool 26 | ^System.Int64 ^:volatile-mutable idx] 27 | IGobPool 28 | (-stats [a] 29 | (list (inc idx) '/ (.Length pool))) 30 | (-reuse [a] 31 | (try 32 | (set! idx (dec idx)) 33 | (aget pool (inc idx)) 34 | (catch Exception e (set! idx (inc idx)) nil))) 35 | (-recycle [a b] 36 | (try 37 | (set! idx (inc idx)) 38 | (aset pool idx b) nil 39 | (catch Exception e (set! idx (dec idx)) nil)))) 40 | 41 | (defn pool-prep [o] 42 | `((set! (.tag ~o) "pooled") 43 | (.SetParent (.transform ~o) nil false) 44 | (set! (.hideFlags ~o) UnityEngine.HideFlags/HideAndDontSave) 45 | (set! (.position (.transform ~o)) (UnityEngine.Vector3. 0 -100000 0)))) 46 | 47 | (defn reuse-prep [o] 48 | `((set! (.tag ~o) "clone") 49 | (set! (.hideFlags ~o) UnityEngine.HideFlags/None) 50 | (set! (.position (.transform ~o)) (UnityEngine.Vector3. 0 0 0)))) 51 | 52 | (defmacro gobpool [length type-sym model] 53 | (let [gob (with-meta (gensym 'gob) {:tag 'UnityEngine.GameObject}) 54 | sym (with-meta (symbol (str "*" type-sym)) {:tag 'UnityEngine.GameObject}) 55 | pool (with-meta (symbol (str "<>" type-sym)) {:tag 'UnityEngine.GameObject}) 56 | return (with-meta (symbol (str "!" type-sym)) {:tag System.Boolean}) 57 | o# (gensym)] 58 | `(~'let [~gob ~model] 59 | ~@(pool-prep gob) 60 | (declare ~pool) 61 | (when (bound? (var ~pool)) (dorun (map ~'arcadia.core/destroy-immediate (~'.pool ~pool)))) 62 | (~'def ~pool (new ~GobPool (~'make-array ~'System.Object ~length) -1)) 63 | (~'defn ~return 64 | [~(with-meta (symbol "a") {:tag 'UnityEngine.GameObject})] 65 | (~'hard.gobpool/-recycle ~pool ~'a) 66 | ~@(pool-prep 'a)) 67 | (~'defn ~sym [] 68 | (~'if-let [~(with-meta o# {:tag 'UnityEngine.GameObject}) (~'hard.gobpool/-reuse ~pool)] 69 | (if (~'arcadia.core/null-obj? ~o#) (~sym) 70 | (do ~@(reuse-prep o#) ~o#)) 71 | (let [~o# (~'hard.gobpool/-tag-clone (~'arcadia.core/instantiate ~gob) ~(str type-sym))] 72 | (do ~@(reuse-prep o#) ~o#)))) 73 | ~(mapv keyword [pool sym return])))) 74 | -------------------------------------------------------------------------------- /input.clj: -------------------------------------------------------------------------------- 1 | (ns hard.input 2 | (:import 3 | [UnityEngine Input KeyCode Camera Physics Time Camera Ray RaycastHit])) 4 | 5 | (def ^:private axis-cache (atom [0 0])) 6 | 7 | (declare mouse?) 8 | 9 | (defn get-keycode [s] 10 | (try (or (eval (symbol (str "KeyCode/" s))) false) (catch Exception e nil))) 11 | 12 | (defn ^:private kcode* [k] 13 | (cond 14 | (keyword? k) (apply str (rest (str k))) 15 | (symbol? k) (get-keycode k) 16 | (string? k) k)) 17 | 18 | (defn key-down? [k] 19 | (Input/GetKeyDown (kcode* k))) 20 | 21 | (defn key? [k] 22 | (Input/GetKey (kcode* k))) 23 | 24 | (defn key-up? [k] 25 | (Input/GetKeyUp (kcode* k))) 26 | 27 | (defn button? [s] 28 | (Input/GetButton s)) 29 | 30 | (defn button-up? [s] 31 | (Input/GetButtonUp s)) 32 | 33 | (defn button-down? [s] 34 | (Input/GetButtonDown s)) 35 | 36 | (defmacro route [f & more] 37 | (let [pairs (partition 2 more)] 38 | (cons 'do 39 | (for [[k code] pairs] 40 | `(if (~f ~k) ~code) )))) 41 | 42 | 43 | 44 | (defn ^:private mouse-code* [b] 45 | (cond (#{0 1 2} b) b 46 | :else (or (get {:left 0 :middle 1 :right 2} b) 0))) 47 | 48 | (defn mouse-down? 49 | ([] (mouse-down? 0)) 50 | ([b] (Input/GetMouseButtonDown (mouse-code* b)))) 51 | 52 | (defn mouse-up? 53 | ([] (mouse-up? 0)) 54 | ([b] (Input/GetMouseButtonUp (mouse-code* b)))) 55 | 56 | (defn mouse? 57 | ([] (mouse? 0)) 58 | ([b] (Input/GetMouseButton (mouse-code* b)))) 59 | 60 | 61 | (defn mouse-pos [] 62 | (let [pos (Input/mousePosition)] 63 | [(.x pos) (.y pos)])) 64 | 65 | 66 | (defn get-axis [k] 67 | (case k 68 | :horizontal (Input/GetAxis "Horizontal") 69 | "horizontal" (Input/GetAxis "Horizontal") 70 | :vertical (Input/GetAxis "Vertical") 71 | "vertical" (Input/GetAxis "Vertical" 72 | :mouse-x (Input/GetAxis "Mouse X") 73 | "Mouse X" (Input/GetAxis "Mouse X") 74 | :mouse-y (Input/GetAxis "Mouse Y") 75 | "Mouse Y" (Input/GetAxis "Mouse Y")))) 76 | 77 | (defn mouse-ray [] 78 | (.ScreenPointToRay (Camera/main) (Input/mousePosition))) 79 | 80 | (defn ray-hit 81 | ([ray] (ray-hit ray 10000.0)) 82 | ([^Ray ray ^double length ] 83 | (let [hit (RaycastHit.)] 84 | (Physics/Raycast (.origin ray) (.direction ray) length)))) 85 | 86 | (defn ray-hits 87 | ([ray] (ray-hits ray 1000.0)) 88 | ([^Ray ray ^double length ] 89 | (let [hit (RaycastHit.)] 90 | (Physics/RaycastAll (.origin ray) (.direction ray) length)))) 91 | 92 | 93 | (defn joy [] 94 | [(get-axis :horizontal) 95 | (get-axis :vertical)]) 96 | 97 | (defn joy-left? [] 98 | (< (get-axis :horizontal) -0.3)) 99 | 100 | (defn joy-right? [] 101 | (> (get-axis :horizontal) 0.3)) 102 | 103 | (defn joy-up? [] 104 | (> (get-axis :vertical) 0.3)) 105 | 106 | (defn joy-down? [] 107 | (< (get-axis :vertical) -0.3)) 108 | 109 | 110 | -------------------------------------------------------------------------------- /math.clj: -------------------------------------------------------------------------------- 1 | (ns hard.math 2 | (:refer-clojure :exclude [update]) 3 | (:use arcadia.linear) 4 | (:import [UnityEngine Debug Gizmos Vector3 Color Time Mathf])) 5 | 6 | 7 | ;;catmull rom by nasser 8 | (defn spline 9 | ([t ps] 10 | (let [i (int t) 11 | t (- t i)] 12 | (spline t 13 | (nth ps i) 14 | (nth ps (+ i 1)) 15 | (nth ps (+ i 2)) 16 | (nth ps (+ i 3))))) 17 | ([t p0 p1 p2 p3] 18 | (let [a (v3* (v3* p1 2) 0.5) 19 | b (v3* (v3- p2 p0) 0.5) 20 | c (v3* (v3+ (v3* p0 2) 21 | (v3* p1 -5) 22 | (v3* p2 4) 23 | (v3* p3 -1)) 24 | 0.5) 25 | d (v3* (v3+ (v3* p0 -1) 26 | (v3* p1 3) 27 | (v3* p2 -3) 28 | p3) 29 | 0.5)] 30 | (v3+ a 31 | (v3* b t) 32 | (v3* c (Mathf/Pow t 2)) 33 | (v3* d (Mathf/Pow t 3)))))) -------------------------------------------------------------------------------- /mesh.clj: -------------------------------------------------------------------------------- 1 | (ns hard.mesh 2 | (:import 3 | [UnityEngine Color])) 4 | 5 | (defn gobj? [x] (instance? UnityEngine.GameObject x)) 6 | 7 | (defn vertices [^UnityEngine.GameObject gob] 8 | (.vertices (.mesh (.GetComponent gob UnityEngine.MeshFilter)))) 9 | 10 | (defn vertices! [^UnityEngine.GameObject gob ^UnityEngine.Vector3|[]| ar] 11 | (set! (.vertices (.mesh (.GetComponent gob UnityEngine.MeshFilter))) ar)) 12 | 13 | (defn vertex-color! [gob col] 14 | (when (gobj? gob) 15 | (when-let [meshfilter (.GetComponent gob UnityEngine.MeshFilter)] 16 | (let [mesh (.sharedMesh meshfilter) 17 | verts (.vertices mesh) 18 | colors (into-array (take (count verts) (repeat col)))] 19 | (set! (.colors mesh) colors) nil)))) 20 | 21 | 22 | (defn vertex-colors! [gob c] 23 | (when (gobj? gob) 24 | (when-let [meshfilter (.GetComponent gob UnityEngine.MeshFilter)] 25 | (let [mesh (.mesh meshfilter) 26 | verts (.vertices mesh) 27 | fn (cond (fn? c) c 28 | :else (fn [_ _ _ _] c)) 29 | colors (into-array (doall 30 | (for [idx (range (count verts)) 31 | :let [v (.GetValue verts idx) 32 | x (.x v) 33 | y (.y v) 34 | z (.z v)]] 35 | (fn x y z idx))))] 36 | (set! (.colors mesh) colors) 37 | (count colors) )))) 38 | 39 | (defn map-mesh-set! [o f] 40 | (let [mf (.GetComponent o UnityEngine.MeshFilter) 41 | vs (.. mf mesh vertices)] 42 | (set! (.vertices (.mesh mf)) 43 | (into-array (vec (for [i (range (count vs))] (f i (get (.vertices (.mesh mf)) i)))))) 44 | (.RecalculateNormals (.mesh mf)) 45 | ;TODO recalc bounds 46 | true)) 47 | 48 | (defn vcol-fn-normals [o f] 49 | (let [mf (.GetComponent o UnityEngine.MeshFilter)] 50 | (set! (.colors (.mesh mf)) 51 | (into-array (vec (for [i (range (count (.colors (.mesh mf))))] (f i (get (.normals (.mesh mf)) i)))))) 52 | true)) -------------------------------------------------------------------------------- /physics.clj: -------------------------------------------------------------------------------- 1 | (ns hard.physics 2 | (:use arcadia.linear) 3 | (:import 4 | [UnityEngine Mathf Vector3 Ray Physics RaycastHit Physics2D LayerMask])) 5 | 6 | (defn gob? [x] (instance? UnityEngine.GameObject x)) 7 | 8 | (defn mask [n] 9 | (int (bit-shift-left 1 (if (string? n) (LayerMask/NameToLayer n) n)))) 10 | 11 | '(LayerMask/GetMask (into-array System.String ["player"])) 12 | 13 | (defn set-mask! [o n] 14 | (let [m (int (if (string? n) (LayerMask/NameToLayer n) n)) 15 | ^UnityEngine.Transform|[]| ts (.GetComponentsInChildren o UnityEngine.Transform)] 16 | (run! 17 | #(set! (.layer (.gameObject %)) m) ts))) 18 | 19 | (def ^:private hit-buff (make-array UnityEngine.RaycastHit 200)) 20 | 21 | (defn ^System.Single raycast-non-alloc [ 22 | ^Vector3 origin 23 | ^Vector3 direction 24 | ^|UnityEngine.RaycastHit[]| results 25 | ^System.Double len] 26 | (Physics/RaycastNonAlloc origin direction results len)) 27 | 28 | 29 | (defn- hit* 30 | {:inline-arities #{2 3} 31 | :inline 32 | (fn 33 | ([a b] `(raycast-non-alloc ~a ~b hit-buff Mathf/Infinity)) 34 | ([a b c] `(raycast-non-alloc ~a ~b hit-buff ~c)))} 35 | ([^Vector3 a ^Vector3 b] 36 | (raycast-non-alloc a b hit-buff Mathf/Infinity)) 37 | ([^Vector3 a ^Vector3 b ^System.Double c] 38 | (raycast-non-alloc a b hit-buff c))) 39 | 40 | (def zero-long (long 0)) 41 | 42 | (defn hit 43 | ([^Vector3 a ^Vector3 b] 44 | (if (> (hit* a b) 0) (aget hit-buff 0))) 45 | ([^Vector3 a ^Vector3 b ^System.Double c] 46 | (if (> (hit* a b c) 0) (aget hit-buff 0))) 47 | ([^Vector3 a ^Vector3 b ^System.Double c d] 48 | (if (> (Physics/RaycastNonAlloc a b hit-buff c d) zero-long) (aget hit-buff zero-long)))) 49 | 50 | (defn hits 51 | ([^Vector3 a ^Vector3 b] 52 | (map #(aget hit-buff %) (range (hit* a b)))) 53 | ([^Vector3 a ^Vector3 b ^System.Double c] 54 | (map #(aget hit-buff %) (range (hit* a b c)))) 55 | ([^Vector3 a ^Vector3 b ^System.Double c d] 56 | (map #(aget hit-buff %) (range (Physics/RaycastNonAlloc a b hit-buff c d))))) 57 | 58 | 59 | 60 | (defn gravity [] (Physics/gravity)) 61 | 62 | (defn gravity! [v3] (set! (Physics/gravity) v3)) 63 | 64 | (defn rigidbody? [o] (instance? UnityEngine.Rigidbody o)) 65 | 66 | (defn ^UnityEngine.Rigidbody ->rigidbody [^UnityEngine.GameObject o] 67 | (.GetComponent o UnityEngine.Rigidbody)) 68 | 69 | (defn ->rigidbody2d [v] 70 | (if-let [o (.gameObject v)] (.GetComponent o UnityEngine.Rigidbody2D) nil)) 71 | 72 | (defn force! [body x y z] (.AddRelativeForce body x y z)) 73 | (defn global-force! [body x y z] (.AddForce body x y z)) 74 | (defn torque! [body x y z] (.AddRelativeTorque body x y z)) 75 | (defn global-torque! [body x y z] (.AddTorque body x y z)) 76 | (defn kinematic! [go v] (set! (.isKinematic (->rigidbody go)) v)) 77 | 78 | (defn force2d! [body x y] (.AddRelativeForce body (v2 x y))) 79 | (defn global-force2d! [^UnityEngine.Rigidbody2D body x y] (.AddForce body (v2 x y))) 80 | (defn torque2d! [^UnityEngine.Rigidbody2D body r] (.AddTorque body (float r)) nil) 81 | 82 | (defn ->velocity [o] 83 | (if-let [body (cond (rigidbody? o) o (gob? o) (->rigidbody o))] 84 | (.velocity body))) 85 | 86 | (defn layer-mask [& s] 87 | (short (UnityEngine.LayerMask/GetMask (into-array s)))) 88 | 89 | (defn overlap-circle 90 | ([p r] (Physics2D/OverlapCircle p (float r))) 91 | ([p r m] (Physics2D/OverlapCircle p (float r) m) )) 92 | 93 | (defn overlap-sphere 94 | ([p r] (Physics/OverlapSphere p (float r))) 95 | ([p r m] (Physics/OverlapSphere p (float r) m) )) -------------------------------------------------------------------------------- /seed.clj: -------------------------------------------------------------------------------- 1 | (ns hard.seed 2 | (:import [UnityEngine] [Hard PerlinNoise])) 3 | 4 | (defn seed! [v] (set! UnityEngine.Random/seed (hash v))) 5 | 6 | (defn srand 7 | ([] UnityEngine.Random/value) 8 | ([n] (* n (srand)))) 9 | 10 | (defn srand-int [n] (int (* (srand) n))) 11 | 12 | (defn srand-nth [col] (get col (srand-int (count col)))) 13 | 14 | (defn sshuffle [col] (sort-by (fn [_](srand)) col)) 15 | 16 | ;https://gist.github.com/nasser/de0ddaead927dfa5261b 17 | (defmacro schance [& body] 18 | (let [parts (partition 2 body) 19 | total (apply + (map first parts)) 20 | rsym (gensym "random_") 21 | clauses (->> parts 22 | (sort-by first (comparator >)) 23 | (reductions 24 | (fn [[odds-1 _] 25 | [odds-2 expr-2]] 26 | [(+ odds-1 (/ odds-2 total)) expr-2]) 27 | [0 nil]) 28 | rest 29 | (mapcat 30 | (fn [[odds expr]] 31 | [(or (= 1 odds) `(< ~rsym ~odds)) 32 | expr])))] 33 | `(let [~rsym (srand)] 34 | (cond ~@clauses)))) 35 | 36 | 37 | (defn srand-vec [& more] 38 | (mapv (fn [col] 39 | (cond (number? col) (srand col) 40 | (sequential? col) 41 | (case (count col) 42 | 0 (srand) 43 | 1 (srand (first col)) 44 | 2 (+ (srand (apply - (reverse col))) (first col)) 45 | (srand) 46 | :else (srand)))) more)) 47 | 48 | 49 | (defn noise* 50 | ([] (noise* 0 {})) 51 | ([seed] (noise* seed {})) 52 | ([seed opts] 53 | (let [i (PerlinNoise. (hash seed)) 54 | {:keys [in out]} opts 55 | nf (fn [v] (.Noise i (double (.x v)) (double (.y v) ) (double (.z v))))] 56 | (apply comp (filter fn? [out nf in]))))) 57 | 58 | (defn harmonic [f mags f2] (fn [v] (reduce f2 (map #(f (UnityEngine.Vector3/op_Multiply v %)) mags)))) 59 | 60 | (defn list-reduce [a b] (if (seq? a) (cons b a) (list b a))) 61 | 62 | 63 | -------------------------------------------------------------------------------- /sound.clj: -------------------------------------------------------------------------------- 1 | (ns hard.sound 2 | (use 3 | arcadia.core) 4 | (import [UnityEngine GameObject Application])) 5 | 6 | 7 | (def audio-clips 8 | (if (. Application isPlaying) 9 | (into {} (mapv (juxt #(.name %) identity) 10 | (UnityEngine.Resources/FindObjectsOfTypeAll UnityEngine.AudioClip))))) 11 | 12 | (defn play-clip! 13 | ([k] (play-clip! k {})) 14 | ([k opts] 15 | (when-let [clip (get audio-clips k)] 16 | (let [idle-source 17 | (or (first (remove #(.isPlaying %) 18 | (UnityEngine.Resources/FindObjectsOfTypeAll UnityEngine.AudioSource))) 19 | (.AddComponent (GameObject. "sound") UnityEngine.AudioSource))] 20 | (assert idle-source) 21 | (when idle-source (set! (.clip idle-source) clip) 22 | (if (:volume opts) (set! (.volume idle-source) (float (:volume opts)))) 23 | (.Play idle-source)))))) 24 | 25 | (defn play-clip [o s] 26 | (let [clip (UnityEngine.Resources/Load s) 27 | source (cmpt o UnityEngine.AudioSource)] 28 | (set! (.volume source) (float 2.0)) 29 | (set! (.clip source) clip) 30 | (.Play source) 31 | (.length clip))) --------------------------------------------------------------------------------