其他分享
首页 > 其他分享> > 《交互媒体专题设计》之瘟疫模拟 相关技术介绍

《交互媒体专题设计》之瘟疫模拟 相关技术介绍

作者:互联网

《交互媒体专题设计》之瘟疫模拟 相关技术介绍

一、生命游戏——细胞自动机

简述

细胞自动机(英语:Cellular automaton),又称格状自动机、元胞自动机,是一种离散模型,在可算性理论、数学及理论生物学都有相关研究。它是由无限个有规律、坚硬的方格组成,每格均处于一种有限状态。整个格网可以是任何有限维的。同时也是离散的。每格于t时的态由 t-1时的一集有限格的态决定。 每一格的“邻居”都是已被固定的。(每次演进时,每格均遵从同一规矩一齐演进。

三个特征

1)平行计算(parallel computation):每一个细胞个体都同时同步的改变
2)局部的(local):细胞的状态变化只受周遭细胞的影响。
3)一致性的(homogeneous):所有细胞均受同样的规则所支配

三种可变因素

在这里插入图片描述
1)计算规则
模拟生命数量稀少:当前细胞:存活状态,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态
模拟正常生存:当前细胞:存活状态,当周围有2个或3个存活细胞时, 该细胞保持原样。
模拟生命数量过多:当前细胞:存活状态,当周围有3个以上的存活细胞时,该细胞变成死亡状态。
模拟繁殖:当前细胞:死亡状态,当周围有3个存活细胞时,该细胞变成存活状态。
2)C的数值类型
每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。(如图,红色为存活,白色为死亡)
在这里插入图片描述
3)阵列的呈现形式
通过方块的形式来显示细胞,效果如下:
在这里插入图片描述

代码实现

(1)、细胞的两种状态Died,Living

public enum State
{
	Died,
	Living
};

(2)、定义细胞类

public class Cell
{
	public State currentState;
}

(3)、定义变量

public int width;  //定义宽度
	public int height;  //定义长度

	public string seed;
	public bool useRandomSeed;

	public float updateInterval = 1.0f;  //细胞进化的速度
	float refreshTime = -1f;

	int generation = 1;       //细胞进化的代数
	[Range(0, 100)]
	public int randomFillPercent;    //初始细胞存活率

	Cell[,] map;    //定义数组存放细胞
	Cell[,] mapTmp;    //细胞进化的中间变量

(4)、细胞数组初始化

void Start()
	{
		map = new Cell[width, height];
		mapTmp = new Cell[width, height];

		for (int i = 0; i < width; i++)
			for (int j = 0; j < height; j++)
			{
				map[i, j] = new Cell();
				map[i, j].currentState = State.Died;

				mapTmp[i, j] = new Cell();
				mapTmp[i, j].currentState = State.Died;
			}
		initEarth();
	}

初始化的时候,边界处的细胞都处于活着的状态,内部的细胞通过随机数的设定随机选取部分细胞赋予“活”的状态。

void initEarth()
	{
		if (useRandomSeed)
		{
			seed = Time.time.ToString();
		}

		System.Random pseudoRandom = new System.Random(seed.GetHashCode());

		for (int x = 0; x < width; x++)
		{
			for (int y = 0; y < height; y++)
			{
				if (x == 0 || x == width - 1 || y == 0 || y == height - 1)
				{
					map[x, y].currentState = State.Living;
				}
				else
				{
					map[x, y].currentState = (pseudoRandom.Next(0, 100) < randomFillPercent) ? State.Living : State.Died;
				}
			}
		}
	}

(5)、更新

void Update()
	{
		//更新频率
		if (Time.time - refreshTime > updateInterval)
		{
			print("第" + generation + "代");
			UpdateEarth();
			generation += 1;
			refreshTime = Time.time;
		}
	}

根据计算规则F进行细胞的更新

