1.從一個數組中隨機取出一個元素
1 var element = myArray[Random.Range(0, myArray.Length)];
2.PRD偽隨機算法, 通常用來計算暴擊率
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using UnityEngine; 5 using UnityEditor; 6 using System.IO; 7 using System.Text; 8 using System.Threading; 9 10 public class PRDCalcC : EditorWindow 11 { 12 private static readonly string obj = "lock"; 13 private static Dictionary<int, int> prdDic = new Dictionary<int, int>(); 14 private string infoStr = ""; 15 private string dataStr = "數據運算中...."; 16 17 [MenuItem("Tools/PRD_C")] 18 static void ShowWindow() 19 { 20 GetWindow<PRDCalcC>(); 21 } 22 23 private void OnGUI() 24 { 25 EditorGUILayout.BeginVertical(); 26 if (GUILayout.Button("運算數據")) 27 { 28 // 計算 1% - 100% 暴擊率范圍所有的 PRD C值 29 for (int i = 0; i <= 100; ++i) 30 { 31 int j = i; 32 // 創建線程負責具體計算 C 值 33 Thread thread = new Thread(() => 34 { 35 double p = i * 1d / 100d; // 顯示給玩家的暴擊率 36 double c = CFromP(p); // PRD算法 暴擊增量 37 int ic = (int)Math.Round(c * 100, 0); // 將百分數小數轉換為整數 38 lock (obj) 39 { 40 prdDic[j] = ic; // 計算結果存放在字典中 41 } 42 }); 43 thread.Start(); 44 } 45 } 46 GUILayout.Label(dataStr); 47 if (prdDic.Count == 101) 48 { 49 dataStr = "數據運算完畢"; 50 if (GUILayout.Button("點擊生成配置文件")) 51 { 52 try 53 { 54 CreateXml(); 55 infoStr = "配置文件生成成功!"; 56 } 57 catch (Exception e) 58 { 59 infoStr = "配置文件生成失敗!錯誤為:" + e; 60 } 61 } 62 } 63 64 GUILayout.Label(infoStr); 65 66 EditorGUILayout.EndVertical(); 67 } 68 69 // 生成 XML 文件 70 private void CreateXml() 71 { 72 string path = EditorUtility.OpenFolderPanel("選擇目標文件夾", "", "") + @"/prd.xml"; 73 StringBuilder sb = new StringBuilder(); 74 sb.Append(@"<?xml version=""1.0"" encoding=""UTF - 8"" standalone=""yes""?>"); 75 sb.Append('\n'); 76 sb.Append(@"<root xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">"); 77 sb.Append('\n'); 78 79 string xml = null; 80 lock (obj) 81 { 82 // 在主線程中 從字典中拿出多線程放入的數據,進行解析 83 foreach(var pair in prdDic) 84 { 85 sb.Append("<item>\n"); 86 sb.Append(" <p>" + pair.Key + "</p>\n"); 87 sb.Append(" <c>" + pair.Value + "</c>\n"); 88 sb.Append("</item>\n"); 89 } 90 xml = sb.ToString(); 91 sb.Clear(); 92 xml.Remove(xml.Length - 1); 93 } 94 using(FileStream fs = Directory.Exists(path) ? File.OpenWrite(path) : File.Create(path)) 95 { 96 byte[] bytes = Encoding.UTF8.GetBytes(xml); 97 fs.Write(bytes, 0, bytes.Length); 98 fs.Flush(); 99 fs.Close(); 100 } 101 lock (obj) 102 { 103 prdDic.Clear(); 104 } 105 } 106 107 // 根據 傳入 C 值,計算該C值下,最小暴擊范圍的平均暴擊率 108 private static double PFromC(double c) 109 { 110 double dCurP = 0d; 111 double dPreSuccessP = 0d; 112 double dPE = 0; 113 int nMaxFail = (int)Math.Ceiling(1d / c); 114 for (int i = 1; i <= nMaxFail; ++i) 115 { 116 dCurP = Math.Min(1d, i * c) * (1 - dPreSuccessP); 117 dPreSuccessP += dCurP; 118 dPE += i * dCurP; 119 } 120 return 1d / dPE; 121 } 122 123 // 根據傳入的暴擊率,計算 PRD 算法中的系數 C 124 private static double CFromP(double p) 125 { 126 double dUp = p; 127 double dLow = 0d; 128 double dMid = p; 129 double dPLast = 1d; 130 while (true) 131 { 132 dMid = (dUp + dLow) / 2d; 133 double dPtested = PFromC(dMid); 134 135 if (Math.Abs(dPtested - dPLast) <= 0.00005d) break; 136 137 if (dPtested > p) dUp = dMid; 138 else dLow = dMid; 139 140 dPLast = dPtested; 141 } 142 143 return dMid; 144 } 145 }
3.洗牌算法
1 /// <summary> 2 /// Knuth-Durstenfeld Shuffle算法,效率最高,會打亂原數組,時間復雜度O(n) 空間復雜度O(1) 3 /// </summary> 4 /// <typeparam name="T">數組類型</typeparam> 5 /// <param name="_array">目標數組</param> 6 public void KnuthDurstenfeldShuffle<T>(T[] _array) 7 { 8 int rand; 9 T tempValue; 10 for (int i = 0; i < _array.Length; i++) 11 { 12 rand = Random.Range(0, _array.Length - i); 13 tempValue = _array[rand]; 14 _array[rand] = _array[_array.Length - 1 - i]; 15 _array[_array.Length - 1 - i] = tempValue; 16 } 17 }
4.權重概率算法
1 //probs為權重數組, 且權重由大到小排序 2 float Choose (float[] probs) { 3 float total = 0; 4 foreach (float elem in probs) { 5 total += elem; 6 } 7 float randomPoint = Random.value * total; 8 for (int i= 0; i < probs.Length; i++) { 9 if (randomPoint < probs[i]) { 10 return i; 11 } 12 else { 13 randomPoint -= probs[i]; 14 } 15 } 16 return probs.Length - 1; 17 }
5.在一個空心圓范圍內隨機生成物體

1 using UnityEngine; 2 using System.Collections; 3 4 public class RandomRadius : MonoBehaviour { 5 public GameObject prefabs; 6 // Use this for initialization 7 void Start () { 8 for (int i = 0; i < 1000; i++) { 9 Vector2 p = Random.insideUnitCircle*3; 10 Vector2 pos = p.normalized*(2+p.magnitude); 11 Vector3 pos2 = new Vector3(pos.x,0,pos.y); 12 Instantiate(prefabs,pos2,Quaternion.identity); 13 } 14 } 15 }
6.從一個數組中隨機選擇指定個數且不重復的元素
1 int[] spawnPoints = {1, 5, 6, 8, 9, 20, 15, 10, 13}; 2 3 int[] ChooseSet (int numRequired) { 4 int[] result = new Transform[numRequired]; 5 int numToChoose = numRequired; 6 for (int numLeft = spawnPoints.Length; numLeft > 0; numLeft--) { 7 float prob = (float)numToChoose/(float)numLeft; 8 if (Random.value <= prob) { 9 numToChoose--; 10 result[numToChoose] = spawnPoints[numLeft - 1]; 11 if (numToChoose == 0) { 12 break; 13 } 14 } 15 } 16 return result; 17 }
7.在一個球體內生成隨機點
1 var randWithinRadius = Random.insideUnitSphere * radius;
8.遵循高斯分布的隨機算法(lua實現)
1 function randomNormalDistribution() 2 local u, v, w, c = 0, 0, 0, 0 3 while(w == 0 or w >= 1) 4 do 5 --//獲得兩個(-1,1)的獨立隨機變量 6 u = math.random() * 2 - 1 7 v = math.random() * 2 - 1 8 w = u * u + v * v 9 end 10 --//這里就是 Box-Muller轉換 11 c = math.sqrt((-2 * math.log(w)) / w) 12 --//返回2個標准正態分布的隨機數,封裝進一個數組返回 13 --//當然,因為這個函數運行較快,也可以扔掉一個 14 --//return [u*c,v*c]; 15 return u * c 16 end 17 18 function getNumberInNormalDistribution(mean, std_dev) 19 return mean + (randomNormalDistribution() * std_dev) 20 end 21 --//參數1表示期望值, 參數二表示差值范圍 22 getNumberInNormalDistribution(180, 10)