当前位置: 首页 > news >正文

Unity开发中常用的洗牌算法

 

在Unity游戏开发中,洗牌算法(Shuffle Algorithm)是一种常用的技术,主要用于随机化数组或列表元素的顺序。这在卡牌游戏、随机道具生成、敌人出场顺序等场景中非常有用。

基本洗牌算法

1. Fisher-Yates洗牌算法

这是最经典且高效的洗牌算法,时间复杂度为O(n)。

// Fisher-Yates洗牌算法
public static void Shuffle<T>(T[] array)
{int n = array.Length;for (int i = 0; i < n; i++){// 在剩余元素中随机选择一个int r = i + Random.Range(0, n - i);// 交换当前元素和随机选择的元素T temp = array[r];array[r] = array[i];array[i] = temp;}
}

Unity特定实现

1. 使用Unity的Random类

using UnityEngine;
using System.Collections.Generic;public class Shuffler : MonoBehaviour
{public static void ShuffleArray<T>(T[] array){for (int i = array.Length - 1; i > 0; i--){int j = Random.Range(0, i + 1);T temp = array[i];array[i] = array[j];array[j] = temp;}}
}

2. 洗牌并返回新列表

public static List<T> ShuffleList<T>(List<T> inputList)
{List<T> shuffledList = new List<T>(inputList);int n = shuffledList.Count;while (n > 1){n--;int k = Random.Range(0, n + 1);T value = shuffledList[k];shuffledList[k] = shuffledList[n];shuffledList[n] = value;}return shuffledList;
}

高级应用

1. 可重复的随机洗牌(使用种子)

public static void ShuffleWithSeed<T>(T[] array, int seed)
{System.Random rng = new System.Random(seed);int n = array.Length;while (n > 1){n--;int k = rng.Next(n + 1);T value = array[k];array[k] = array[n];array[n] = value;}
}

2. 权重洗牌算法

当元素有不同的出现概率时:

public static T WeightedShuffle<T>(List<T> elements, List<float> weights)
{if (elements.Count != weights.Count){Debug.LogError("元素和权重数量不匹配");return default(T);}float totalWeight = 0f;foreach (float weight in weights){totalWeight += weight;}float randomValue = Random.Range(0f, totalWeight);float weightSum = 0f;for (int i = 0; i < elements.Count; i++){weightSum += weights[i];if (randomValue <= weightSum){return elements[i];}}return elements[elements.Count - 1];
}
public class Deck : MonoBehaviour
{public List<Card> cards = new List<Card>();public void ShuffleDeck(){for (int i = 0; i < cards.Count; i++){int randomIndex = Random.Range(i, cards.Count);Card temp = cards[i];cards[i] = cards[randomIndex];cards[randomIndex] = temp;}}public Card DrawCard(){if (cards.Count == 0) return null;Card drawnCard = cards[0];cards.RemoveAt(0);return drawnCard;}
}

在游戏开发(特别是卡牌游戏如炉石传说)和计算机科学中,随机性分为真随机(True Random)​伪随机(Pseudo-Random)​两种类型,它们有着本质的区别和应用场景。

真随机(True Random)

基本概念

真随机是指完全不可预测、无模式的随机性,通常来源于物理世界的随机现象。

特点

  • 不可预测性​:无法通过任何方法预测下一个结果
  • 无周期性​:不会出现重复的模式
  • 来源​:通常来自物理现象(如大气噪声、放射性衰变等)

实现方式

// 使用系统提供的真随机数生成器(基于硬件熵源)
using System.Security.Cryptography;public static int TrueRandom(int min, int max)
{using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()){byte[] randomNumber = new byte[4];rng.GetBytes(randomNumber);int value = BitConverter.ToInt32(randomNumber, 0);return Math.Abs(value % (max - min)) + min;}
}

应用场景

  • 加密安全场景(如生成加密密钥)
  • 高安全性赌博机
  • 科学实验中的随机抽样

伪随机(Pseudo-Random)

基本概念

伪随机是通过确定性算法生成的看似随机的数列,实际上是完全可预测的。

特点

  • 可重现性​:使用相同种子会产生相同的随机序列
  • 周期性​:经过足够长的序列后会重复
  • 高效性​:计算速度快,资源消耗低

实现方式

