首页 > 编程语言 >洗牌算法学习笔记

洗牌算法学习笔记

时间:2022-09-03 18:34:31浏览次数:62  
标签:障碍物 int dateArray 洗牌 笔记 randomCoord 算法 瓦片 public

洗牌算法

Quad vs Plane

  1. Quad:

    • 两个单位三角形组成的四边形
      image
  2. Plane

    • Plane是一个10行10列一共200个单位三角形组成的
      image

三角形越多也就意味着模型顶点越多,所制作的动画和模型也就越精细;同理,如果三角形少,那么模型顶点也就越少,所能制作的效果会很具有局限性。

这里只是制作地图上的单位瓦片,所以使用Quad即可。

Z-fighting 深度冲突

在项目中,你可以试着把一个白色立方体,放在一个红色立方体的内部,当它们的一个面足够接近时,会出现很奇怪的效果。

Z-fighting

原因是:2个模型足够接近时,系统不知道该渲染哪一个。

随机生成地图的制作

  1. 首先,我们需要创建一个瓦片预制体(让它来成为构成我们地图的一部分),还有地图的大小,为了方便管理,把它们统一放在一个父物体底下,还有瓦片与瓦片间生成的空隙
    [Header("瓦片预制体")]public GameObject tilePrefab;
    [Header("地图大小")]public Vector2 mapSize;
    [Header("瓦片生成的父物体")]public Transform mapHolder;
    [Header("瓦片与瓦片之间的空隙")][Range(0,1)]public float outlinePercent;
  1. 接着就是生成地图,这里构建的想法就是以地图中心点为原点,向四周进行扩充。
  /// <summary>
    /// 生成地图
    /// 以第一个点为原点,向四周排列组合
    /// </summary>
    private void GenerateMap()
    {
        for (int i = 0; i < mapSize.x; i++)
        {
            for (int j = 0; j < mapSize.y; j++)
            {
                //向左平移一半的长度,还要扣除瓦片一半的长度(单位长度为1),让原点为中心点
                Vector3 newPos = new Vector3(-mapSize.x / 2 + 0.5F + i, 0, -mapSize.x / 2 + 0.5F + j);
                //生成物体需要先旋转90度
                GameObject spawnTile = Instantiate(tilePrefab, newPos, Quaternion.Euler(90, 0, 0));
                spawnTile.transform.SetParent(mapHolder);
                spawnTile.transform.localScale *= (1 - outlinePercent);
                
                allTilesCoord.Add(new Coord(i,j));
            }
        }
    }
  1. 接着就是障碍物的生成,这里我们设置了一个存储瓦片坐标(x,y)的结构体进行存储,然后以位置的形式让障碍物进行生成。
/// <summary>
/// 坐标结构体
/// 存储瓦片的信息
/// </summary>
[System.Serializable]
public struct Coord
{
    public int x;
    public int y;

    public Coord(int x,int y)
    {
        this.x = x;
        this.y = y;
    }
}
  1. 在生成瓦片的最后进行随机障碍物生成(障碍物的预制体和障碍物的个数)
    ...
    [Header("障碍物")] public GameObject obsPrefab;
    [Header("生成障碍物的数量")] public int obsCount;
    public List<Coord> allTilesCoord = new List<Coord>();
    /// <summary>
    /// 生成地图
    /// 以第一个点为原点,向四周排列组合
    /// </summary>
    private void GenerateMap()
    {
        ...

        //生成障碍物
        for (int i = 0; i < obsCount; i++)
        {
            Coord randomCoord = allTilesCoord[UnityEngine.Random.Range(0, allTilesCoord.Count)];
            Vector3 newPos = new Vector3(-mapSize.x / 2 + 0.5F + randomCoord.x, 0, -mapSize.x / 2 + 0.5F + randomCoord.y);
            GameObject spawnObs = Instantiate(obsPrefab, newPos, Quaternion.identity);
            spawnObs.transform.SetParent(mapHolder);
            spawnObs.transform.localScale *= (1 - outlinePercent);
        }
    }

普通随机遇到的问题

通过上面的方法后,我们经过一番调试后,发现地图确实可以生成,障碍物也是,但是,当我们在6*6的地图中生成9个障碍物时,发现了一个问题。
image

障碍物的数量和我们设置的障碍物的数量并不一致,原因是有2个障碍物重复出现在了相同的地方;我们不可能通过调整地图大小来解决出错的概率,所以下面就要用到"洗牌算法"

