├── .gitignore ├── Editor ├── UnityRandomEditorDraw.cs └── UnityRandomEditorWindow.cs ├── Example.unity ├── ExampleFiles ├── ExampleUnityRandom.cs └── RotateAround.cs ├── README.pdf ├── README.textile ├── Samples └── .gitkeep ├── UnityRandom.cs └── lib ├── DiceRoll.cs ├── ExponentialDistribution.cs ├── GammaDistribution.cs ├── MersenneTwister.cs ├── NormalDistribution.cs ├── PoissonDistribution.cs ├── PowerLaw.cs ├── RandomCube.cs ├── RandomDisk.cs ├── RandomSphere.cs ├── RandomSquare.cs ├── ShuffleBagCollection.cs ├── SpecialFunctions.cs └── WaveToRgb.cs /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Samples/*.txt 3 | 4 | -------------------------------------------------------------------------------- /Editor/UnityRandomEditorDraw.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System; 4 | using System.Collections; 5 | using System.Text; 6 | using System.IO; 7 | using URandom; 8 | 9 | public class UnityRandomEditorDraw 10 | { 11 | public static Texture2D aaLineTex = null; 12 | public static Texture2D lineTex = null; 13 | public static Texture2D tex = null; 14 | 15 | public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width, bool antiAlias) 16 | { 17 | Color savedColor = GUI.color; 18 | Matrix4x4 savedMatrix = GUI.matrix; 19 | 20 | if (!lineTex) 21 | { 22 | lineTex = new Texture2D(1, 1, TextureFormat.ARGB32, true); 23 | lineTex.SetPixel(0, 1, Color.white); 24 | lineTex.Apply(); 25 | } 26 | 27 | if (!aaLineTex) 28 | { 29 | aaLineTex = new Texture2D(1, 3, TextureFormat.ARGB32, true); 30 | aaLineTex.SetPixel(0, 0, new Color(1, 1, 1, 0)); 31 | aaLineTex.SetPixel(0, 1, Color.white); 32 | aaLineTex.SetPixel(0, 2, new Color(1, 1, 1, 0)); 33 | aaLineTex.Apply(); 34 | } 35 | 36 | if (antiAlias) width *= 3; 37 | 38 | float angle = Vector3.Angle(pointB - pointA, Vector2.right) * (pointA.y <= pointB.y?1:-1); 39 | 40 | float m = (pointB - pointA).magnitude; 41 | 42 | if (m > 0.01f) 43 | { 44 | Vector3 dz = new Vector3(pointA.x, pointA.y, 0); 45 | 46 | GUI.color = color; 47 | GUI.matrix = translationMatrix(dz) * GUI.matrix; 48 | GUIUtility.ScaleAroundPivot(new Vector2(m, width), new Vector3(-0.5f, 0, 0)); 49 | GUI.matrix = translationMatrix(-dz) * GUI.matrix; 50 | GUIUtility.RotateAroundPivot(angle, Vector2.zero); 51 | GUI.matrix = translationMatrix(dz + new Vector3(width / 2, -m / 2) * Mathf.Sin(angle * Mathf.Deg2Rad)) * GUI.matrix; 52 | 53 | if (!antiAlias) 54 | GUI.DrawTexture(new Rect(0, 0, 1, 1), lineTex); 55 | else 56 | GUI.DrawTexture(new Rect(0, 0, 1, 1), aaLineTex); 57 | } 58 | GUI.matrix = savedMatrix; 59 | GUI.color = savedColor; 60 | } 61 | 62 | private static Matrix4x4 translationMatrix(Vector3 v) 63 | { 64 | return Matrix4x4.TRS(v,Quaternion.identity,Vector3.one); 65 | } 66 | 67 | public static void DrawXYPlot(ArrayList rlist, int width, int height) 68 | { 69 | DrawXYPoints(rlist, 0, 1, width, height); 70 | } 71 | 72 | public static void DrawXYPlot(ArrayList rlist, int width, int height, bool scale) 73 | { 74 | // SCALE 75 | float _min, _max; 76 | if (scale) { 77 | _min = Convert.ToSingle(rlist[0]); 78 | _max = Convert.ToSingle(rlist[rlist.Count - 1]); 79 | } else { 80 | _min = 0; 81 | _max = 1; 82 | } 83 | DrawXYPoints(rlist, _min, _max, width, height); 84 | } 85 | 86 | public static void DrawXYPlot(ArrayList rlist, int width, int height, float min, float max) 87 | { 88 | DrawXYPoints(rlist, min, max, width, height); 89 | } 90 | 91 | private static void DrawXYPoints(ArrayList rlist, float _min, float _max, int width, int height) 92 | { 93 | int counter = 0; 94 | foreach ( object obj in rlist ) 95 | { 96 | counter++; 97 | float x, y, val; 98 | val = Convert.ToSingle(obj); 99 | val = ( (val - _min) / (_max - _min) ); 100 | y = val * height; 101 | x = counter * (Convert.ToSingle(width) / rlist.Count); 102 | DrawPoint(new Vector2(x,y)); 103 | } 104 | } 105 | 106 | public static void DrawV3Plot(ArrayList rlist, int width, int height, UnityRandomEditorWindow.RandomVector3DType _type, float alpha, float beta) 107 | { 108 | foreach ( object obj in rlist ) 109 | { 110 | Vector2 _pos = MapTo2D( (Vector3) obj, alpha, beta); // rotation (alpha,beta) 111 | // move from space -1 - 1 to space 0-1 112 | _pos = ((_pos + Vector2.one) * 0.5f); 113 | DrawPoint( Vector2.Scale(_pos, new Vector2(width, height))); 114 | } 115 | } 116 | 117 | private static Vector2 MapTo2D(Vector3 pos, float a, float b) 118 | { 119 | // MAP a 3D point in a 2D space (a and b gives you the rotation) 120 | float ca = (float) Math.Cos(a); float sa = (float) Math.Sin(a); 121 | float cb = (float) Math.Cos(b); float sb = (float) Math.Sin(b); 122 | float xx = ((pos.x * ca) + (pos.y*sa))*cb + pos.z*sb; 123 | float yy = (pos.y*ca) - (pos.x*sa); 124 | return new Vector2(xx,yy); 125 | } 126 | 127 | public static void DrawV2Plot(ArrayList rlist, int width, int height, UnityRandomEditorWindow.RandomVector2DType _type) 128 | { 129 | foreach ( object obj in rlist ) 130 | { 131 | Vector2 pos = ((Vector2) obj + Vector2.one) * 0.5f; 132 | switch (_type) { 133 | case UnityRandomEditorWindow.RandomVector2DType.SQUARE: 134 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height)) ); 135 | break; 136 | case UnityRandomEditorWindow.RandomVector2DType.CIRCLE: 137 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height) ) ); 138 | break; 139 | case UnityRandomEditorWindow.RandomVector2DType.DISK: 140 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height) ) ); 141 | break; 142 | default: 143 | break; 144 | } 145 | } 146 | } 147 | 148 | private static void DrawPoint(Vector2 pos) 149 | { 150 | // 1. make a Cross around zero 151 | Vector2 _pointA = new Vector2(0.0f,-1.0f); 152 | Vector2 _pointB = new Vector2(0.0f,1.0f); 153 | Vector2 _pointC = new Vector2(1.0f,0.0f); 154 | Vector2 _pointD = new Vector2(-1.0f,0.0f); 155 | 156 | // 2. move the cross into place 157 | // Y: value 158 | // X: Position 159 | Vector2 _a = _pointA + pos; 160 | Vector2 _b = _pointB + pos; 161 | Vector2 _c = _pointC + pos; 162 | Vector2 _d = _pointD + pos; 163 | 164 | UnityRandomEditorDraw.DrawLine(_a,_b,Color.blue,1.0f,true); 165 | UnityRandomEditorDraw.DrawLine(_c,_d,Color.blue,1.0f,true); 166 | } 167 | 168 | public static void DrawColorPlot(ArrayList rlist, int width, int height) 169 | { 170 | float x,y; 171 | x = y = 0.0f; 172 | float grid_space = 25.0f; 173 | if (!tex) { 174 | tex = new Texture2D(1,1,TextureFormat.ARGB32,false); 175 | } 176 | // make a simple grid 177 | foreach ( object obj in rlist ) 178 | { 179 | Vector2 a = new Vector2(x,y); 180 | Vector2 b = new Vector2((x+grid_space),y); 181 | Vector2 c = new Vector2(x,(y+grid_space)); 182 | Vector2 d = new Vector2((x+grid_space),(y+grid_space)); 183 | DrawPoint(a); 184 | DrawPoint(b); 185 | DrawPoint(c); 186 | DrawPoint(d); 187 | 188 | // make a new texture with the color 189 | tex.SetPixel(0, 1, (Color) obj); 190 | tex.Apply(); 191 | GUI.DrawTexture(new Rect(a.x,a.y,grid_space,grid_space), tex); 192 | 193 | if (x < (width - grid_space)) { 194 | x += grid_space; 195 | } else { 196 | x = 0; 197 | y += grid_space; 198 | } 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Editor/UnityRandomEditorWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using System.IO; 9 | 10 | using URandom; 11 | 12 | public class UnityRandomEditorWindow : EditorWindow { 13 | 14 | #region Attributes 15 | 16 | float[] shufflebag = {1,2,3,4,5,6,7,8,9,10}; 17 | Dictionary wshufflebag; 18 | 19 | float alpha = 0; 20 | float beta = 0; 21 | bool rotation = false; 22 | 23 | int _graph_area_width = 500; 24 | int _graph_area_height = 500; 25 | int _area_margin = 10; 26 | int _editor_area_width = 400; 27 | int _editor_area_height = 400; 28 | 29 | int _range_min = 0; 30 | int _range_max = Int32.MaxValue; 31 | 32 | bool transform = false; 33 | int samplig_size = 500; 34 | int max_samplig_size = 10000; // depend on the type 35 | float temperature = 5.0f; 36 | 37 | int seed; 38 | string stringSeed = Int32.MaxValue.ToString(); 39 | 40 | // FOR CAP AND RING 41 | float spotAngle = 20.0f; 42 | float innerAngle = 20.0f; 43 | float outerAngle = 60.0f; 44 | ArrayList randomList; 45 | String filename = "sampling.txt"; 46 | private String path; 47 | StreamWriter fileWriter = null; 48 | 49 | // GENERAL TYPE 50 | public enum RandomType 51 | { 52 | NUMBER = 1, 53 | VECTOR_2D = 2, 54 | VECTOR_3D = 3, 55 | COLOR = 4, 56 | DICE = 5, 57 | SHUFFLEBAG = 6, 58 | WEIGHTEDBAG = 7 59 | } 60 | private RandomType _randomType = RandomType.NUMBER; 61 | 62 | // TYPE OF RANDOM FLOAT NUMBER 63 | public enum RandomNumberType 64 | { 65 | VALUE = 0, 66 | RANGE = 1, 67 | POISSON = 2, 68 | EXPONENTIAL = 3, 69 | GAMMA = 4 70 | } 71 | private RandomNumberType _randomNumberType = RandomNumberType.VALUE; 72 | 73 | // TYPE OF RANDOM VECTOR 2D 74 | public enum RandomVector2DType 75 | { 76 | SQUARE = 0, 77 | CIRCLE = 1, 78 | DISK = 2 79 | } 80 | private RandomVector2DType _randomVector2DType = RandomVector2DType.SQUARE; 81 | 82 | // TYPE OF RANDOM VECTOR 3D 83 | public enum RandomVector3DType 84 | { 85 | INCUBE = 0, 86 | ONCUBE = 1, 87 | INSPHERE = 2, 88 | ONSPHERE = 3, 89 | ONCAP = 4, 90 | ONRING = 5 91 | } 92 | private RandomVector3DType _randomVector3DType = RandomVector3DType.ONSPHERE; 93 | 94 | // THIS IS THE NORMALIZATION FOR UnityRandom Class 95 | private UnityRandom.Normalization normalization = UnityRandom.Normalization.STDNORMAL; 96 | 97 | // THIS IS THE DICE TYPE 98 | private DiceRoll.DiceType dice = DiceRoll.DiceType.D6; 99 | private int nroll = 1; 100 | 101 | #endregion 102 | 103 | 104 | #region Init,Update,OnGUI 105 | // Add menu named "Unity Random" to the Window menu 106 | [MenuItem ("Window/Unity Random")] 107 | static void Init () 108 | { 109 | // Get existing open window or if none, make a new one: 110 | UnityRandomEditorWindow window = (UnityRandomEditorWindow)EditorWindow.GetWindow(typeof (UnityRandomEditorWindow), false, "UNITY RANDOM"); 111 | window.Show(); 112 | } 113 | 114 | // Update 115 | void Update() 116 | { 117 | if (rotation) 118 | { 119 | // NAIF ROTATION 120 | alpha += Time.deltaTime * 500; 121 | beta += Time.deltaTime * 500; 122 | this.Repaint(); 123 | } 124 | } 125 | 126 | // OnGUI 127 | void OnGUI() 128 | { 129 | // SAMPLING SIZE 130 | switch (_randomType) { 131 | case RandomType.NUMBER: max_samplig_size = 10000; break; 132 | case RandomType.VECTOR_2D: max_samplig_size = 5000; break; 133 | case RandomType.VECTOR_3D: max_samplig_size = 1000; break; 134 | case RandomType.COLOR: max_samplig_size = 400; break; 135 | case RandomType.DICE: max_samplig_size = 5000; break; 136 | default: max_samplig_size = 5000; break; 137 | } 138 | // ADJUST CURRENT SIZE 139 | if (samplig_size > max_samplig_size) samplig_size = max_samplig_size; 140 | 141 | // DRAWING AREA 142 | GUILayout.BeginArea(new Rect(_area_margin,_area_margin,_graph_area_width, _graph_area_height)); 143 | GUILayout.Box("", GUILayout.Width(_graph_area_width), GUILayout.Height(_graph_area_height)); 144 | if (randomList != null && randomList.Count > 0) { 145 | switch (_randomType) { 146 | case RandomType.NUMBER: 147 | switch (_randomNumberType) { 148 | case RandomNumberType.VALUE: 149 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height); 150 | break; 151 | case RandomNumberType.RANGE: 152 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, _range_min, _range_max); 153 | break; 154 | default: 155 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, true); 156 | break; 157 | } 158 | break; 159 | case RandomType.VECTOR_2D: 160 | UnityRandomEditorDraw.DrawV2Plot(randomList, _graph_area_width, _graph_area_height, _randomVector2DType); 161 | break; 162 | case RandomType.VECTOR_3D: 163 | UnityRandomEditorDraw.DrawV3Plot(randomList, _graph_area_width, _graph_area_height, _randomVector3DType, alpha, beta); 164 | break; 165 | case RandomType.COLOR: 166 | UnityRandomEditorDraw.DrawColorPlot(randomList, _graph_area_width, _graph_area_height); 167 | break; 168 | case RandomType.DICE: 169 | // generate a new ArrayList with the Sum, then send to DrawXYPlot 170 | ArrayList sums = RandomDiceSums(); 171 | sums.Sort(); 172 | UnityRandomEditorDraw.DrawXYPlot(sums, _graph_area_width, _graph_area_height, true); 173 | break; 174 | case RandomType.SHUFFLEBAG: 175 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, shufflebag[0], shufflebag[shufflebag.Length - 1]); 176 | break; 177 | case RandomType.WEIGHTEDBAG: 178 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, 1, 10); 179 | break; 180 | default: 181 | // defailt is no drawing 182 | break; 183 | } 184 | } 185 | GUILayout.EndArea(); 186 | 187 | // SAMPLE RANDOM BUTTON 188 | GUILayout.BeginArea(new Rect(_area_margin, _area_margin + _area_margin + _graph_area_height, _graph_area_width, 60)); 189 | EditorGUILayout.BeginHorizontal(); 190 | if (GUILayout.Button("Generate Random Numbers",GUILayout.Height(60))) { 191 | this.SampleRandom(); 192 | } 193 | EditorGUILayout.EndHorizontal(); 194 | GUILayout.EndArea(); 195 | 196 | // CONTROL PANEL RIGHT BOX 197 | GUILayout.BeginArea(new Rect(_area_margin + _area_margin +_graph_area_width, _area_margin, _editor_area_width, _editor_area_height)); 198 | 199 | // TITLE 200 | EditorGUILayout.BeginVertical("box"); 201 | EditorGUILayout.BeginHorizontal(); 202 | GUILayout.FlexibleSpace(); 203 | GUILayout.Label("CHOOSE TYPE OF RANDOM TYPE: "); 204 | _randomType = (RandomType) EditorGUILayout.EnumPopup(_randomType, GUILayout.Width(100)); 205 | GUILayout.FlexibleSpace(); 206 | EditorGUILayout.EndHorizontal(); 207 | EditorGUILayout.EndVertical(); 208 | 209 | switch (_randomType) { 210 | 211 | case RandomType.NUMBER: RandomNumbersGUI(); 212 | break; 213 | 214 | case RandomType.VECTOR_2D: RandomVector2DGUI(); 215 | break; 216 | 217 | case RandomType.VECTOR_3D: RandomVector3DGUI(); 218 | break; 219 | 220 | case RandomType.COLOR: RandomColorGUI(); 221 | break; 222 | 223 | case RandomType.DICE: RandomDiceGUI(); 224 | break; 225 | 226 | case RandomType.SHUFFLEBAG: ShuffleBagGUI(); 227 | break; 228 | 229 | case RandomType.WEIGHTEDBAG: ShuffleBagGUI(); 230 | break; 231 | 232 | default: 233 | break; 234 | } 235 | 236 | EditorGUILayout.BeginVertical("box"); 237 | samplig_size = EditorGUILayout.IntSlider ("Sampling Size:", samplig_size, 1, max_samplig_size); 238 | EditorGUILayout.EndVertical(); 239 | 240 | if (randomList != null && randomList.Count > 0) { 241 | EditorGUILayout.BeginVertical("box"); 242 | EditorGUILayout.BeginHorizontal(); 243 | GUILayout.FlexibleSpace(); 244 | if (GUILayout.Button("SAVE",GUILayout.Width(100))) this.Save(); 245 | GUILayout.FlexibleSpace(); 246 | filename = EditorGUILayout.TextField(filename); 247 | EditorGUILayout.EndHorizontal(); 248 | EditorGUILayout.EndVertical(); 249 | } 250 | 251 | 252 | // 3D VIEWS BUTTONS 253 | if (randomList != null && randomList.Count > 0 && _randomType == RandomType.VECTOR_3D && 254 | (_randomVector3DType == RandomVector3DType.INSPHERE || 255 | _randomVector3DType == RandomVector3DType.ONSPHERE || 256 | _randomVector3DType == RandomVector3DType.ONCAP || 257 | _randomVector3DType == RandomVector3DType.ONRING )) { 258 | EditorGUILayout.BeginVertical("box"); 259 | String rotationLabel = rotation ? "STOP ROTATE VIEW" : "START ROTATE VIEW"; 260 | if (GUILayout.Button(rotationLabel,GUILayout.Height(60))) { 261 | rotation = !rotation; 262 | } 263 | EditorGUILayout.EndVertical(); 264 | } 265 | GUILayout.EndArea(); 266 | 267 | // if GUI has changed empty the Array 268 | if (GUI.changed && randomList != null && randomList.Count != 0) { 269 | CleanList(); 270 | this.Repaint(); 271 | } 272 | 273 | // if Array is empty stop rotation and reset alpha/beta 274 | if (randomList == null || randomList.Count == 0) { 275 | rotation = false; 276 | alpha = beta = 0; 277 | } 278 | } 279 | 280 | #endregion 281 | 282 | #region PrivateMethods 283 | private void CleanList() 284 | { 285 | // FIXME I NEED TO REMOVE OBJECTS MANUALLY? 286 | randomList.Clear(); 287 | } 288 | 289 | private ArrayList RandomDiceSums() 290 | { 291 | ArrayList result = new ArrayList(); 292 | foreach ( object obj in randomList ) 293 | { 294 | DiceRoll _roll = (DiceRoll) obj; 295 | result.Add( _roll.Sum() ); 296 | } 297 | return result; 298 | } 299 | 300 | // DICES GUI 301 | private void RandomDiceGUI() 302 | { 303 | EditorGUILayout.BeginVertical("box"); 304 | EditorGUILayout.BeginHorizontal(); 305 | GUILayout.FlexibleSpace(); 306 | GUILayout.Label("TEST RANDOM DICES"); 307 | GUILayout.FlexibleSpace(); 308 | EditorGUILayout.EndHorizontal(); 309 | EditorGUILayout.EndVertical(); 310 | 311 | SeedBoxGUI(); 312 | 313 | EditorGUILayout.BeginVertical("box"); 314 | EditorGUILayout.BeginHorizontal(); 315 | GUILayout.Label("Dice:", GUILayout.Width(100)); 316 | dice = (DiceRoll.DiceType) EditorGUILayout.EnumPopup(dice, GUILayout.Width(100)); 317 | GUILayout.FlexibleSpace(); 318 | GUILayout.Label( (nroll + dice.ToString()), GUILayout.Width(100)); 319 | EditorGUILayout.EndHorizontal(); 320 | EditorGUILayout.EndVertical(); 321 | 322 | EditorGUILayout.BeginVertical("box"); 323 | EditorGUILayout.BeginHorizontal(); 324 | GUILayout.Label("#Rolls:", GUILayout.Width(100)); 325 | nroll = EditorGUILayout.IntSlider(nroll, 0, 10); 326 | GUILayout.FlexibleSpace(); 327 | EditorGUILayout.EndHorizontal(); 328 | EditorGUILayout.EndVertical(); 329 | } 330 | 331 | // BOXSEEDCONFIGURATION 332 | private void SeedBoxGUI() 333 | { 334 | EditorGUILayout.BeginVertical("box"); 335 | EditorGUILayout.BeginHorizontal(); 336 | GUILayout.Label("RandomSeed:", GUILayout.Width(100)); 337 | stringSeed = EditorGUILayout.TextField(stringSeed, GUILayout.Width(100)); 338 | ParseSeed(); 339 | GUILayout.FlexibleSpace(); 340 | GUILayout.Label("range: +/-" + Int32.MaxValue); 341 | EditorGUILayout.EndHorizontal(); 342 | EditorGUILayout.EndVertical(); 343 | } 344 | 345 | private void ShuffleBagGUI() 346 | { 347 | EditorGUILayout.BeginVertical("box"); 348 | EditorGUILayout.BeginHorizontal(); 349 | GUILayout.FlexibleSpace(); 350 | GUILayout.Label("TEST SHUFFLE BAG"); 351 | GUILayout.FlexibleSpace(); 352 | EditorGUILayout.EndHorizontal(); 353 | EditorGUILayout.EndVertical(); 354 | SeedBoxGUI(); 355 | } 356 | 357 | private void RandomColorGUI() 358 | { 359 | EditorGUILayout.BeginVertical("box"); 360 | EditorGUILayout.BeginHorizontal(); 361 | GUILayout.FlexibleSpace(); 362 | GUILayout.Label("TEST RANDOM COLORS"); 363 | GUILayout.FlexibleSpace(); 364 | EditorGUILayout.EndHorizontal(); 365 | EditorGUILayout.EndVertical(); 366 | SeedBoxGUI(); 367 | 368 | // BOX TRANSFORMATIONS 369 | EditorGUILayout.BeginVertical("box"); 370 | EditorGUILayout.BeginHorizontal(); 371 | GUILayout.FlexibleSpace(); 372 | GUILayout.Label("TRANSFORMATIONS"); 373 | GUILayout.FlexibleSpace(); 374 | EditorGUILayout.EndHorizontal(); 375 | EditorGUILayout.EndVertical(); 376 | 377 | EditorGUILayout.BeginVertical("box"); 378 | transform = EditorGUILayout.Toggle("Transform?",transform); 379 | EditorGUILayout.EndVertical(); 380 | 381 | if (transform) NormalizationNumberTypes(); 382 | } 383 | 384 | private void RandomVector3DGUI() 385 | { 386 | EditorGUILayout.BeginVertical("box"); 387 | EditorGUILayout.BeginHorizontal(); 388 | GUILayout.FlexibleSpace(); 389 | GUILayout.Label("TEST RANDOM VECTOR3"); 390 | GUILayout.FlexibleSpace(); 391 | EditorGUILayout.EndHorizontal(); 392 | EditorGUILayout.EndVertical(); 393 | 394 | EditorGUILayout.BeginVertical("box"); 395 | EditorGUILayout.BeginHorizontal(); 396 | GUILayout.Label("Random Type:", GUILayout.Width(100)); 397 | _randomVector3DType = (RandomVector3DType) EditorGUILayout.EnumPopup(_randomVector3DType, GUILayout.Width(100)); 398 | GUILayout.FlexibleSpace(); 399 | switch (_randomVector3DType) { 400 | case RandomVector3DType.INCUBE: 401 | case RandomVector3DType.ONCUBE: 402 | GUILayout.Label("Vector3: [-1,1] r = 1"); 403 | break; 404 | case RandomVector3DType.ONSPHERE: 405 | case RandomVector3DType.INSPHERE: 406 | case RandomVector3DType.ONCAP: 407 | case RandomVector3DType.ONRING: 408 | GUILayout.Label("Vector3: [-1,1] r = 1"); 409 | break; 410 | default: 411 | break; 412 | } 413 | EditorGUILayout.EndHorizontal(); 414 | 415 | switch (_randomVector3DType) { 416 | case RandomVector3DType.ONCAP: 417 | spotAngle = EditorGUILayout.Slider ("Spot Angle:", spotAngle, 0.0f, 180.0f); 418 | break; 419 | case RandomVector3DType.ONRING: 420 | innerAngle = EditorGUILayout.Slider ("Inner Angle:", innerAngle, 0.0f, 180.0f); 421 | outerAngle = EditorGUILayout.Slider ("Outer Angle:", outerAngle, 0.0f, 180.0f); 422 | if (innerAngle > outerAngle) innerAngle = outerAngle; 423 | break; 424 | default: 425 | break; 426 | } 427 | 428 | EditorGUILayout.EndVertical(); 429 | 430 | SeedBoxGUI(); 431 | 432 | // BOX TRANSFORMATIONS 433 | EditorGUILayout.BeginVertical("box"); 434 | EditorGUILayout.BeginHorizontal(); 435 | GUILayout.FlexibleSpace(); 436 | GUILayout.Label("TRANSFORMATIONS"); 437 | GUILayout.FlexibleSpace(); 438 | EditorGUILayout.EndHorizontal(); 439 | EditorGUILayout.EndVertical(); 440 | 441 | EditorGUILayout.BeginVertical("box"); 442 | transform = EditorGUILayout.Toggle("Transform?",transform); 443 | EditorGUILayout.EndVertical(); 444 | 445 | if (transform) NormalizationNumberTypes(); 446 | } 447 | 448 | private void RandomVector2DGUI() 449 | { 450 | EditorGUILayout.BeginVertical("box"); 451 | EditorGUILayout.BeginHorizontal(); 452 | GUILayout.FlexibleSpace(); 453 | GUILayout.Label("TEST RANDOM VECTOR2"); 454 | GUILayout.FlexibleSpace(); 455 | EditorGUILayout.EndHorizontal(); 456 | EditorGUILayout.EndVertical(); 457 | 458 | EditorGUILayout.BeginVertical("box"); 459 | // TYPE 460 | EditorGUILayout.BeginHorizontal(); 461 | GUILayout.Label("Random Type:", GUILayout.Width(100)); 462 | _randomVector2DType = (RandomVector2DType) EditorGUILayout.EnumPopup(_randomVector2DType, GUILayout.Width(100)); 463 | GUILayout.FlexibleSpace(); 464 | switch (_randomVector2DType) { 465 | case RandomVector2DType.SQUARE: 466 | GUILayout.Label("Vector2: [-1,1]"); 467 | break; 468 | case RandomVector2DType.CIRCLE: 469 | GUILayout.Label("Vector2: [-1,1] r = 1"); 470 | break; 471 | case RandomVector2DType.DISK: 472 | GUILayout.Label("Vector2: [-1,1] r = 1"); 473 | break; 474 | default: 475 | break; 476 | } 477 | EditorGUILayout.EndHorizontal(); 478 | EditorGUILayout.EndVertical(); 479 | 480 | SeedBoxGUI(); 481 | 482 | // BOX TRANSFORMATIONS 483 | EditorGUILayout.BeginVertical("box"); 484 | EditorGUILayout.BeginHorizontal(); 485 | GUILayout.FlexibleSpace(); 486 | GUILayout.Label("TRANSFORMATIONS"); 487 | GUILayout.FlexibleSpace(); 488 | EditorGUILayout.EndHorizontal(); 489 | EditorGUILayout.EndVertical(); 490 | 491 | EditorGUILayout.BeginVertical("box"); 492 | transform = EditorGUILayout.Toggle("Transform?",transform); 493 | EditorGUILayout.EndVertical(); 494 | 495 | if (transform) NormalizationNumberTypes(); 496 | } 497 | 498 | private void RandomNumbersGUI() 499 | { 500 | EditorGUILayout.BeginVertical("box"); 501 | EditorGUILayout.BeginHorizontal(); 502 | GUILayout.FlexibleSpace(); 503 | GUILayout.Label("TEST RANDOM NUMBERS"); 504 | GUILayout.FlexibleSpace(); 505 | EditorGUILayout.EndHorizontal(); 506 | EditorGUILayout.EndVertical(); 507 | 508 | 509 | // BOX RANDOM NUMBER CONFIGURATION 510 | EditorGUILayout.BeginVertical("box"); 511 | // TYPE 512 | EditorGUILayout.BeginHorizontal(); 513 | GUILayout.Label("Random Type:", GUILayout.Width(100)); 514 | _randomNumberType = (RandomNumberType) EditorGUILayout.EnumPopup( _randomNumberType, GUILayout.Width(100)); 515 | // HELP TYPE 516 | GUILayout.FlexibleSpace(); 517 | if (_randomNumberType == RandomNumberType.VALUE) { 518 | GUILayout.Label("Float: 0 < x < 1"); 519 | } else { 520 | GUILayout.Label("Float: 0 < x < " + Int32.MaxValue); 521 | } 522 | EditorGUILayout.EndHorizontal(); 523 | EditorGUILayout.EndVertical(); 524 | 525 | // RANGES SLIDERS 526 | if (_randomNumberType == RandomNumberType.RANGE) 527 | { 528 | EditorGUILayout.BeginVertical("box"); 529 | GUILayout.Label("Any Int Number in range: 0 - " + Int32.MaxValue + ". Test range: 0 - 100"); 530 | EditorGUILayout.BeginHorizontal(); 531 | GUILayout.BeginVertical(); 532 | GUILayout.Label("Min:"); 533 | GUILayout.Label("Max:"); 534 | GUILayout.EndVertical(); 535 | GUILayout.BeginVertical(); 536 | _range_min = EditorGUILayout.IntSlider(_range_min, 0, 100, GUILayout.ExpandWidth(true)); 537 | _range_max = EditorGUILayout.IntSlider(_range_max, 0, 100, GUILayout.ExpandWidth(true)); 538 | if (_range_min > _range_max) _range_max = _range_min; 539 | GUILayout.EndVertical(); 540 | EditorGUILayout.EndHorizontal(); 541 | EditorGUILayout.EndVertical(); 542 | } 543 | 544 | SeedBoxGUI(); 545 | 546 | // BOX TRANSFORMATIONS 547 | switch (_randomNumberType) { 548 | case RandomNumberType.VALUE: 549 | case RandomNumberType.RANGE: 550 | EditorGUILayout.BeginVertical("box"); 551 | EditorGUILayout.BeginHorizontal(); 552 | GUILayout.FlexibleSpace(); 553 | GUILayout.Label("TRANSFORMATIONS"); 554 | GUILayout.FlexibleSpace(); 555 | EditorGUILayout.EndHorizontal(); 556 | EditorGUILayout.EndVertical(); 557 | 558 | EditorGUILayout.BeginVertical("box"); 559 | transform = EditorGUILayout.Toggle("Transform?",transform); 560 | EditorGUILayout.EndVertical(); 561 | 562 | if (transform) NormalizationNumberTypes(); 563 | break; 564 | 565 | case RandomNumberType.POISSON: 566 | EditorGUILayout.BeginVertical("box"); 567 | temperature = EditorGUILayout.Slider ("Lambda", temperature, 0.0f, 100.0f); 568 | EditorGUILayout.EndVertical(); 569 | break; 570 | 571 | case RandomNumberType.EXPONENTIAL: 572 | EditorGUILayout.BeginVertical("box"); 573 | temperature = EditorGUILayout.Slider ("Lambda", temperature, 0.0f, 10.0f); 574 | EditorGUILayout.EndVertical(); 575 | break; 576 | 577 | case RandomNumberType.GAMMA: 578 | EditorGUILayout.BeginVertical("box"); 579 | temperature = (float) EditorGUILayout.IntSlider ("Integer Order", (int) temperature, 0, 100); 580 | EditorGUILayout.EndVertical(); 581 | break; 582 | 583 | default: 584 | break; 585 | } 586 | } 587 | 588 | private void NormalizationNumberTypes() 589 | { 590 | EditorGUILayout.BeginVertical("box"); 591 | 592 | EditorGUILayout.BeginHorizontal(); 593 | GUILayout.Label("Tranformation Type:"); 594 | normalization = (UnityRandom.Normalization) EditorGUILayout.EnumPopup( normalization, GUILayout.Width(100.0f)); 595 | EditorGUILayout.EndHorizontal(); 596 | 597 | switch (normalization) { 598 | 599 | case UnityRandom.Normalization.STDNORMAL: 600 | temperature = EditorGUILayout.Slider ("Temperature", temperature, 0.0f, 10.0f); 601 | break; 602 | 603 | case UnityRandom.Normalization.POWERLAW: 604 | temperature = EditorGUILayout.Slider ("Power", temperature, 0.0f, 100.0f); 605 | break; 606 | 607 | default: 608 | Debug.LogError("Unrecognized Option"); 609 | break; 610 | } 611 | EditorGUILayout.EndVertical(); 612 | } 613 | 614 | private void SampleRandom() 615 | { 616 | Debug.Log("GENERATING RANDOM " + _randomType + " WITH SEED: " + seed); 617 | 618 | UnityRandom urand = new UnityRandom(seed); 619 | if (randomList == null) randomList = new ArrayList(); 620 | randomList.Clear(); 621 | 622 | switch (_randomType) 623 | { 624 | case RandomType.NUMBER: SampleNumber(ref urand); break; 625 | case RandomType.VECTOR_2D: SampleVector2D(ref urand); break; 626 | case RandomType.VECTOR_3D: SampleVector3D(ref urand); break; 627 | case RandomType.COLOR: SampleColor(ref urand); break; 628 | case RandomType.DICE: SampleDice(ref urand); break; 629 | case RandomType.SHUFFLEBAG: SampleShuffle(ref urand); break; 630 | case RandomType.WEIGHTEDBAG: SampleWShuffle(ref urand); break; 631 | default: SampleNumber(ref urand); break; 632 | } 633 | 634 | this.Repaint(); 635 | } 636 | 637 | private void SampleShuffle(ref UnityRandom _urand) 638 | { 639 | ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag); 640 | for (int m = 0; m < samplig_size; m++) 641 | { 642 | randomList.Add(thebag.Next()); 643 | } 644 | randomList.Sort(); 645 | } 646 | 647 | // Really no time to make it better (FIXME) 648 | private void SampleWShuffle(ref UnityRandom _urand) 649 | { 650 | wshufflebag = new Dictionary(); 651 | // fill the wshufflebag 652 | wshufflebag[1] = 5; 653 | wshufflebag[2] = 10; 654 | wshufflebag[3] = 10; 655 | wshufflebag[4] = 25; 656 | wshufflebag[5] = 25; 657 | wshufflebag[6] = 10; 658 | wshufflebag[7] = 5; 659 | wshufflebag[8] = 5; 660 | wshufflebag[9] = 3; 661 | wshufflebag[10] = 2; 662 | 663 | ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag); 664 | for (int m = 0; m < samplig_size; m++) 665 | { 666 | randomList.Add(thebag.Next()); 667 | } 668 | randomList.Sort(); 669 | } 670 | 671 | private void SampleDice(ref UnityRandom _urand) 672 | { 673 | for (int i = 0; i < samplig_size; i++) 674 | { 675 | randomList.Add( _urand.RollDice(nroll, dice)); 676 | } 677 | } 678 | 679 | private void SampleColor(ref UnityRandom _urand) 680 | { 681 | for (int i = 0; i < samplig_size; i++) 682 | { 683 | if (transform) { 684 | randomList.Add(_urand.Rainbow(normalization,temperature)); 685 | } else { 686 | randomList.Add(_urand.Rainbow()); 687 | } 688 | } 689 | } 690 | 691 | private void SampleVector3D(ref UnityRandom _urand) 692 | { 693 | for (int i = 0; i < samplig_size; i++) 694 | { 695 | switch (_randomVector3DType) { 696 | case RandomVector3DType.INCUBE: 697 | if (transform) { 698 | randomList.Add(_urand.PointInACube(normalization,temperature)); 699 | } else { 700 | randomList.Add(_urand.PointInACube()); 701 | } 702 | break; 703 | case RandomVector3DType.ONCUBE: 704 | if (transform) { 705 | randomList.Add(_urand.PointOnACube(normalization,temperature)); 706 | } else { 707 | randomList.Add(_urand.PointOnACube()); 708 | } 709 | break; 710 | case RandomVector3DType.INSPHERE: 711 | randomList.Add(_urand.PointInASphere()); 712 | break; 713 | case RandomVector3DType.ONSPHERE: 714 | randomList.Add(_urand.PointOnASphere()); 715 | break; 716 | case RandomVector3DType.ONCAP: 717 | randomList.Add(_urand.PointOnCap(spotAngle)); 718 | break; 719 | case RandomVector3DType.ONRING: 720 | randomList.Add(_urand.PointOnRing(innerAngle,outerAngle)); 721 | break; 722 | default: 723 | break; 724 | } 725 | } 726 | } 727 | 728 | private void SampleVector2D(ref UnityRandom _urand) 729 | { 730 | for (int i = 0; i < samplig_size; i++) 731 | { 732 | switch (_randomVector2DType) { 733 | case RandomVector2DType.SQUARE: 734 | if (transform) { 735 | randomList.Add(_urand.PointInASquare(normalization,temperature)); 736 | } else { 737 | randomList.Add(_urand.PointInASquare()); 738 | } 739 | break; 740 | case RandomVector2DType.CIRCLE: 741 | if (transform) { 742 | randomList.Add(_urand.PointInACircle(normalization,temperature)); 743 | } else { 744 | randomList.Add(_urand.PointInACircle()); 745 | } 746 | break; 747 | case RandomVector2DType.DISK: 748 | if (transform) { 749 | randomList.Add(_urand.PointInADisk(normalization,temperature)); 750 | } else { 751 | randomList.Add(_urand.PointInADisk()); 752 | } 753 | break; 754 | default: 755 | break; 756 | } 757 | } 758 | } 759 | 760 | private void SampleNumber(ref UnityRandom _urand) 761 | { 762 | for (int i = 0; i < samplig_size; i++) 763 | { 764 | switch (_randomNumberType) { 765 | 766 | case RandomNumberType.VALUE: 767 | if (transform) { 768 | randomList.Add(_urand.Value( normalization, temperature )); 769 | } else { 770 | randomList.Add(_urand.Value()); 771 | } 772 | break; 773 | 774 | case RandomNumberType.RANGE: 775 | if (transform) { 776 | randomList.Add(_urand.Range(_range_min, _range_max, normalization, temperature )); 777 | } else { 778 | randomList.Add(_urand.Range(_range_min, _range_max)); 779 | } 780 | break; 781 | 782 | 783 | case RandomNumberType.POISSON: 784 | randomList.Add(_urand.Possion(temperature)); 785 | break; 786 | 787 | case RandomNumberType.EXPONENTIAL: 788 | randomList.Add(_urand.Exponential(temperature)); 789 | break; 790 | 791 | case RandomNumberType.GAMMA: 792 | randomList.Add(_urand.Gamma(temperature)); 793 | break; 794 | 795 | default: 796 | break; 797 | } 798 | } 799 | randomList.Sort(); 800 | } 801 | 802 | private void Save() 803 | { 804 | path = Application.dataPath + "/UnityRandom/Samples/" + filename; 805 | Debug.Log("SAVING TO FILE: " + path); 806 | 807 | fileWriter = File.CreateText(path); 808 | 809 | foreach ( object obj in randomList ) 810 | { 811 | // FIXME SAMPLING WRITE LINE FOR Vector3 and Vector2 812 | switch (_randomType) 813 | { 814 | case RandomType.NUMBER: 815 | fileWriter.WriteLine(obj); 816 | break; 817 | case RandomType.VECTOR_2D: 818 | Vector2 pos = (Vector2) obj; 819 | fileWriter.WriteLine(pos.x + "\t" + pos.y); 820 | break; 821 | case RandomType.VECTOR_3D: 822 | Vector3 pos3 = (Vector3) obj; 823 | fileWriter.WriteLine(pos3.x + "\t" + pos3.y + "\t" + pos3.z); 824 | break; 825 | default: 826 | break; 827 | } 828 | 829 | } 830 | 831 | // when you are done writing 832 | fileWriter.Close(); 833 | 834 | UnityEngine.Object myfile = AssetDatabase.LoadMainAssetAtPath("Assets/UnityRandom/Samples/" + filename); 835 | AssetDatabase.OpenAsset(myfile); 836 | } 837 | 838 | private void ParseSeed() 839 | { 840 | checked 841 | { 842 | try 843 | { 844 | seed = int.Parse(stringSeed); 845 | } 846 | catch (System.Exception) 847 | { 848 | seed = Int32.MaxValue; 849 | stringSeed = seed.ToString(); 850 | this.Repaint(); 851 | } 852 | } 853 | } 854 | 855 | #endregion 856 | 857 | #region Events 858 | // BEWARE of TEXTURE2D MEMORY LEAKS!!!! 859 | void OnDisable() 860 | { 861 | // KILL TEXTURES 862 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.tex); 863 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.aaLineTex); 864 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.lineTex); 865 | } 866 | #endregion 867 | } 868 | -------------------------------------------------------------------------------- /Example.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tucano/UnityRandom/82d3d5565eeb322a4ed229da2d8e11b84e08d763/Example.unity -------------------------------------------------------------------------------- /ExampleFiles/ExampleUnityRandom.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class ExampleUnityRandom : MonoBehaviour 5 | { 6 | private UnityRandom urand; 7 | 8 | private bool rotate = false; 9 | public float sphereRadius = 20.0f; 10 | public int max_objects = 1000; 11 | public int seed = 123456; 12 | 13 | /* LateUpdate is called after all Update functions have been called. */ 14 | void LateUpdate () 15 | { 16 | if (Input.GetButtonDown("Jump")) { 17 | rotate = !rotate; 18 | ToggleRotation(); 19 | } 20 | } 21 | 22 | private void ToggleRotation() 23 | { 24 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 25 | foreach (GameObject item in objs) 26 | { 27 | item.GetComponent().rotating = rotate; 28 | } 29 | } 30 | 31 | // GUI 32 | void OnGUI() 33 | { 34 | GUILayout.BeginVertical("box"); 35 | 36 | GUILayout.BeginHorizontal(); 37 | GUILayout.FlexibleSpace(); 38 | GUILayout.Label("UNITYRANDOM POINT EXAMPLES"); 39 | GUILayout.FlexibleSpace(); 40 | GUILayout.EndHorizontal(); 41 | 42 | GUILayout.BeginHorizontal(); 43 | GUILayout.FlexibleSpace(); 44 | GUILayout.Label("SET A SEED: " + seed); 45 | GUILayout.FlexibleSpace(); 46 | GUILayout.EndHorizontal(); 47 | 48 | // I cut the SEED space for the GUI 49 | // Because the Slider get crazy with Int32.MaxValue (it goes back to Int.32.MinValue) 50 | seed = (int) GUILayout.HorizontalSlider(seed, 0, UnityRandom.max_seed - 1000); 51 | 52 | if (GUILayout.Button("IN SPHERE SURFACE")) ExampleInSpheres(); 53 | if (GUILayout.Button("IN CIRCLE")) ExampleInCircle(); 54 | if (GUILayout.Button("IN DISK")) ExampleInDisk(); 55 | if (GUILayout.Button("IN SPHERE VOLUME")) ExampleInSphere(); 56 | if (GUILayout.Button("IN CUBE")) ExampleInCube(); 57 | if (GUILayout.Button("ON CUBE")) ExampleOnCube(); 58 | if (GUILayout.Button("ON CAP")) ExampleOnCap(); 59 | if (GUILayout.Button("ON RING")) ExampleOnRing(); 60 | GUILayout.BeginHorizontal(); 61 | GUILayout.FlexibleSpace(); 62 | GUILayout.Label("TOGGLE ROTATION WITH JUMP"); 63 | GUILayout.FlexibleSpace(); 64 | GUILayout.EndHorizontal(); 65 | 66 | GUILayout.EndVertical(); 67 | } 68 | 69 | private void ExampleOnRing() 70 | { 71 | InitRandom(); 72 | CleanUp(); 73 | MakeObjects(); 74 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 75 | foreach (GameObject item in objs) 76 | { 77 | item.transform.position = ScalePosition(urand.PointOnRing(20.0f, 30.0f)); 78 | } 79 | } 80 | 81 | private void ExampleOnCap() 82 | { 83 | InitRandom(); 84 | CleanUp(); 85 | MakeObjects(); 86 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 87 | foreach (GameObject item in objs) 88 | { 89 | item.transform.position = ScalePosition(urand.PointOnCap(30.0f)); 90 | } 91 | } 92 | 93 | // INIT a new UnityRandom object with a random seed 94 | private void InitRandom() 95 | { 96 | urand = new UnityRandom(seed); 97 | } 98 | 99 | private void ExampleInCircle() 100 | { 101 | InitRandom(); 102 | CleanUp(); 103 | MakeObjects(); 104 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 105 | foreach (GameObject item in objs) 106 | { 107 | item.transform.position = ScalePosition(urand.PointInACircle()); 108 | } 109 | } 110 | 111 | private void ExampleInDisk() 112 | { 113 | InitRandom(); 114 | CleanUp(); 115 | MakeObjects(); 116 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 117 | foreach (GameObject item in objs) 118 | { 119 | item.transform.position = ScalePosition(urand.PointInADisk()); 120 | } 121 | } 122 | 123 | private void ExampleInSphere() 124 | { 125 | InitRandom(); 126 | CleanUp(); 127 | MakeObjects(); 128 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 129 | foreach (GameObject item in objs) 130 | { 131 | item.transform.position = ScalePosition(urand.PointInASphere()); 132 | } 133 | } 134 | 135 | private void ExampleInCube() 136 | { 137 | InitRandom(); 138 | CleanUp(); 139 | MakeObjects(); 140 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 141 | foreach (GameObject item in objs) 142 | { 143 | item.transform.position = ScalePosition(urand.PointInACube()); 144 | } 145 | } 146 | 147 | private void ExampleOnCube() 148 | { 149 | InitRandom(); 150 | CleanUp(); 151 | MakeObjects(); 152 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 153 | foreach (GameObject item in objs) 154 | { 155 | item.transform.position = ScalePosition(urand.PointOnACube()); 156 | } 157 | } 158 | 159 | private void ExampleInSpheres() 160 | { 161 | InitRandom(); 162 | CleanUp(); 163 | MakeObjects(); 164 | } 165 | 166 | private void CleanUp() 167 | { 168 | // Clear all 169 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player"); 170 | foreach (GameObject item in objs) 171 | { 172 | Destroy(item); 173 | } 174 | } 175 | 176 | private void MakeObjects() 177 | { 178 | 179 | // CENTER OF THE SPHERE: x = 0, y = 20, z = 0 I generate an object there 180 | GameObject _pivot = new GameObject(); 181 | _pivot.transform.position = new Vector3(0,sphereRadius,0); 182 | 183 | for (int i = 0; i < max_objects; i++) 184 | { 185 | // WE make a small sphere 186 | GameObject _sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); 187 | // WE SCALE THE SPHERE 188 | _sphere.transform.localScale = new Vector3(0.5f,0.5f,0.5f); 189 | // TAKE A SCALED RANDOM POSITION 190 | Vector3 pos = ScalePosition(urand.PointOnASphere()); 191 | // WE set the sphere position 192 | _sphere.transform.position = pos; 193 | // WE give a tag to the sphere 194 | _sphere.tag = "Player"; 195 | // Attach the rotation script 196 | RotateAround _ra = _sphere.AddComponent(); 197 | // SET the PIVOT POINT IN SCRIPT 198 | _ra.pivotPoint = _pivot.transform; 199 | // SET the MATERIAL as a RANDOM COLOR 200 | _sphere.renderer.material.color = urand.Rainbow(); 201 | } 202 | } 203 | 204 | // CAN BE ADDED IN THE LIBRARY??? FIXME 205 | private Vector3 ScalePosition(Vector3 pos) 206 | { 207 | // WE scale TO 20,20,20 208 | pos = Vector3.Scale(pos, new Vector3(sphereRadius,sphereRadius,sphereRadius)); 209 | // WE move UP 210 | pos = pos + new Vector3(0,sphereRadius,0); 211 | return pos; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /ExampleFiles/RotateAround.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class RotateAround : MonoBehaviour { 5 | 6 | public Transform pivotPoint; 7 | public bool rotating = true; 8 | 9 | void Start() 10 | { 11 | if (!pivotPoint) 12 | Debug.LogError("I need an object to rotate around"); 13 | } 14 | 15 | 16 | // Update is called once per frame 17 | void Update () 18 | { 19 | if (rotating) 20 | transform.RotateAround(pivotPoint.position, Vector3.up, 20 * Time.deltaTime); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tucano/UnityRandom/82d3d5565eeb322a4ed229da2d8e11b84e08d763/README.pdf -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1=. Unity Random 2 | 3 | h3=. Version 1.0 4 | 5 | h2=. Random Numbers for Unity3d 6 | 7 | p. Homepage: http://tucanosoftware.com/projects/unityrandom 8 | 9 | p. Example: http://108.166.95.149/UnityTest/UnityRandomExample/UnityRandomExample.html 10 | 11 | h3. FAQ 12 | 13 | h4. What is this? 14 | 15 | p. In Unity3d there is already a Random number generator based on the *platform-specific* random generator. 16 | Here we present an alternative Random library for *Unity3d* designed to generate uniform Pseudo-Random deviates. 17 | The library use a fast PRNG (*Mersenne-Twister*) to generate: *Floating Numbers* in range [0-1] and in range [n-m], *Vector2* and *Vector3* data types. 18 | The library comes with some special functions designed specifically for a game design framework: *Shuffle Bag*, *Dice*, *Random Color*. 19 | 20 | h4. Which kind of transformations I can apply to the random uniform deviates? 21 | 22 | p. The uniform deviates can be transformed with the distributions: *Standard Normal Distribution* and *Power-Law*. In addition is possible to generate floating random deviates coming from other distributions: *Poisson*, *Exponential* and *Gamma*. 23 | 24 | h4. How I can test the random numbers? 25 | 26 | p. The library add a window to the *Unity3D* editor that allow you to *Test* and *Visualize* your random numbers, Vector2 and Vector3. With the *SAVE* button, you can write the sample of random number to a txt file. This is useful if you need to analyze in deep the distribution of your random numbers with a statistical software. 27 | 28 | 29 | h3. Usage (C#) 30 | 31 | *Initialization* 32 | Initialization with a seed: @UnityRandom urand = new UnityRandom(int seed);@ 33 | 34 | *Numbers* 35 | A Random number in range [0-1]: @float val = urand.Value() 36 | 37 | *Transformations* 38 | A Random number in range [0-1] with a Transformation: @float val = urand.Value(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 39 | 40 | *Vectors* 41 | A random point in a disk with R=1: @Vector2 pos = urand.PointInADisk()@ 42 | 43 | *Colors* 44 | A random color in the range of visible light (rainbow): @Color col = urand.Rainbow()@ 45 | 46 | *Dice* 47 | A 2D6 dice roll @DiceRoll roll = urand.RollDice(2,DiceRoll.DiceType.D6)@ 48 | 49 | *Shuffle Bag* 50 | 51 | In games or educational programs you often don't want real randomness. Unsurprisingly random it's often a bit too random. You may get some items several times in a row and others too rarely. It's either too easy or too hard. Balancing the weights is hard as well, because each run is too different. And if that wouldn't be already bad enough; it's also difficult to verify the results. 52 | 53 | A shuffle Bag with values: [1,10] 54 | 55 | @float[] shufflebag = {1,2,3,4,5,6,7,8,9,10};@ 56 | 57 | @ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag);@ 58 | 59 | @float randvalue = thebag.Next()@ 60 | 61 | A shuffle bag with weighted values: 62 | 63 | @Dictionary wshufflebag = new Dictionary();@ 64 | 65 | @wshufflebag[1] = 5;@ 66 | 67 | @wshufflebag[2] = 45;@ 68 | 69 | @wshufflebag[3] = 25;@ 70 | 71 | @wshufflebag[4] = 25;@ 72 | 73 | @ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag); @ 74 | 75 | @float randvalue = thebag.Next()@ 76 | 77 | 78 | 79 | 80 |
81 | 82 | h3. Documentation 83 | 84 | h4. Initialization 85 | 86 | * Initialization without a seed: @UnityRandom urand = new UnityRandom();@ 87 | * Initialization with a seed: @UnityRandom urand = new UnityRandom(int seed);@ 88 | 89 | h4. Numbers 90 | 91 | Generation of uniform deviates in any range. 92 | 93 | *Available Transformations* 94 | * @UnityRandom.Normalization.STDNORMAL@ with parameter: @float temperature@ 95 | * @UnityRandom.Normalization.POWERLAW@ with parameter: @float power@ 96 | 97 | h5. Value 98 | 99 | * A Random number in range [0-1]: @float val = urand.Value()@ 100 | * A Random number in range [0-1] with a Transformation: @float val = urand.Value(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 101 | 102 | h5. Range 103 | 104 | * A Random number in range [1-100]: @float val = urand.Range(1,100)@ 105 | * A Random number in range [m-n] with a Transformation: @float val = urand.Value(0,100,UnityRandom.Normalization.POWERLAW, 5.0f)@ 106 | 107 | h5. Poisson 108 | 109 | * The Poisson distribution (pronounced [pwasɔ̃]) is a discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time and/or space if these events occur with a known average rate and independently of the time since the last event. Example: @float val = urand.Poisson(5.0f)@ 110 | 111 | h5. Exponential 112 | 113 | * The Exponential distribution describes the time between events in a Poisson process, i.e. a process in which events occur continuously and independently at a constant average rate. Example: @float val = urand.Exponential(5.0f)@ 114 | 115 | h5. Gamma 116 | 117 | * The gamma distribution, like the lognormal distribution, is an alternative to consider for ecological variables that seem to be highly skewed. Example: @float val = urand.Gamma(5.0f)@ 118 | 119 | h4. Vector2 120 | 121 | generation of Unity Vector2 Objects. 122 | 123 | h5. Square 124 | 125 | * A random *Vector2* point in a square with L=1: @Vector2 pos = urand.PointInASquare()@ 126 | * A random *Vector2* point in a square with L=1 *normalized*: @Vector2 pos = urand.PointInASquare(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 127 | 128 | h5. Disk/Circle 129 | 130 | * A random *Vector2* point in a circle (in the circle *perimeter*) with R=1: @Vector2 pos = urand.PointInACircle()@ 131 | * A random *Vector2* point in a circle (in the circle *perimeter*) with R=1 *normalized*: @Vector2 pos = urand.PointInACircle(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 132 | * A random *Vector2* point in a disk (in the circle *area*) with R=1: @Vector2 pos = urand.PointInADisk()@ 133 | * A random *Vector2* point in a circle (in the circle *area*) with R=1 *normalized*: @Vector2 pos = urand.PointInADisk(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 134 | 135 | h4. Vector3 136 | 137 | generation of Unity Vector3 138 | 139 | h5. Cube 140 | 141 | * A random *Vector3* point inside a cube with L=1: @Vector3 pos = urand.PointInACube()@ 142 | * A random *Vector3* point inside a cube with L=1 *normalized*: @Vector3 pos = urand.PointInACube(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 143 | * A random *Vector3* point in the surface of a cube with L=1: @Vector3 pos = urand.PointOnACube()@ 144 | * A random *Vector3* point inside a cube with L=1 *normalized*: @Vector3 pos = urand.PointOnACube(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 145 | 146 | h5. Sphere 147 | 148 | * A random *Vector3* point inside a sphere (in the sphere *volume*) with R=1: @Vector3 pos = urand.PointInASphere()@ 149 | * A random *Vector3* point in the sphere surface (in the sphere *surface*) with R=1: @Vector3 pos = urand.PointOnASphere()@ 150 | 151 | h4. Color 152 | 153 | * A random *Color* in the range of visible light (rainbow): @Color col = urand.Rainbow()@ 154 | * A random *Color* in the range of visible light (rainbow) *normalized*: @Color col = urand.Rainbow(UnityRandom.Normalization.STDNORMAL, 5.0f)@ 155 | 156 | h4. Dice 157 | 158 | * A *Dice Roll*: @DiceRoll roll = urand.RollDice(n,type)@ 159 | 160 | *Dice types:* 161 | 162 | * DiceRoll.DiceType.D2 163 | * DiceRoll.DiceType.D3 164 | * DiceRoll.DiceType.D4 165 | * DiceRoll.DiceType.D6 166 | * DiceRoll.DiceType.D8 167 | * DiceRoll.DiceType.D10 168 | * DiceRoll.DiceType.D12 169 | * DiceRoll.DiceType.D20 170 | * DiceRoll.DiceType.D30 171 | * DiceRoll.DiceType.D100 172 | 173 | Example 2D6: 174 | 175 | @DiceRoll roll = urand.RollDice(2,DiceRoll.DiceType.D6)@ 176 | 177 | h4. Shuffle Bag 178 | 179 | From: http://kaioa.com/node/53 180 | 181 | In games or educational programs you often don't want real randomness. Unsurprisingly random it's often a bit too random. You may get some items several times in a row and others too rarely. It's either too easy or too hard. Balancing the weights is hard as well, because each run is too different. And if that wouldn't be already bad enough; it's also difficult to verify the results. 182 | 183 | A shuffle Bag with values: [1,10] 184 | 185 | @float[] shufflebag = {1,2,3,4,5,6,7,8,9,10};@ 186 | 187 | @ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag);@ 188 | 189 | @float randvalue = thebag.Next()@ 190 | 191 | A shuffle bag with weighted values: 192 | 193 | @Dictionary wshufflebag = new Dictionary();@ 194 | 195 | @wshufflebag[1] = 5;@ 196 | 197 | @wshufflebag[2] = 45;@ 198 | 199 | @wshufflebag[3] = 25;@ 200 | 201 | @wshufflebag[4] = 25;@ 202 | 203 | @ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag); @ 204 | 205 | @float randvalue = thebag.Next()@ 206 | 207 | 208 | 209 |
210 | 211 | h3. Dev Notes 212 | 213 | * *Clone and test* 214 | ** Fork the main project or clone: git://github.com/tucano/UnityRandom.git 215 | ** Create an empty project in Unity 216 | ** cd ./Assets 217 | ** clone the repo there! 218 | 219 | -------------------------------------------------------------------------------- /Samples/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tucano/UnityRandom/82d3d5565eeb322a4ed229da2d8e11b84e08d763/Samples/.gitkeep -------------------------------------------------------------------------------- /UnityRandom.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using NPack; 6 | using URandom; 7 | 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // // 10 | // Unity Random // 11 | // // 12 | // This code is free software under the Artistic license. // 13 | // // 14 | // distributions mainly from: http://www.nrbook.com/a/bookcpdf.php // 15 | // // 16 | // // 17 | ///////////////////////////////////////////////////////////////////////////// 18 | 19 | public class UnityRandom 20 | { 21 | // STORE MAX SEED VALUE (no access to System) 22 | public static int max_seed = Int32.MaxValue; 23 | 24 | public enum Normalization 25 | { 26 | STDNORMAL = 0, 27 | POWERLAW = 1 28 | } 29 | 30 | private MersenneTwister _rand; 31 | 32 | // THE CONSTRUCTORS 33 | public UnityRandom() 34 | { 35 | _rand = new MersenneTwister(); 36 | } 37 | 38 | public UnityRandom(int seed) 39 | { 40 | _rand = new MersenneTwister(seed); 41 | } 42 | 43 | // VALUE Return a Float 0 - 1 44 | public float Value() 45 | { 46 | return _rand.NextSingle(true); 47 | } 48 | 49 | // VALUE Return a Float 0 - 1 50 | public float Value( Normalization n , float t) 51 | { 52 | if (n == Normalization.STDNORMAL) { 53 | return (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 54 | } else if (n == Normalization.POWERLAW) { 55 | return (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 56 | } else { 57 | return _rand.NextSingle(true); 58 | } 59 | } 60 | 61 | // RANGE Return a Float min < x < max 62 | public float Range(Int32 minValue, Int32 maxValue) 63 | { 64 | return _rand.Next(minValue, maxValue); 65 | } 66 | 67 | // RANGE Return a Float min < x < max 68 | public float Range(Int32 minValue, Int32 maxValue, Normalization n, float t) 69 | { 70 | if (n == Normalization.STDNORMAL) { 71 | return SpecialFunctions.ScaleFloatToRange( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), minValue, maxValue, 0, 1); 72 | } else if (n == Normalization.POWERLAW) { 73 | return (float) PowerLaw.Normalize(_rand.NextSingle(true), t, minValue, maxValue); 74 | } else { 75 | return _rand.Next(minValue, maxValue); 76 | } 77 | } 78 | 79 | // POISSON Return a Float 80 | public float Possion(float lambda) 81 | { 82 | return PoissonDistribution.Normalize( ref _rand, lambda); 83 | } 84 | 85 | // EXPONENTIAL Return a Float 86 | public float Exponential(float lambda) 87 | { 88 | return ExponentialDistribution.Normalize( _rand.NextSingle( false ), lambda ); 89 | } 90 | 91 | // GAMMA Return a Float 92 | public float Gamma(float order) 93 | { 94 | return GammaDistribution.Normalize(ref _rand, (int) order); 95 | } 96 | 97 | // POINT IN A SQUARE Return a Vector2 98 | public Vector2 PointInASquare() 99 | { 100 | return RandomSquare.Area(ref _rand); 101 | } 102 | 103 | // POINT IN A SQUARE Return a Vector2 104 | public Vector2 PointInASquare(Normalization n , float t ) 105 | { 106 | return RandomSquare.Area(ref _rand, n, t); 107 | } 108 | 109 | // RANDOM POINT IN A CIRCLE centered at 0 110 | // FROM http://mathworld.wolfram.com/CirclePointPicking.html 111 | // Take a number between 0 and 2PI and move to Cartesian Coordinates 112 | public Vector2 PointInACircle() 113 | { 114 | return RandomDisk.Circle(ref _rand); 115 | } 116 | 117 | // RANDOM POINT IN A CIRCLE centered at 0 118 | // FROM http://mathworld.wolfram.com/CirclePointPicking.html 119 | // Take a number between 0 and 2PI and move to Cartesian Coordinates 120 | public Vector2 PointInACircle(Normalization n, float t) 121 | { 122 | return RandomDisk.Circle(ref _rand, n, t); 123 | } 124 | 125 | // RANDOM POINT in a DISK 126 | // FROM http://mathworld.wolfram.com/DiskPointPicking.html 127 | public Vector2 PointInADisk() 128 | { 129 | return RandomDisk.Disk(ref _rand); 130 | } 131 | 132 | // RANDOM POINT in a DISK 133 | // FROM http://mathworld.wolfram.com/DiskPointPicking.html 134 | public Vector2 PointInADisk(Normalization n, float t) 135 | { 136 | return RandomDisk.Disk(ref _rand, n, t); 137 | } 138 | 139 | // RANDOM POINT IN A CUBE. Return a Vector3 140 | public Vector3 PointInACube() 141 | { 142 | return RandomCube.Volume(ref _rand); 143 | } 144 | 145 | // RANDOM POINT IN A CUBE. Return a Vector3 146 | public Vector3 PointInACube(Normalization n, float t) 147 | { 148 | return RandomCube.Volume(ref _rand, n, t); 149 | } 150 | 151 | // RANDOM POINT ON A CUBE. Return a Vector3 152 | public Vector3 PointOnACube() 153 | { 154 | return RandomCube.Surface(ref _rand); 155 | } 156 | 157 | // RANDOM POINT ON A CUBE. Return a Vector3 158 | public Vector3 PointOnACube(Normalization n, float t) 159 | { 160 | return RandomCube.Surface(ref _rand, n, t); 161 | } 162 | 163 | // RANDOM POINT ON A SPHERE. Return a Vector3 164 | public Vector3 PointOnASphere() 165 | { 166 | return RandomSphere.Surface(ref _rand); 167 | } 168 | 169 | // RANDOM POINT ON A SPHERE. Return a Vector3 170 | public Vector3 PointOnASphere(Normalization n, float t) 171 | { 172 | throw new ArgumentException("Normalizations for Sphere is not yet implemented"); 173 | } 174 | 175 | // RANDOM POINT IN A SPHERE. Return a Vector3 176 | public Vector3 PointInASphere() 177 | { 178 | return RandomSphere.Volume(ref _rand); 179 | } 180 | 181 | // RANDOM POINT IN A SPHERE. Return a Vector3 182 | public Vector3 PointInASphere(Normalization n, float t) 183 | { 184 | throw new ArgumentException("Normalizations for Sphere is not yet implemented"); 185 | } 186 | 187 | // RANDOM POINT IN A CAP. Return a Vector3 188 | // TODO: see RandomSphere GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation) 189 | public Vector3 PointOnCap(float spotAngle) 190 | { 191 | return RandomSphere.GetPointOnCap(spotAngle, ref _rand); 192 | } 193 | 194 | public Vector3 PointOnCap(float spotAngle, Normalization n, float t) 195 | { 196 | throw new ArgumentException("Normalizations for PointOnCap is not yet implemented"); 197 | } 198 | 199 | // RANDOM POINT IN A RING on a SPHERE. Return a Vector3 200 | // TODO: see RandomSphere public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation) 201 | public Vector3 PointOnRing(float innerAngle, float outerAngle) 202 | { 203 | return RandomSphere.GetPointOnRing(innerAngle, outerAngle, ref _rand); 204 | } 205 | 206 | public Vector3 PointOnRing(float innerAngle, float outerAngle, Normalization n, float t) 207 | { 208 | throw new ArgumentException("Normalizations for PointOnRing is not yet implemented"); 209 | } 210 | 211 | // RANDOM RAINBOW COLOR 212 | public Color Rainbow() 213 | { 214 | return WaveToRgb.LinearToRgb(_rand.NextSingle(true)); 215 | } 216 | 217 | // RANDOM RAINBOW COLOR 218 | public Color Rainbow(Normalization n, float t) 219 | { 220 | if (n == Normalization.STDNORMAL) { 221 | return WaveToRgb.LinearToRgb ( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t)); 222 | } else if (n == Normalization.POWERLAW) { 223 | return WaveToRgb.LinearToRgb ( (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1)); 224 | } else { 225 | return WaveToRgb.LinearToRgb(_rand.NextSingle(true)); 226 | } 227 | } 228 | 229 | // RANDOM DICES 230 | public DiceRoll RollDice(int size, DiceRoll.DiceType type) 231 | { 232 | DiceRoll roll = new DiceRoll(size, type, ref _rand); 233 | //Debug.Log(roll.TypeToString()); 234 | //Debug.Log(roll.RollToString()); 235 | //Debug.Log(roll.Sum()); 236 | return roll; 237 | } 238 | 239 | // START a FLOAT SHUFFLE BAG 240 | // Note the a value can be shuffled with himself 241 | public ShuffleBagCollection ShuffleBag(float[] values) 242 | { 243 | ShuffleBagCollection bag = new ShuffleBagCollection(); 244 | foreach (float x in values) 245 | { 246 | bag.Add(x); 247 | } 248 | return bag; 249 | } 250 | 251 | // START a WIGHTED FLOAT SHUFFLE BAG, the trick is the it is added many times 252 | // Note the a value can be shuffled with himself 253 | public ShuffleBagCollection ShuffleBag(Dictionary dict) 254 | { 255 | ShuffleBagCollection bag = new ShuffleBagCollection(); 256 | foreach (KeyValuePair x in dict) 257 | { 258 | //Debug.Log(x.Value); 259 | int val = x.Value; 260 | float key = x.Key; 261 | bag.Add( key, val); 262 | } 263 | return bag; 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /lib/DiceRoll.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | using NPack; 5 | 6 | namespace URandom 7 | { 8 | public class DiceRoll 9 | { 10 | // STORE DICE RESULTS in an ARRAYLIST 11 | private int[] _result; 12 | public int[] result 13 | { 14 | get 15 | { 16 | return _result; 17 | } 18 | } 19 | 20 | public enum DiceType 21 | { 22 | D2 = 2, 23 | D3 = 3, 24 | D4 = 4, 25 | D6 = 6, 26 | D8 = 8, 27 | D10 = 10, 28 | D12 = 12, 29 | D20 = 20, 30 | D30 = 30, 31 | D100 = 100 32 | } 33 | 34 | private DiceType _dice_type = DiceType.D6; 35 | public DiceType type 36 | { 37 | get { return _dice_type; } 38 | } 39 | 40 | private int _size = 1; 41 | public int size 42 | { 43 | get { return _size; } 44 | } 45 | 46 | // CONSTRUCTOR 47 | public DiceRoll(int size, DiceType type, ref NPack.MersenneTwister _rand) 48 | { 49 | if (size < 1) throw new ArgumentOutOfRangeException ("Number of dices shlud be > 0"); 50 | init(size,type,ref _rand); 51 | } 52 | 53 | // INIT 54 | private void init(int size, DiceType type, ref NPack.MersenneTwister _rand) 55 | { 56 | _result = new int[size]; 57 | _dice_type = type; 58 | _size = size; 59 | 60 | for (int i = 0; i < _size; i++) { 61 | // Cast enum to int to get the value 62 | _result[i] = _rand.Next( 1, (int) type); 63 | } 64 | } 65 | 66 | // DICETYPE TO STRING 67 | public String TypeToString() 68 | { 69 | return _size + _dice_type.ToString(); 70 | } 71 | 72 | // DICEROLL TO STRING 73 | public String RollToString() 74 | { 75 | String s = ""; 76 | for (int i = 0; i < _size; i++) { 77 | s += _result[i].ToString(); 78 | if (i != (_size -1)) s += ", "; 79 | } 80 | return s; 81 | } 82 | 83 | public int Sum() 84 | { 85 | return _result.Sum(); 86 | } 87 | 88 | } 89 | } -------------------------------------------------------------------------------- /lib/ExponentialDistribution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace URandom 4 | { 5 | public static class ExponentialDistribution 6 | { 7 | // FROM http://stackoverflow.com/questions/2106503/pseudorandom-number-generator-exponential-distribution 8 | public static float Normalize( float randx, float lambda ) 9 | { 10 | return Convert.ToSingle((Math.Log(1-randx) / (-lambda))); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /lib/GammaDistribution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NPack; 3 | 4 | namespace URandom 5 | { 6 | // Returns a deviate distributed as a gamma distribution of integer of order ia, i.e. the waiting time for the iath event in a Poisson process of unit mean 7 | // Use _rand as a source of uniform deviates 8 | // http://www.nrbook.com/a/bookcpdf.php 9 | public static class GammaDistribution 10 | { 11 | public static float Normalize(ref NPack.MersenneTwister _rand, int ia) 12 | { 13 | int j; 14 | float am, e, s, v1, v2, x, y; 15 | 16 | if (ia < 1) 17 | throw new ArgumentException("Error in Gamma Distribution. Argument ia should be an integer > 1"); 18 | 19 | if (ia < 6) { 20 | // use direct method, addin waiting times 21 | x = 1.0f; 22 | for (j=1; j<=ia; j++) x *= _rand.NextSingle(true); 23 | x = (float) - (Math.Log(x)); 24 | } else { 25 | do { 26 | do { 27 | // This four lines generate the tanget of random angle 28 | // Equivalent to y = tan( pi * rand()) 29 | do { 30 | v1 = _rand.NextSingle(true); 31 | v2 = 2.0f * _rand.NextSingle(true) - 1.0f; 32 | } while (v1 * v1+v2 * v2 > 1.0f); 33 | y = v2/v1; 34 | am = ia-1; 35 | s = (float) Math.Sqrt(2.0*am+1.0f); 36 | x = s * y + am; 37 | // We decide wheter to reject x, Reject in 0 probability region 38 | } while (x <= 0.0f); 39 | e = (float) ((1.0f + y*y) * Math.Exp(am * Math.Log(x/am) -s*y)); 40 | } while (_rand.NextSingle(true) > e); 41 | } 42 | return x; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /lib/MersenneTwister.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tucano/UnityRandom/82d3d5565eeb322a4ed229da2d8e11b84e08d763/lib/MersenneTwister.cs -------------------------------------------------------------------------------- /lib/NormalDistribution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | //////////////////////////////////////////////////////////////////////////// 4 | // C# Version Standard CDF // 5 | // // 6 | // This code is free software under the Artistic license. // 7 | // // 8 | ///////////////////////////////////////////////////////////////////////////// 9 | 10 | namespace URandom 11 | { 12 | 13 | /// 14 | /// Convert a Uniform Distribution to a Normal Distribution 15 | /// 16 | /// 17 | /// See http://stackoverflow.com/questions/75677/converting-a-uniform-distribution-to-a-normal-distribution for details 18 | /// 19 | public static class NormalDistribution 20 | { 21 | /// 22 | /// Standard Normal CDF 23 | /// 24 | /// The random value 25 | public static double StdNormalCDF(double u) 26 | { 27 | const double m_1_sqrtpi = 0.564189583547756286948; 28 | double msqrt2 = 1.41421356237309504880; 29 | double z, y; 30 | 31 | double[] a = new double [] { 32 | 1.161110663653770e-002, 33 | 3.951404679838207e-001, 34 | 2.846603853776254e+001, 35 | 1.887426188426510e+002, 36 | 3.209377589138469e+003 37 | }; 38 | 39 | double[] b = new double [] { 40 | 1.767766952966369e-001, 41 | 8.344316438579620e+000, 42 | 1.725514762600375e+002, 43 | 1.813893686502485e+003, 44 | 8.044716608901563e+003 45 | }; 46 | 47 | double[] c = new double [] { 48 | 2.15311535474403846e-8, 49 | 5.64188496988670089e-1, 50 | 8.88314979438837594e00, 51 | 6.61191906371416295e01, 52 | 2.98635138197400131e02, 53 | 8.81952221241769090e02, 54 | 1.71204761263407058e03, 55 | 2.05107837782607147e03, 56 | 1.23033935479799725E03 57 | }; 58 | 59 | double[] d = new double [] { 60 | 1.00000000000000000e00, 61 | 1.57449261107098347e01, 62 | 1.17693950891312499e02, 63 | 5.37181101862009858e02, 64 | 1.62138957456669019e03, 65 | 3.29079923573345963e03, 66 | 4.36261909014324716e03, 67 | 3.43936767414372164e03, 68 | 1.23033935480374942e03 69 | }; 70 | 71 | double[] p = new double [] { 72 | 1.63153871373020978e-2, 73 | 3.05326634961232344e-1, 74 | 3.60344899949804439e-1, 75 | 1.25781726111229246e-1, 76 | 1.60837851487422766e-2, 77 | 6.58749161529837803e-4 78 | }; 79 | 80 | double[] q = new double [] { 81 | 1.00000000000000000e00, 82 | 2.56852019228982242e00, 83 | 1.87295284992346047e00, 84 | 5.27905102951428412e-1, 85 | 6.05183413124413191e-2, 86 | 2.33520497626869185e-3 87 | }; 88 | 89 | if (Double.IsNaN(u)) { 90 | return(Double.NaN); 91 | } 92 | 93 | if(Double.IsInfinity(u)) { 94 | return (u < 0 ? 0.0 : 1.0); 95 | } 96 | 97 | y = Math.Abs(u); 98 | 99 | if (y <= 0.46875*msqrt2) { 100 | /* evaluate erf() for |u| <= sqrt(2)*0.46875 */ 101 | z = y*y; 102 | y = u*((((a[0]*z+a[1])*z+a[2])*z+a[3])*z+a[4])/((((b[0]*z+b[1])*z+b[2])*z+b[3])*z+b[4]); 103 | return 0.5+y; 104 | } 105 | 106 | z = Math.Exp(-y*y/2)/2; 107 | 108 | if (y <= 4.0) { 109 | /* evaluate erfc() for sqrt(2)*0.46875 <= |u| <= sqrt(2)*4.0 */ 110 | y = y/msqrt2; 111 | y = ((((((((c[0]*y+c[1])*y+c[2])*y+c[3])*y+c[4])*y+c[5])*y+c[6])*y+c[7])*y+c[8]) 112 | / ((((((((d[0]*y+d[1])*y+d[2])*y+d[3])*y+d[4])*y+d[5])*y+d[6])*y+d[7])*y+d[8]); 113 | y = z*y; 114 | } else { 115 | /* evaluate erfc() for |u| > sqrt(2)*4.0 */ 116 | z = z*msqrt2/y; 117 | y = 2/(y*y); 118 | y = y*(((((p[0]*y+p[1])*y+p[2])*y+p[3])*y+p[4])*y+p[5]) 119 | /(((((q[0]*y+q[1])*y+q[2])*y+q[3])*y+q[4])*y+q[5]); 120 | y = z*(m_1_sqrtpi-y); 121 | } 122 | return (u < 0.0 ? y : 1-y); 123 | } 124 | 125 | /// 126 | /// Standard Normal INV 127 | /// 128 | /// The random value 129 | public static double StdNormalINV(double p) 130 | { 131 | const double m_sqrt2pi = 2.50662827463100; 132 | double[] a = new double [] { 133 | -3.969683028665376e+01, 2.209460984245205e+02, 134 | -2.759285104469687e+02, 1.383577518672690e+02, 135 | -3.066479806614716e+01, 2.506628277459239e+00 136 | }; 137 | 138 | double[] b = new double [] { 139 | -5.447609879822406e+01, 1.615858368580409e+02, 140 | -1.556989798598866e+02, 6.680131188771972e+01, 141 | -1.328068155288572e+01 142 | }; 143 | 144 | double[] c = new double [] { 145 | -7.784894002430293e-03, -3.223964580411365e-01, 146 | -2.400758277161838e+00, -2.549732539343734e+00, 147 | 4.374664141464968e+00, 2.938163982698783e+00 148 | }; 149 | 150 | double[] d = new double [] { 151 | 7.784695709041462e-03, 3.224671290700398e-01, 152 | 2.445134137142996e+00, 3.754408661907416e+00 153 | }; 154 | 155 | double q, t, u; 156 | 157 | if (Double.IsNaN(p) || p > 1.0 || p < 0.0) 158 | { 159 | return(Double.NaN); 160 | } 161 | if (p == 0.0) 162 | { 163 | return Double.NegativeInfinity; 164 | } 165 | if (p == 1.0) 166 | { 167 | return Double.PositiveInfinity; 168 | } 169 | 170 | q = (p < (1-p)) ? p : (1-p); 171 | 172 | if (q > 0.02425) { 173 | /* Rational approximation for central region. */ 174 | u = q-0.5; 175 | t = u*u; 176 | u = u*(((((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4])*t+a[5]) 177 | /(((((b[0]*t+b[1])*t+b[2])*t+b[3])*t+b[4])*t+1); 178 | } else { 179 | /* Rational approximation for tail region. */ 180 | t = Math.Sqrt(-2*Math.Log(q)); 181 | u = (((((c[0]*t+c[1])*t+c[2])*t+c[3])*t+c[4])*t+c[5]) 182 | /((((d[0]*t+d[1])*t+d[2])*t+d[3])*t+1); 183 | } 184 | 185 | /* The relative error of the approximation has absolute value less 186 | than 1.15e-9. One iteration of Halley's rational method (third 187 | order) gives full machine precision... */ 188 | 189 | t = StdNormalCDF(u)-q; /* error */ 190 | t = t*m_sqrt2pi*Math.Exp(u*u/2); /* f(u)/df(u) */ 191 | u = u-t/(1+u*t/2); /* Halley's method */ 192 | 193 | return (p > 0.5 ? -u : u); 194 | } 195 | 196 | /// 197 | /// Normalize 198 | /// 199 | /// The random value 200 | /// Distribution Temperature 201 | public static double Normalize(double rn, float temperature) 202 | { 203 | // Trasformiamo questo numero in una distribuzione normale (CDF inversa, nota anche come Gaussiana, vedi http://en.wikipedia.org/wiki/Normal_distribution) 204 | // facendo l'inversa della cumulative density function su una distribuzione uniforme [0,1] otteniamo una distribuzione normale (-inf,+inf) centrata a zero 205 | // e con deviazione standard 1 206 | double localVal = StdNormalINV(rn); 207 | 208 | // A questo punto passiamo attraverso una funzione sigmoide (o curva logistica) con Lateratura 5 209 | // Questo ci riporta a un campo (0,1), il valore 5 fa si che circa il 90% dei valori restituiti sia tra 0.45 e 0.55, aumentandolo 210 | // la distribuzione si stringe (piu' valori vicini a 0.5), abbassandolo si allarga, ma a differenza di una gaussiana in ogni caso 211 | // il valore restituito e' tra zero e uno. 212 | localVal = localVal / temperature; 213 | localVal = 1.0 / (1.0 + Math.Exp(-localVal)); 214 | return(localVal); 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /lib/PoissonDistribution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NPack; 3 | 4 | // 5 | // NEW VERSION FROM NUMERICAL RECIPES http://www.nrbook.com/a/bookcpdf.php 6 | // 7.3 Rejection Method: Gamma, Poisson, Binomial Deviates 7 | 8 | namespace URandom 9 | { 10 | public static class PoissonDistribution 11 | { 12 | 13 | // return as a floating point number an integer value that is a random deviate drawn 14 | // from a Possion Distribution of mean xm using randx as a source of uniform deviates 15 | public static float Normalize( ref NPack.MersenneTwister _rand, float xm) 16 | { 17 | // Davide Rambaldi: all moved to double precision 18 | double sq, alxm, g, oldm; // oldm is a flag for wheter xm has changed or not sincle last call 19 | sq = alxm = g = oldm = (-1.0); 20 | double em, t, y; 21 | 22 | if (xm < 12.0f) { // Use direct method 23 | if (xm != oldm) { 24 | oldm = xm; 25 | g = Math.Exp(-xm); // if x is new, compute the exponential 26 | } 27 | em = -1; 28 | t = 1.0f; 29 | // Instead of adding exponential deviates it is equivalent to multiply unifomr deviates 30 | // We never actually take the log, we compare the precomupted exponential 31 | do { 32 | ++em; 33 | t *= _rand.NextSingle(true); 34 | } while (t > g); 35 | } else { 36 | // Use REJECTION method 37 | // xm has changed? 38 | if ( xm != oldm) { 39 | oldm = xm; 40 | sq = Math.Sqrt(2.0 * xm); 41 | alxm = Math.Log(xm); 42 | 43 | // Gammln is the natural log of a gamma function 44 | g = xm * alxm - SpecialFunctions.gammln(xm + 1.0f); 45 | } 46 | do { 47 | do { 48 | // y is the deviate from a Lorentzian comparison function 49 | y = Math.Tan(Math.PI*_rand.NextSingle(true)); 50 | em=sq*y+xm; 51 | } while (em < 0.0); 52 | em = Math.Floor(em); 53 | t = 0.9 * (1.0+y*y) * Math.Exp(em*alxm-SpecialFunctions.gammln(em+1.0f)-g); 54 | } while (_rand.NextSingle(true) > t); 55 | } 56 | return (float) em; 57 | } 58 | 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /lib/PowerLaw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | // 4 | // FROM HERE: 5 | // 6 | // http://stackoverflow.com/questions/918736/random-number-generator-that-produces-a-power-law-distribution 7 | // 8 | // 9 | 10 | namespace URandom 11 | { 12 | public static class PowerLaw 13 | { 14 | public static double Normalize( float x, float t, float min, float max) 15 | { 16 | return Math.Pow( ( Math.Pow(max, (t + 1)) - Math.Pow(min,(t+1)) ) * x + Math.Pow(min,(t+1)) , ( 1 / (t+1) )); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /lib/RandomCube.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using NPack; 4 | 5 | namespace URandom 6 | { 7 | public static class RandomCube 8 | { 9 | public static Vector3 Surface(ref NPack.MersenneTwister _rand) 10 | { 11 | // Move to -1, 1 space as for CIRCLE and SPHERE 12 | Vector3 pos = GetPointOnCubeSurface(_rand.NextSingle(true),_rand.NextSingle(true),_rand.Next(5)); 13 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1); 14 | } 15 | 16 | public static Vector3 Surface(ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t) 17 | { 18 | Vector3 pos = new Vector3(); 19 | switch (n) { 20 | case UnityRandom.Normalization.STDNORMAL: 21 | pos = GetPointOnCubeSurface( 22 | (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), 23 | (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), 24 | _rand.Next(5)); 25 | break; 26 | case UnityRandom.Normalization.POWERLAW: 27 | pos = GetPointOnCubeSurface( 28 | (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1), 29 | (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1), 30 | _rand.Next(5)); 31 | break; 32 | default: 33 | pos = GetPointOnCubeSurface(_rand.NextSingle(true),_rand.NextSingle(true),_rand.Next(5)); 34 | break; 35 | } 36 | 37 | // Move to -1, 1 space as for CIRCLE and SPHERE 38 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1); 39 | } 40 | 41 | // This should work: FIXME? 42 | // take 3 random numbers, use 2 for coordinates, the last one to select which face. 43 | private static Vector3 GetPointOnCubeSurface( float xx, float yy, int side) 44 | { 45 | float x,y,z; 46 | 47 | // SIDES MAP 48 | switch (side) { 49 | case 0: z = 0; x = xx; y = yy; break; 50 | case 1: z = 1; x = xx; y = yy; break; 51 | case 2: z = xx; x = yy; y = 0; break; 52 | case 3: z = xx; x = yy; y = 1; break; 53 | case 4: z = xx; y = yy; x = 0; break; 54 | case 5: z = xx; y = yy; x = 1; break; 55 | default: x = 0; y = 0; z = 0; break; 56 | } 57 | 58 | return new Vector3(x,y,z); 59 | } 60 | 61 | public static Vector3 Volume(ref NPack.MersenneTwister _rand) 62 | { 63 | Vector3 pos = new Vector3(_rand.NextSingle(true), _rand.NextSingle(true), _rand.NextSingle(true)); 64 | // Move to -1, 1 space as for CIRCLE and SPHERE 65 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1); 66 | } 67 | 68 | public static Vector3 Volume(ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t) 69 | { 70 | float x, y, z; 71 | x = y = z = 0; 72 | switch (n) { 73 | case UnityRandom.Normalization.STDNORMAL: 74 | x = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 75 | y = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 76 | z = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 77 | break; 78 | case UnityRandom.Normalization.POWERLAW: 79 | x = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 80 | y = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 81 | z = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 82 | break; 83 | default: 84 | x = _rand.NextSingle(true); 85 | y = _rand.NextSingle(true); 86 | z = _rand.NextSingle(true); 87 | break; 88 | } 89 | // Move to -1, 1 space as for CIRCLE and SPHERE 90 | return new Vector3((2*x)-1, (2*y)-1, (2*z)-1); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /lib/RandomDisk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using NPack; 4 | 5 | namespace URandom 6 | { 7 | public static class RandomDisk 8 | { 9 | // CIRCLE with R=1 10 | public static Vector2 Circle( ref NPack.MersenneTwister _rand ) 11 | { 12 | float t = (float) _rand.Next(); 13 | float _2pi = (float) Math.PI * 2; 14 | float a = SpecialFunctions.ScaleFloatToRange(t, 0, _2pi, 0, Int32.MaxValue); 15 | return new Vector2( (float) Math.Cos(a) , (float) Math.Sin(a)); 16 | } 17 | 18 | public static Vector2 Circle( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t ) 19 | { 20 | float r; 21 | switch (n) { 22 | case UnityRandom.Normalization.STDNORMAL: 23 | r = SpecialFunctions.ScaleFloatToRange( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), 0, Int32.MaxValue, 0, 1); 24 | break; 25 | case UnityRandom.Normalization.POWERLAW: 26 | r = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, Int32.MaxValue); 27 | break; 28 | default: 29 | r = (float) _rand.Next(); 30 | break; 31 | } 32 | float _2pi = (float) Math.PI * 2; 33 | float a = SpecialFunctions.ScaleFloatToRange(r, 0, _2pi, 0, Int32.MaxValue); 34 | return new Vector2( (float) Math.Cos(a) , (float) Math.Sin(a)); 35 | } 36 | 37 | 38 | public static Vector2 Disk( ref NPack.MersenneTwister _rand ) 39 | { 40 | // t [0,1] , Theta [0,2pi) 41 | double t = _rand.NextSingle(true); 42 | // in range [0,1) then multiply this number by k to get a random number in the range [0,k) 43 | double theta = _rand.NextSingle(false) * 2 * Math.PI; 44 | return new Vector2( (float) (Math.Sqrt(t) * Math.Cos(theta)), (float) (Math.Sqrt(t) * Math.Sin(theta)) ); 45 | } 46 | 47 | public static Vector2 Disk( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float temp ) 48 | { 49 | double t, theta; 50 | 51 | switch (n) { 52 | case UnityRandom.Normalization.STDNORMAL: 53 | t = NormalDistribution.Normalize(_rand.NextSingle(true), temp); 54 | theta = NormalDistribution.Normalize(_rand.NextSingle(true), temp) * 2 * Math.PI; 55 | break; 56 | case UnityRandom.Normalization.POWERLAW: 57 | t = PowerLaw.Normalize(_rand.NextSingle(true), temp, 0, 1); 58 | theta = PowerLaw.Normalize(_rand.NextSingle(true), temp, 0, 1) * 2 * Math.PI; 59 | break; 60 | default: 61 | t = (float) _rand.NextSingle(true); 62 | theta = _rand.NextSingle(false) * 2 * Math.PI; 63 | break; 64 | } 65 | 66 | return new Vector2( (float) (Math.Sqrt(t) * Math.Cos(theta)), (float) (Math.Sqrt(t) * Math.Sin(theta)) ); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /lib/RandomSphere.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using NPack; 4 | 5 | namespace URandom 6 | { 7 | public static class RandomSphere 8 | { 9 | // RADIUS = 1 10 | 11 | // Marsaglia Method (1972) I use for Surface and Volume 12 | // FROM http://stackoverflow.com/questions/5531827/random-point-on-a-given-sphere 13 | // ALSO: http://mathworld.wolfram.com/SpherePointPicking.html 14 | // 1. Pick a random point inside the [-1,1]x[-1,1]x[-1,1] cube 15 | // 2. If x*x + y*y + z*z > 1 repeat from 1 16 | // 3. Normalize dividing x, y and z by Math.sqrt(x*x + y*y + z*z) 17 | 18 | public static Vector3 Surface(ref NPack.MersenneTwister _rand) 19 | { 20 | Vector3 pos = PickCubePoints(ref _rand); 21 | while ( IsNotOnSurface(pos) ) 22 | { 23 | pos = PickCubePoints(ref _rand); 24 | } 25 | return Normalize(pos); 26 | } 27 | 28 | public static Vector3 Volume(ref NPack.MersenneTwister _rand) 29 | { 30 | Vector3 pos = PickCubePoints(ref _rand); 31 | while ( isNotInsideSphere(pos) ) 32 | { 33 | pos = PickCubePoints(ref _rand); 34 | } 35 | return pos; 36 | } 37 | 38 | private static Vector3 PickCubePoints( ref NPack.MersenneTwister _rand ) 39 | { 40 | 41 | float x = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 ); 42 | float y = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 ); 43 | float z = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 ); 44 | 45 | return new Vector3(x,y,z); 46 | } 47 | 48 | private static bool isNotInsideSphere(Vector3 pos) 49 | { 50 | return( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) > 1 ); 51 | } 52 | 53 | private static bool IsNotOnSurface(Vector3 pos) 54 | { 55 | return ( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) > 1 ); 56 | } 57 | 58 | private static Vector3 Normalize( Vector3 pos) 59 | { 60 | float k = (float) Math.Sqrt( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) ); 61 | return new Vector3( pos.x / k, pos.y / k, pos.z / k ); 62 | } 63 | 64 | /// FROM: http://unifycommunity.com/wiki/index.php?title=UnitSphere 65 | /// 66 | /// Returns a point on the unit sphere that is within a cone along the z-axis 67 | /// 68 | /// [0..180] specifies the angle of the cone. 69 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand) 70 | { 71 | float angle1 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),0.0f, Mathf.PI*2, 0, 1); 72 | float angle2 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true), 0.0f,spotAngle * Mathf.Deg2Rad, 0, 1); 73 | Vector3 V = new Vector3(Mathf.Sin(angle1),Mathf.Cos(angle1),0); 74 | V *= Mathf.Sin(angle2); 75 | V.z = Mathf.Cos(angle2); 76 | return V; 77 | } 78 | 79 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM 80 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation) 81 | { 82 | return orientation * GetPointOnCap(spotAngle, ref _rand); 83 | } 84 | 85 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM 86 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Transform relativeTo, float radius) 87 | { 88 | return relativeTo.TransformPoint( GetPointOnCap(spotAngle, ref _rand)*radius ); 89 | } 90 | 91 | /// FROM: http://unifycommunity.com/wiki/index.php?title=UnitSphere 92 | /// 93 | /// Returns a point on the unit sphere that is within the outer cone along the z-axis 94 | /// but not inside the inner cone. The resulting area describes a ring on the sphere surface. 95 | /// 96 | /// [0..180] specifies the inner cone that should be excluded. 97 | /// [0..180] specifies the outer cone that should be included. 98 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand) 99 | { 100 | float angle1 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),0.0f, Mathf.PI*2, 0, 1); 101 | float angle2 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),innerSpotAngle, outerSpotAngle, 0, 1) * Mathf.Deg2Rad; 102 | Vector3 V = new Vector3(Mathf.Sin(angle1),Mathf.Cos(angle1),0); 103 | V *= Mathf.Sin(angle2); 104 | V.z = Mathf.Cos(angle2); 105 | return V; 106 | } 107 | 108 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM 109 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation) 110 | { 111 | return orientation * GetPointOnRing(innerSpotAngle, outerSpotAngle, ref _rand); 112 | } 113 | 114 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM 115 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Transform relativeTo, float radius) 116 | { 117 | return relativeTo.TransformPoint( GetPointOnRing(innerSpotAngle, outerSpotAngle, ref _rand)*radius ); 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /lib/RandomSquare.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using NPack; 4 | 5 | namespace URandom 6 | { 7 | public static class RandomSquare 8 | { 9 | public static Vector2 Area( ref NPack.MersenneTwister _rand ) 10 | { 11 | // Move to -1, 1 space as for CIRCLE and SPHERE 12 | return new Vector2((2*_rand.NextSingle(true) - 1), (2*_rand.NextSingle(true) - 1)); 13 | } 14 | 15 | public static Vector2 Area( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t ) 16 | { 17 | float x,y; 18 | x = y = 0; 19 | switch (n) { 20 | case UnityRandom.Normalization.STDNORMAL: 21 | x = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 22 | y = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t); 23 | break; 24 | case UnityRandom.Normalization.POWERLAW: 25 | x = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 26 | y = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1); 27 | break; 28 | default: 29 | x = _rand.NextSingle(true); 30 | y = _rand.NextSingle(true); 31 | break; 32 | } 33 | 34 | // Move to -1, 1 space as for CIRCLE and SPHERE 35 | return new Vector2((2*x - 1), (2*y - 1)); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /lib/ShuffleBagCollection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from: http://liboxide.svn.sourceforge.net/viewvc/liboxide/trunk/Oxide/Collections/ShuffleBagCollection.cs?view=markup 3 | * 4 | * davide.rambaldi AT gmail.com : Changed Random to Mersenne Twister random, changed namespace to URandom 5 | * 6 | */ 7 | 8 | /* 9 | * Oxide .NET extensions library 10 | * Copyright (C) 2009 Matthew Scharley and the liboxide team 11 | * 12 | * This program is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU Lesser General Public License as 14 | * published by the Free Software Foundation, either version 3 of the 15 | * License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public License 23 | * along with this program. If not, see . 24 | */ 25 | 26 | /* 27 | * This class is a port and/or based very heavily on the GShuffleBag class 28 | * written by Jos Hirth originally implemented 29 | * in Java. 30 | */ 31 | 32 | /* 33 | * This file is also released seperately from the Oxide Library under a 34 | * BSD style licence described at , with the 35 | * following extra provision: 36 | * 37 | * - All the above copyright notices must be kept intact in any source 38 | * code derived from this file. 39 | */ 40 | 41 | /* 42 | * Works with any class that subclasses System.Random 43 | * 44 | * There is a Mersenne Twister implementation available from 45 | * http://code.msdn.microsoft.com/MersenneTwister if the default 46 | * implementation is not good enough. 47 | */ 48 | using System; 49 | using System.Collections.Generic; 50 | using System.Collections; 51 | using System.Text; 52 | using NPack; 53 | 54 | namespace URandom 55 | { 56 | public sealed class ShuffleBagCollection : IEnumerable 57 | { 58 | private Random m_generator; 59 | private List m_data; 60 | private int m_cursor = -1; 61 | private T m_current = default(T); 62 | 63 | /// 64 | /// Constructs an empty bag with an initial capacity of 10 and the default source of randomness. 65 | /// 66 | public ShuffleBagCollection() : this(10, new MersenneTwister()) { } 67 | /// 68 | /// Constructs an empty bag with an initial capacity of 10 and the specified source of randomness. 69 | /// 70 | /// The random number generator to use 71 | public ShuffleBagCollection(MersenneTwister generator) : this(10, generator) { } 72 | /// 73 | /// Constructs an empty bag with the specified initial capacity and the default source of randomness. 74 | /// 75 | /// The initial capacity to use 76 | /// Thrown if initialCapacity < 0 77 | public ShuffleBagCollection(int initialCapacity) : this(initialCapacity, new MersenneTwister()) { } 78 | /// 79 | /// Creates an empty bag with the specified initial capacity and the specified random number generator. 80 | /// 81 | /// The initial capacity to use 82 | /// The random number generator to use 83 | /// Thrown if initialCapacity < 0 84 | public ShuffleBagCollection(int initialCapacity, MersenneTwister generator) 85 | { 86 | if (initialCapacity < 0) 87 | throw new ArgumentException("Capacity must be a positive integer.", "initialCapacity"); 88 | 89 | m_generator = generator; 90 | m_data = new List(initialCapacity); 91 | } 92 | 93 | /// 94 | /// Add an item to the bag once. 95 | /// 96 | /// The item to throw into the bag. 97 | public void Add(T item) 98 | { Add(item, 1); } 99 | /// 100 | /// Adds an item to the bag multiple times. 101 | /// 102 | /// The item to throw into the bag. 103 | /// The number of times it should come back out. 104 | /// Thrown if quantity is not > 0 105 | public void Add(T item, int quantity) 106 | { 107 | if (quantity <= 0) 108 | throw new ArgumentException("Quantity must be a positive integer.", "quantity"); 109 | 110 | for (int i = 0; i < quantity; i++) 111 | { 112 | m_data.Add(item); 113 | } 114 | 115 | // Reseting the cursor to the end makes it possible to get freshly added values right away, 116 | // otherwise it would have to finish this run first. 117 | m_cursor = m_data.Count - 1; 118 | } 119 | 120 | /// 121 | /// Pulls an item out of the bag. 122 | /// 123 | /// The next item in the sequence. 124 | public T Next() 125 | { 126 | if (m_cursor < 1) 127 | { 128 | m_cursor = m_data.Count - 1; 129 | m_current = m_data[0]; 130 | return m_current; 131 | } 132 | 133 | int index = m_generator.Next(m_cursor); 134 | m_current = m_data[index]; 135 | m_data[index] = m_data[m_cursor]; 136 | m_data[m_cursor] = m_current; 137 | m_cursor--; 138 | return m_current; 139 | } 140 | 141 | /// 142 | /// The last element that was returned from Next(). Can be null, if Next() has not been called 143 | /// yet. 144 | /// 145 | public T Current 146 | { 147 | get { return m_current; } 148 | } 149 | 150 | /// 151 | /// The current capacity of the underlying storage. 152 | /// 153 | public int Capacity 154 | { 155 | get { return m_data.Capacity; } 156 | } 157 | 158 | /// 159 | /// Reduces the capacity as much as possible to save memory. 160 | /// 161 | public void TrimExcess() 162 | { 163 | m_data.TrimExcess(); 164 | } 165 | 166 | /// 167 | /// The number of elements in this bag. 168 | /// 169 | public int Size 170 | { 171 | get { return m_data.Count; } 172 | } 173 | 174 | #region IEnumerable Members 175 | 176 | /// 177 | /// 178 | /// A sequence of random elements from the bag. 179 | IEnumerator IEnumerable.GetEnumerator() 180 | { 181 | for (int i = 0; i <= Size; i++) 182 | { 183 | yield return this.Next(); 184 | } 185 | } 186 | 187 | #endregion 188 | 189 | #region IEnumerable Members 190 | 191 | /// 192 | /// 193 | /// A sequence of random elements from the bag. 194 | IEnumerator IEnumerable.GetEnumerator() 195 | { 196 | return ((IEnumerable)this).GetEnumerator(); 197 | } 198 | 199 | #endregion 200 | } 201 | } -------------------------------------------------------------------------------- /lib/SpecialFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | ///////////////////////////////////////////////////////////////////////////// 4 | // // 5 | // Unity Random // 6 | // // 7 | // special Functions from http://www.nrbook.com/a/bookcpdf/c6-1.pdf // 8 | // // 9 | // // 10 | ///////////////////////////////////////////////////////////////////////////// 11 | 12 | namespace URandom 13 | { 14 | public static class SpecialFunctions 15 | { 16 | // Builtin arrays (native .NET arrays), are extremely fast and efficient but they can not be resized. 17 | static double[] cof = new double[6] { 18 | 76.18009172947146, 19 | -86.50532032941677, 20 | 24.01409824083091, 21 | -1.231739572450155, 22 | 0.1208650973866179e-2, 23 | -0.5395239384953e-5}; 24 | 25 | // 6.1 Gamma Function, Beta Function, Factorials, Binomial Coefficients 26 | // http://www.nrbook.com/a/bookcpdf/c6-1.pdf 27 | // Return the natural log of a gamma function for xx > 0 28 | // Internal arithmetic in double precision. 29 | public static double gammln( double xx ) 30 | { 31 | double x,y,tmp,ser; 32 | 33 | int j; 34 | 35 | y = x = xx; 36 | tmp = x + 5.5; 37 | tmp -= (x + 0.5) * Math.Log(tmp); 38 | ser=1.000000000190015; 39 | 40 | for (j=0;j<=5;j++) 41 | { 42 | ser += cof[j]/++y; 43 | } 44 | 45 | return -tmp+Math.Log(2.5066282746310005 * ser/x ); 46 | } 47 | 48 | // Scale range old to any range 49 | public static float ScaleFloatToRange(float x, float newMin, float newMax, float oldMin, float oldMax) 50 | { 51 | return (x / ((oldMax - oldMin) / (newMax - newMin))) + newMin; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /lib/WaveToRgb.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace URandom 5 | { 6 | public class WaveToRgb 7 | { 8 | // CONSTS 9 | public const float MinVisibleWaveLength = 350.0f; 10 | public const float MaxVisibleWaveLength = 650.0f; 11 | public const float Gamma = 0.80f; 12 | public const int IntesityMax = 255; 13 | 14 | // CORE 15 | public static Color LinearToRgb( float linearvalue) 16 | { 17 | return WaveLengthToRgb(GetWaveLengthFromDataPoint( linearvalue, 0.0f, 1.0f)); 18 | } 19 | 20 | // WAVE LENGTH ALGORITHM 21 | private static float GetWaveLengthFromDataPoint(float x, float min, float max) 22 | { 23 | // convert data in the range min - max to wavelength 24 | float result = (x - min) / (max - min) * (MaxVisibleWaveLength - MinVisibleWaveLength) + MinVisibleWaveLength; 25 | return result; 26 | } 27 | 28 | // ADJUST ALGORITHM 29 | private static int Adjust( float color, float factor) 30 | { 31 | if (color == 0.0f) { 32 | return 0; 33 | } else { 34 | return (int) Mathf.Round( IntesityMax * Mathf.Pow(color * factor, Gamma) ); 35 | } 36 | } 37 | 38 | // WAVELENGTH TO RGB 39 | private static Color WaveLengthToRgb( float wave ) 40 | { 41 | wave = Mathf.Floor(wave); 42 | 43 | float r = 0.0f; 44 | float g = 0.0f; 45 | float b = 0.0f; 46 | float factor = 0.0f; 47 | 48 | if (wave >= 380 && wave < 440) { 49 | r = - (wave - 440) / (440 -380); 50 | g = 0.0f; 51 | b = 1.0f; 52 | } else if (wave >= 440 && wave < 490) { 53 | r = 0.0f; 54 | g = (wave - 440) / (490 - 440); 55 | b = 1.0f; 56 | } else if (wave >= 490 && wave < 510) { 57 | r = 0.0f; 58 | g = 1.0f; 59 | b = - (wave - 510) / (510 - 490); 60 | } else if (wave >= 510 && wave < 580) { 61 | r = (wave - 510) / (580 - 510); 62 | g = 1.0f; 63 | b = 0.0f; 64 | } else if (wave >= 580 && wave < 645) { 65 | r = 1.0f; 66 | g = - (wave - 645) / (645 - 580); 67 | b = 0.0f; 68 | } else if (wave >= 645 && wave <= 780) { 69 | r = 1.0f; 70 | g = 0.0f; 71 | b = 0.0f; 72 | } else { 73 | r = 0.0f; 74 | g = 0.0f; 75 | b = 0.0f; 76 | } 77 | 78 | // Let the intensity fall off near the vision limits 79 | if (wave >= 380 && wave < 420) { 80 | factor = 0.3f + 0.7f * ( wave - 380) / (420 - 380); 81 | } else if (wave >= 420 && wave < 700) { 82 | factor = 1.0f; 83 | } else if (wave >= 700 && wave <= 780) { 84 | factor = 0.3f + 0.7f * (780 - wave) / (780 - 700); 85 | } else { 86 | factor = 0.0f; 87 | } 88 | 89 | r = Adjust(r, factor); 90 | g = Adjust(g, factor); 91 | b = Adjust(b, factor); 92 | 93 | // come back to 0.0 - 1.0 94 | r = r / 255; 95 | g = g / 255; 96 | b = b / 255; 97 | 98 | Color newColor = new Color(r,g,b); 99 | return newColor; 100 | } 101 | } 102 | } 103 | 104 | --------------------------------------------------------------------------------