游戏中的随机算法

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('
');
76         sb.Append(@"<root xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">");
77         sb.Append('
');
78 
79         string xml = null;
80         lock (obj)
81         {
82             // 在主线程中 从字典中拿出多线程放入的数据,进行解析
83             foreach(var pair in prdDic)
84             {
85                 sb.Append("<item>
");
86                 sb.Append("    <p>" + pair.Key + "</p>
");
87                 sb.Append("    <c>" + pair.Value + "</c>
");
88                 sb.Append("</item>
");
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)

 

原文地址:https://www.cnblogs.com/tqw1215/p/14759919.html