洗牌算法介绍

基本思路:
比如说这有10张牌,我们随机抽取了一张,每次取值的范围就是Range(0,10)之间,这也就是导致我们随机到之前抽取过牌的元凶;
洗牌算法在于,我们第一次随机到一张卡牌后,会与集合中第一张牌的位置进行互换;互换完成后我们下一次遍历就只会在Range(1,10)之间进行随机抽取。以此来避免抽到相同的卡牌。

卡牌算法的实现

通过上面"卡牌算法"的思路,我们可以根据队列"先进先出"的特点进行完成。

  1. 首先,我们需要完成的是,卡片的互换,把随机得到的卡牌与数组中第一个卡片进行互换。最后并返回随机的数组。
    /// <summary>
    /// 对所有瓦片的位置重新排序后,返回瓦片集合
    /// </summary>
    /// <returns></returns>
    public static Coord[] ShuffleCoords(Coord[] _dateArray)
    {
        for (int i = 0; i < _dateArray.Length; i++)
        {
            int randomNum = Random.Range(i, _dateArray.Length);
            
            //Swap思想:AB互换
            //Coord temp = _dateArray[randomNum];
            // _dateArray[randomNum] = _dateArray[i];
            // _dateArray[i] = temp;
            (_dateArray[randomNum], _dateArray[i]) = (_dateArray[i], _dateArray[randomNum]);
        }

        return _dateArray;
    }
  1. 之后我们创建一个队列,把拿到的随机数组依次从头部取出,再从尾部放入;我们来重改一下我们之前的代码。
    ...
    private Queue<Coord> shuffledQueue;

    ...
    /// <summary>
    /// 生成地图
    /// 以第一个点为原点,向四周排列组合
    /// </summary>
    private void GenerateMap()
    {
        ...
        //生成障碍物
        shuffledQueue = new Queue<Coord>(Utilities.ShuffleCoords(allTilesCoord.ToArray()));
        for (int i = 0; i < obsCount; i++)
        {
            Coord randomCoord = GetRandomCoord();
            Vector3 newPos = new Vector3(-mapSize.x / 2 + 0.5F + randomCoord.x, 0.5F, -mapSize.x / 2 + 0.5F + randomCoord.y);
            GameObject spawnObs = Instantiate(obsPrefab, newPos, Quaternion.identity);
            spawnObs.transform.SetParent(mapHolder);
            spawnObs.transform.localScale *= (1 - outlinePercent);
        }
    }
        /// <summary>
    /// 移除第一个坐标并放入队列的最后
    /// 队列的先进先出的特性
    /// </summary>
    /// <returns></returns>
    private Coord GetRandomCoord()
    {
        Coord randomCoord = shuffledQueue.Dequeue();
        shuffledQueue.Enqueue(randomCoord);//将移除的元素放入队列的最后,保证队列的完整性。
        return randomCoord;
    }
...
  1. 最后我们在6*6的地图上生成33个障碍物,看看有没有什么问题。
    image

以上就是"卡牌算法"核心思路的全部实现了。

sharedMaterial

感觉障碍物的颜色有些单一,我们可以设置渐变色和随机高度,来增加障碍物的多样性。

  1. 设置渐变色的开始和结束的值,并设置随机高度。
    [Header("前场景颜色,和后场景颜色")] public Color foregroundColor, backgroundColor;
    [Header("随机高度")] public float minObsHeight, maxObsHeight;
  1. 再生成障碍物的地方添加颜色和高度。
    ...
    /// <summary>
    /// 生成地图
    /// 以第一个点为原点,向四周排列组合
    /// </summary>
    private void GenerateMap()
    {
        ...

        //生成障碍物
        shuffledQueue = new Queue<Coord>(Utilities.ShuffleCoords(allTilesCoord.ToArray()));
        for (int i = 0; i < obsCount; i++)
        {
            Coord randomCoord = GetRandomCoord();
            //随机高度
            float obsHeight = Mathf.Lerp(minObsHeight, maxObsHeight, UnityEngine.Random.Range(0F, 1F));
            Vector3 newPos = new Vector3(-mapSize.x / 2 + 0.5F + randomCoord.x, obsHeight / 2, -mapSize.x / 2 + 0.5F + randomCoord.y);
            GameObject spawnObs = Instantiate(obsPrefab, newPos, Quaternion.identity);
            spawnObs.transform.SetParent(mapHolder);
            spawnObs.transform.localScale = new Vector3(1 - outlinePercent,obsHeight,1 - outlinePercent);

            #region 渐变色

            MeshRenderer meshRenderer = spawnObs.GetComponent<MeshRenderer>();
            Material material = meshRenderer.material;
            //颜色渐变,传入Lerp时需要Y轴的百分比
            //因为Color.Lerp方法是0到1之间的一个数值
            float colorPercent = randomCoord.y / mapSize.y;
            material.color = Color.Lerp(foregroundColor,backgroundColor,colorPercent);
            meshRenderer.material = material;

            #endregion
        }
    }
    ...

