Obstacle Placement——障碍物生成
Utility
using System.Collections;
public static class Utility
{
//洗牌算法
public static T[] ShuffleArray<T>(T[] array, int seed)
{
System.Random prng = new System.Random(seed);
for (int i = 0; i < array.Length - 1; i++)
{
int randomIndex = prng.Next(i, array.Length);
T tempItem = array[randomIndex];
array[randomIndex] = array[i];
array[i] = tempItem;
}
return array;
}
}
T[] , shuffleArray
Random.Next():返回一个随机整数。
Next() | 返回一个非负随机整数。 |
---|---|
Next(Int32) | 返回一个小于所指定最大值的非负随机整数。 |
Next(Int32, Int32) | 返回在指定范围内的任意整数。 |
几种不同的洗牌算法:
//Fisher-Yates Shuffle算法
public void FisherYatesShuffle<T>(List<T> list)
{
List<T> cache = new List<T>();
int currentIndex;
while (list.Count > 0)
{
currentIndex = Random.Range(0, list.Count);
cache.Add(list[currentIndex]);
list.RemoveAt(currentIndex);
}
for (int i = 0; i < cache.Count; i++)
{
list.Add(cache[i]);
}
}
//Knuth-Durstenfeld Shuffle算法
public void KnuthDurstenfeldShuffle<T>(List<T> list)
{
//随机交换
int currentIndex;
T tempValue;
for (int i = 0; i < list.Count; i++)
{
currentIndex = Random.Range(0, list.Count - i);
tempValue = list[currentIndex];
list[currentIndex] = list[list.Count - 1 - i];
list[list.Count - 1 - i] = tempValue;
}
}
//优化,但需要一开始知道长度
public void KnuthDurstenfeldShuffle<T>(List<T> list)
{
//随机交换
int currentIndex;
T tempValue;
for (int i = list.Count - 1; i >= 0; i--)
{
currentIndex = Random.Range(0, i+1);
tempValue = list[currentIndex];
list[currentIndex] = list[i];
list[i] = tempValue;
}
}
//Inside-Out Algorithm算法
public List<T> InsideOutAlgorithm<T>(List<T> list)
{
List<T> cache = new List<T>();
for (int i = 0; i < list.Count; i++)
{
cache.Add(list[i]);
}
//随机交换
int currentIndex;
T tempValue;
for (int i = cache.Count - 1; i >= 0; i--)
{
currentIndex = Random.Range(0, i + 1);
tempValue = cache[currentIndex];
cache[currentIndex] = cache[i];
cache[i] = tempValue;
}
return cache;
}
//ReservoirSampling蓄水池抽样算法
public List<T> ReservoirSampling<T>(List<T> list, int m)
{
List<T> cache = new List<T>(m);
for (int i = 0; i < m; i++)
{
cache.Add(list[i]);
}
int currentIndex;
for (int i = m; i < list.Count; i++)
{
currentIndex = Random.Range(0, i + 1);
if (currentIndex < m)
{
cache[currentIndex] = list[i];
}
}
return cache;
}
MapGenerator
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform tilePrefab;//瓦片预制体
public Transform obstaclePrefab;//障碍物预制体
public Vector2 mapSize;//地图尺寸
[Range(0f, 1f)]
public float outlinePercent;//瓦片间隙
List<Coord> allTileCoords;//所有瓦片坐标
Queue<Coord> shuffledTileCoords;//乱序后的瓦片坐标
public int seed = 10;
void Start()
{
GenerateMap();
}
public void GenerateMap()
{
//记录所有瓦片位置
allTileCoords = new List<Coord>();
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
allTileCoords.Add(new Coord(x, y));
}
}
//乱序后的瓦片坐标存为队列
shuffledTileCoords = new Queue<Coord> (Utility.ShuffleArray(allTileCoords.ToArray(), seed));
string holderName = "Generated Map";
if (transform.Find(holderName))
{
DestroyImmediate(transform.Find(holderName).gameObject);
}
Transform mapHolder = new GameObject(holderName).transform;//创建Generated Map集合瓦片
mapHolder.parent = transform;//将Generated Map父对象设置为为MapGenerator
//循环创建瓦片
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
Vector3 tilePosition = CoordToPosition(x,y);//居中
Transform newTile = Instantiate(tilePrefab, tilePosition, Quaternion.Euler(Vector3.right * 90)) as Transform;
newTile.localScale = Vector3.one * (1 - outlinePercent);
newTile.parent = mapHolder;//将瓦片父对象设置为Generated Map
}
}
int obstacleCount = 10;//障碍物数量
for (int i = 0; i < obstacleCount; i++)
{
Coord randomCoord = GetRandomCoord();//获得队列中第一个的坐标
Vector3 obstaclePosition = CoordToPosition(randomCoord.x,randomCoord.y);//坐标到实际坐标转换
Transform newobstacle = Instantiate(obstaclePrefab, obstaclePosition + Vector3.up * 0.5f, Quaternion.identity) as Transform;
newobstacle.parent = mapHolder;//将障碍物父对象设置为Generated Map
}
}
//坐标到实际坐标转换
Vector3 CoordToPosition(int x, int y)
{
return new Vector3(-mapSize.x / 2 + 0.5f + x, 0, -mapSize.y / 2 + 0.5f + y);
}
//
public Coord GetRandomCoord()
{
Coord randomCoord = shuffledTileCoords.Dequeue();//移除并返回在 Queue 的开头的对象。
shuffledTileCoords.Enqueue(randomCoord);//向 Queue 的末尾添加一个对象。
return randomCoord;
}
public struct Coord
{
//Coord结构体存储坐标
public int x;
public int y;
public Coord(int x, int y)
{
this.x = x;
this.y = y;
}
}
}
List
序号 | 方法名 & 描述 |
---|---|
1 | Add() 将东西加入到列表的最后。 |
2 | Remove() 删掉项中第一个匹配你想删除的条件的项(删去第一个匹配此条件的项)。 |
3 | Clear() 清空所有项。 |
4 | Sort() 用系统默认的方式对项进行排序。 |
5 | Contains() 查看某项是否存在于列表中。 |
Queue
序号 | 方法名 & 描述 |
---|---|
1 | public virtual void Clear(); 从 Queue 中移除所有的元素。 |
2 | public virtual bool Contains( object obj ); 判断某个元素是否在 Queue 中。 |
3 | public virtual object Dequeue(); 移除并返回在 Queue 的开头的对象。 |
4 | public virtual void Enqueue( object obj ); 向 Queue 的末尾添加一个对象。 |
5 | public virtual object[] ToArray(); 复制 Queue 到一个新的数组中。 |
6 | public virtual void TrimToSize(); 设置容量为 Queue 中元素的实际个数。 |
struct:在 C# 中,结构体是值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据。struct 关键字用于创建结构体。
结构体是用来代表一个记录。
拓展:
- C#Shuffle算法(洗牌算法、抽样算法)
- C#中如何选择使用T[]或List
- Random.Next 方法 (System) | Microsoft Learn
- C# 集合(Collection)
- C# 队列(Queue)
- List 构造函数 (System.Collections.Generic)
- C# 结构体(Struct)