void UpdateEarth()
	{
		for (int x = 0; x < width; x++)
		{
			for (int y = 0; y < height; y++)
			{
				mapTmp[x, y].currentState = map[x, y].currentState;
				int neighbourLiveCells = GetSurroundingLiveCells(x, y);
				if (map[x, y].currentState == State.Died && neighbourLiveCells == 3)
				{
					mapTmp[x, y].currentState = State.Living;
				}
				if (map[x, y].currentState == State.Living)
				{
					if (neighbourLiveCells < 2)
					{
						mapTmp[x, y].currentState = State.Died;
					}
					else if (neighbourLiveCells > 3)
					{
						mapTmp[x, y].currentState = State.Died;
					}
					else
					{
						mapTmp[x, y].currentState = State.Living;
					}
				}
			}
		}

		for (int x = 0; x < width; x++)
			for (int y = 0; y < height; y++)
			{
				map[x, y].currentState = mapTmp[x, y].currentState;
			}
	}

获取细胞周围的存活细胞数

int GetSurroundingLiveCells(int gridX, int gridY)
	{
		int count = 0;
		for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX++)
		{
			for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY++)
			{
				if (neighbourX >= 0 && neighbourX < width && neighbourY >= 0 && neighbourY < height)
				{
					if (neighbourX != gridX || neighbourY != gridY)
					{
						count += map[neighbourX, neighbourY].currentState == State.Living ? 1 : 0;
					}
				}
			}
		}

		return count;
	}

(6)、显示
通过cube把细胞的进化进行可视化。

void OnDrawGizmos()
	{
		if (map != null)
		{
			for (int x = 0; x < width; x++)
			{
				for (int y = 0; y < height; y++)
				{
					if (map[x, y] != null)
					{
						Gizmos.color = (map[x, y].currentState == State.Living) ? Color.red : Color.white;
						Vector3 pos = new Vector3(-width / 2 + x + 0.5f, 0, -height / 2 + y + 0.5f);
						Gizmos.DrawCube(pos, new Vector3(1.0f, 1.0f, 1.0f));
					}
				}
			}
		}
	}

二、自动寻路

要实现瘟疫的模拟仿真,就要用到自动寻路技术。

下面有关群集动画的内容参考自博客UnityAI行为-----群组行为之群集动画,具体的细节请见该博文。

集群动画

群落运动是自然界中非常有趣的现象。在天空中,我们可以看见大群的候鸟南飞,在陆地上,我们可以看见羚羊群,牛群在飞快的奔跑,在海洋里,鱼群的运动更是壮观。群落和其他相关的群体,他们运动的时候都是非常的壮观,他们的气势常常让我们惊叹不已。在群落中,每一个个体都是非常的独立,然而整个群落又犹如一个整体。群体中的个体似乎是随机的,但确有一定的运动规律。最令我们感到震惊的是群落中似乎有一种中央控制,这种控制可以使每一个个体之间保持一定的距离,具有大致相同的运动方向,整个群落运动是建立在每一个个体的运动之上的,个体通过对环境的感知,来调整自己的运动方向以及各种状态。

群集动画的基本规则

在设计群集动画的时候,由一些基本原则是我们需要制定的。只有满足这些要求,我们才能基本建构出我们的动画系统。在群集动画的模拟过程中,系统会模拟群集中个体最基本的能力。群集动画中的每一个个体,都可以根据群落中其他个体的运动来决定自己的运动路径。建立一个群落动画并不是太难,但是我们必须遵循三条规则:

规则一:群落中每一个个体都必须有他自己的个人空间,如果其他的个体进入了这个安全空间,个体就要远离,从而保持个人空间不被侵占。

规则二:群落中的个体都尽量保持与群落中的其他个体运动方向保持一致。也就是说,每一个个体的运动方向是大致相同的。

规则三:每一个小的群落,如果有机会的话,假设附近没有障碍物,都会尝试与附近的群落融为一体。这在群落遇到障碍物分开,越过障碍物后又合在一起的情况时是非常重要。

unity的NavmentAgent组件

用unity的NavmentAgent组件可以实现物体的自动寻路,来实现瘟疫的模拟仿真。
NavmentAgent寻路教程

标签:map,专题,int,细胞,height,State,瘟疫,交互,currentState
来源: https://blog.csdn.net/YCSDNG/article/details/105778277