接着我们调整一下,参数后,看看随机出来的地图如何。
image

优化为泛型

在日常项目中,类一般都是不确定的,所以我们一般使用泛型来保证每一种类型的卡牌都可以使用。

  /// <summary>
    /// 对所有瓦片的位置重新排序后,返回瓦片集合
    /// </summary>
    /// <returns></returns>
    public static T[] ShuffleCoords<T>(T[] _dateArray)
    {
        for (int i = 0; i < _dateArray.Length; i++)
        {
            int randomNum = Random.Range(i, _dateArray.Length);
            
            //Swap思想:AB互换
            //T temp = _dateArray[randomNum];
            // _dateArray[randomNum] = _dateArray[i];
            // _dateArray[i] = temp;
            (_dateArray[randomNum], _dateArray[i]) = (_dateArray[i], _dateArray[randomNum]);
        }

        return _dateArray;
    }

标签:障碍物,int,dateArray,洗牌,笔记,randomCoord,算法,瓦片,public
From: https://www.cnblogs.com/948245132ljx/p/16653279.html

相关文章

  • 笔记本电脑显示器禁用触屏功能
    1.打开“设备管理器”2.选择“人体接口设备” 3.双击“符合HID标准的触摸屏” 4.选择“驱动程序”选项卡,点击“禁用设备” ......
  • 线性代数学习笔记
    本文含有较多公式,请耐心等待渲染。一、向量定义有大小、有方向的量称为向量,记为\(\overrightarrow{a}\)或\(\boldsymbola\),向量可以任意平移。向量以有向线段的方式......
  • 机器学习中的数值查找算法(5)——字符串查找算法(Boyer-Moore算法)
    原文链接:机器学习中的数值查找算法(5)——字符串查找算法(Boyer-Moore算法)–每天进步一点点(longkui.site)Boyer—Moore算法简称BM算法,它是在字符串查找的方法中桐KMP......
  • 献芹奏曝-Python面试题-算法-链表篇
    上一篇:献芹奏曝-Python面试题    开篇的话:本文目的是收集和归纳力扣上的算法题,希望用python语言,竭我所能做到思路最清奇、代码最简洁、方法最广泛、性能最高效,了解......
  • 排序算法整理(包括初赛)
    排序算法整理常见考点将一个乱掉的字符串排回有序(以交换为基本操作)的最少操作,就是冒泡排序。排序算法的稳定性排序算法的时间复杂度排序算法的稳定性稳定性是指排......
  • vue3项目-小兔鲜儿笔记-分类模块01
    1.二级类目-筛选区展示获取数据进行品牌和属性的渲染<template><divclass="sub-filter"v-if="filterData&&!filterDataLoading"><divclass="item"><......
  • 1、C++基础知识代码笔记
    C++课堂笔记(一)说明:此笔记是学习于B站黑马程序员的C++视频所作的,感谢黑马程序员的教学;如有什么不足之处,望各位赐教。仅供学习。第一个代码:书写helloworld#include<iost......
  • python | 算法大神左神(左程云)算法课程 二叉树部分【中】
    1.二叉树宽度......
  • BSGS exBSGS 详解(大步小步算法)
    我放弃挣扎了至少除了这个点,我的BSGSexBSGS都是可以过的,我就姑且当它没有问题了!BSGS:BigStepGiantStep额其实我也不懂这个算法和名字有什么关系,倒是有点根号分......
  • P1966 [NOIP2013 提高组] 火柴排队做题笔记
    这题和P5677一样,是从树状数组题单里翻出来的,由于开始看时感觉题解代码写的不是很清晰,就先放进了做题计划里,后来几次看这道题,但由于第一次看题可能留下了一些心理阴影以及......