// Unity/C#中的伪随机实现
public static int PseudoRandom(int min, int max)
{// System.Random或UnityEngine.Random都是伪随机return UnityEngine.Random.Range(min, max); // 或者使用特定种子System.Random seededRandom = new System.Random(12345);return seededRandom.Next(min, max);
}

高级主题:伪随机的"公平性"调整

游戏开发者常对伪随机进行修改以改善玩家体验:

// "伪伪随机" - 防止连续倒霉的情况
public class FairRandom
{private Dictionary<string, int> outcomeCount = new Dictionary<string, int>();public bool WeightedRandom(string eventId, float baseProbability){if (!outcomeCount.ContainsKey(eventId)){outcomeCount[eventId] = 0;}// 根据历史次数动态调整概率float adjustedProb = baseProbability * (outcomeCount[eventId] + 1);bool result = UnityEngine.Random.value < adjustedProb;if (result){outcomeCount[eventId] = 0;}else{outcomeCount[eventId]++;}return result;}
}

真随机与伪随机的视觉表现差异

在Unity中,两种随机在视觉效果上可能表现出不同模式:

// 伪随机点分布(可能可见模式)
void OnDrawGizmos()
{System.Random prng = new System.Random(123);for (int i = 0; i < 1000; i++){float x = (float)prng.NextDouble();float y = (float)prng.NextDouble();Gizmos.DrawSphere(new Vector3(x, y, 0), 0.01f);}
}// 真随机点分布(更均匀)
void OnDrawGizmos()
{using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()){for (int i = 0; i < 1000; i++){byte[] bytes = new byte[8];rng.GetBytes(bytes);double x = BitConverter.ToDouble(bytes, 0) % 1.0;double y = BitConverter.ToDouble(bytes, 4) % 1.0;Gizmos.DrawSphere(new Vector3((float)x, (float)y, 0), 0.01f);}}
}

总结

  1. 游戏开发中90%的情况使用伪随机​:性能好、可重现、易调试
  2. 真随机用于安全关键领域​:如加密、真实赌博游戏
  3. 炉石等在线游戏​:使用服务器控制的伪随机保证公平性和同步性
  4. 好的随机设计​:不仅要考虑算法,还要考虑玩家心理感受

理解这两种随机性的区别和实现方式,可以帮助开发者根据具体需求做出更合适的选择。

http://www.lryc.cn/news/586363.html

相关文章:

  • 程序改错---字符串
  • 【离线数仓项目】——电商域DIM层开发实战
  • [特殊字符] 实时数据洪流突围战:Flink+Paimon实现毫秒级分析的架构革命(附压测报告)——日均百亿级数据处理成本降低60%的工业级方案
  • Spring Boot 2.4+中bootstrap.yml加载顺序的源码深度解析
  • 北京高铁3h可达城市周末游攻略
  • 堆内存的详细结构以及java中内存溢出和排查方式
  • 大模型量化相关
  • 钉钉企业应用开发实战:从零构建组织级业务工具
  • cuDNN 的 IMPLICIT_GEMM 算法
  • bp使用爆破模块破解pikachu的登陆密码
  • C++11之emplace
  • 【C++】封装红黑树模拟实现set和map
  • 支付宝购买功能的使用
  • EPLAN 电气制图(七):电缆设计全攻略
  • 从0设计一个短链接服务:如何实现尽可能短、可变长的短网址系统?
  • NLP:RNN文本生成案例分享
  • 【MediaSoup】MS_DUMP打印转换为PLOGI的形式
  • CTFHub————Web{信息泄露[Git泄露(Stash、Index)]}
  • React - createPortal
  • React useState原理解密:从源码到实战
  • python的婚纱影楼管理系统
  • 【深度学习】常见评估指标Params、FLOPs、MACs
  • 单向链表反转 如何实现
  • 电子电气架构 --- ECU存储与计算资源冗余设计规范
  • 深入详解:决策树在医学影像脑部疾病诊断中的应用与实现
  • 使用ESM3蛋白质语言模型进行快速大规模结构预测
  • Syntax Error: TypeError: Cannot set properties of undefined (setting ‘parent‘)
  • SSM项目上传文件的方式及代码
  • AI图像修复工具CodeFormer实测:马赛克去除与画质增强效果评测
  • 基于随机森林的金融时间序列预测系统:从数据处理到实时预测的完整流水线