文接上一篇
如何使用这些数据?
首先我们需要把这些生成的数据读取出来保存到一个int二维数组里
代码如下
public Vector2 startPos;//地图开始点public Vector2 Scale;//地图大小public Texture2D renderTexture;//用来渲染的战争迷雾贴图private Texture2D orignTexture;//原始没迷雾贴图public Node[,] map;//地图可见度数组public int[,] Bytemap;//地图障碍物和可行走点地图void Init()//初始化因为是demo我没有独自去生成地图数据然后读取,所以开始游戏的时候再去生成地图数据{Bytemap = new int[(int)Scale.x, (int)Scale.y];//这个是地图数据scale的x和y是代表地图的长宽map =new Node[(int)Scale.x, (int)Scale.y];//node下面有介绍是用来记录点的可见度orignTexture = new Texture2D((int)Scale.x , (int)Scale.y );//这是初始的贴图renderTexture = new Texture2D((int)Scale.x, (int)Scale.y);//这是用来渲染的战争迷雾贴图int pre = 4;//因为地图精度是128*128的如果按照这个直接使用NavMesh.SamplePosition来生成数据会导致不精确所以我让它乘上4倍每4个里有3个以上是可行走的对应的点就是可行走的如果不到三个就是障碍物int y =(int) Scale.y * pre;int x = (int)Scale.x * pre;for (int i = 0; i < y; ++i)//遍历可行走网格点{for (int j = 0; j < x; ++j){bool flag = false;//是否可见NavMeshHit hit;//可行走网格的碰撞信息for (int k = -10; k < 10; ++k){//这个是y轴偏移,因为行走网格位置y轴上可能有不同,这样就可以正常获得当前点是不是可行走网格if (NavMesh.SamplePosition(new Vector3(startPos.x,0,startPos.y ) + new Vector3(j*( accuracy/ pre), k, i* (accuracy/ pre)), out hit, 0.5f, NavMesh.AllAreas)){//如果当前点有行走网格的让bytemap对应下标的值+30没有行走网格的下面就让他减40,因为大于0是可行走,小于0是不可以行走,所以一个点需要3个以上都是可行走的才算可以行走,我让它获取网格的数据是4个精细的点代表一个点flag = true;Bytemap[j/ pre, i/ pre] += 30;if (map[j / pre, i / pre] == null){//如果当前node数组是null就给他生成一个nodemap[j / pre, i / pre] = new Node(j / pre, i / pre);}if ( Bytemap[j/ pre, i/ pre]>0){orignTexture.SetPixel(j / pre, i / pre, Color.black);//如果可以行走设置原始地图贴图对应点是黑色}break;}}if (!flag)//如果不可以走就是让bytemap对应点的值-40{Bytemap[j / pre, i / pre] -= 40;if (map[j / pre, i / pre]==null){map[j / pre, i / pre] = new Node(j / pre, i / pre);map[j / pre, i / pre].intensity = 0; //这个是当前点的能见度刚开始将它设置成0}if (Bytemap[j / pre, i / pre] <= 0){orignTexture.SetPixel(j / pre, i / pre, Color.red);//如果不可以行走设置原始地图贴图对应点是红色}}}}orignTexture.filterMode = FilterMode.Point;orignTexture.wrapMode = TextureWrapMode.Clamp;orignTexture.Apply();}
需要创建一个Node类这个类是当一个点可以见的时候给对应的intensity赋值,intensity越大就是这个点能见度越大,x y是代表的对应地图点下标
public class Node
{public int x, y;private int width=1, height=1;public float intensity;public Node(int v1, int v2){this.x = v1;this.y = v2;}public Node(){}public int X{get { return x; }}public int Y{get { return y; }}public int Width { get { return width; } }public int Height { get { return height; } }
}
判断点是否可见的方法
/// <summary>/// /// </summary>/// <param name="player">玩家的点</param>/// <param name="obstacle">障碍物的点</param>/// <param name="target">要判断是否可见的点</param>bool isVisable(Node player, Node obstacle, Node target){if (EyeManager.Instance.Bytemap[(int)target.x, (int)target.y] <= 0){//如果目标点也是障碍物就不可见return false;}if (distance(player,target)>radius){//如果目标点到玩家的距离大于视野范围的就不可见return false;}if (distance(player, target) <= distance(player, obstacle)){//因为我用向量判断所以导致有些点本来可以看见的但是向量也是在两个向量之间导致不可见所以判断障碍物到玩家的点距离是否小于障碍物到玩家的点return true;}if (player.Y == obstacle.Y && target.Y == obstacle.Y){//因为我用向量判断所以导致有些点本来可以看见的但是向量也是在两个向量之间导致不可见if (obstacle.x > player.x && obstacle.x < target.x){return false;}if (obstacle.x < player.x && obstacle.x > target.x){return false;}}if (obstacle.X==player.X&&target.X==obstacle.X){//因为我用向量判断所以导致有些点本来可以看见的但是向量也是在两个向量之间导致不可见if (obstacle.y > player.y && obstacle.y < target.y){return false;}if (obstacle.y < player.y && obstacle.y >target.y){return false;}}if (player.X == obstacle.X && target.X == obstacle.X){//因为我用向量判断所以导致有些点本来可以看见的但是向量也是在两个向量之间导致不可见if (distance(player, target) > distance(player, obstacle)){return false;}}//在下面我把目标点和障碍物位置分成四个象限然后每个象限用不同的计算方式来计算是否可见int dir = 0;//0障碍物在人右边,1在人左边dir = player.X > obstacle.X ? 1 : 0;double a = 0;bool isvisible = true;if (obstacle.Y > player.Y && dir == 0){//第一个象限double targety = target.Y + target.Height - player.Y;double targetx = target.X + target.Width - player.X;a = targety / targetx;double obstacley = obstacle.Y + obstacle.Height - player.Y;double obstaclex = obstacle.X + target.Width - player.X;if (((obstaclex * a <= obstacley) && (obstaclex * a >= (obstacley - obstacle.Height)))|| ((obstaclex - obstacle.Width) * a <=obstacley && (obstaclex - obstacle.Width) * a >= (obstacley - obstacle.Height))|| ((obstaclex * a >= obstacley && ((obstaclex - obstacle.Width) * a <= (obstacley - obstacle.Height))))){isvisible = false;}}else if (obstacle.Y > player.Y && dir == 1){//第二个象限double targety = target.Y + target.Height - player.Y;double targetx = target.X - player.X;a = targety / targetx;double obstacley = obstacle.Y + target.Height - player.Y;double obstaclex = obstacle.X - player.X;if (((obstaclex * a <= obstacley) && (obstaclex * a >= (obstacley - obstacle.Height)))|| ((obstaclex - obstacle.Width) * a <= obstacley && (obstaclex - obstacle.Width) * a >= (obstacley + obstacle.Height))|| (obstaclex * a >= obstacley && ((obstaclex + obstacle.Width) * a <= (obstacley - obstacle.Height)))){isvisible = false;}}else if (obstacle.Y <= player.Y && dir == 1){//第三个象限double targety = target.Y - player.Y;double targetx = target.X - player.X;a = targety / targetx;double obstacley = obstacle.Y - player.Y;double obstaclex = obstacle.X - player.X;if (((obstaclex * a >= obstacley) && (obstaclex * a <= (obstacley + obstacle.Height)))|| ((obstaclex + obstacle.Width) * a >= obstacley && (obstaclex + obstacle.Width) * a <= (obstacley + obstacle.Height))|| (obstaclex * a <= obstacley && (obstaclex + obstacle.Width) * a >= (obstacley + obstacle.Height))){isvisible = false;}}else if (obstacle.Y <= player.Y && dir == 0){//第四个象限double targety = target.Y - player.Y;double targetx = target.X + target.Width - player.X;a = targety / targetx;double obstacley = obstacle.Y - player.Y;double obstaclex = obstacle.X + obstacle.Width - player.X;if (((obstaclex * a >= obstacley) && (obstaclex * a <= (obstacley + obstacle.Height)))|| ((obstaclex - obstacle.Width) * a >= obstacley && (obstaclex - obstacle.Width) * a <= (obstacley + obstacle.Height))|| ((obstaclex * a <= obstacley && (obstaclex - obstacle.Width) * a >= (obstacley + obstacle.Height)))){isvisible = false;}}return isvisible;}
计算周围点可见度的详细方法
先获得要遍历的点
//因为一个英雄只关心自己周围的点是否可见所以我们先获得玩家的点和周围要遍历的点int posx = (int)((pos.x - EyeManager.Instance.startPos.x)/ EyeManager.Instance.accuracy);//玩家的x下标
int posy = (int)((pos.y - EyeManager.Instance.startPos.y) / EyeManager.Instance.accuracy);//玩家的y下标int xStart = (int)(posx - radius < 0 ? 0 : posx - radius);//x轴开始遍历的下标
int yStart = (int)(posy - radius < 0 ? 0 : posy - radius);//y轴开始遍历的下标
int xEnd = (int)(posx + radius >= EyeManager.Instance.Scale.x ? EyeManager.Instance.Scale.x - 1 : posx + radius);//x轴结束遍历的下标
int yEnd = (int)(posy + radius >= EyeManager.Instance.Scale.y ? EyeManager.Instance.Scale.y - 1 : posy + radius);//y轴结束遍历的下标
public Node[] CalcVisibleNodes(int[,] map)//传入地图障碍物数据来计算
{List<Node> obstacles= new List<Node>();//周围障碍物for (int i = xStart; i <= xEnd; i++)//先遍历周围障碍物{for (int j = yStart; j <= yEnd; j++){if ((map[i, j] <= 0)//因为小于零所以是障碍物{Node node = EyeManager.Instance.map[i, j];//获得相应的点obstacles.Add(node);//添加到障碍物列表}}}
for (int i = xStart; i <= xEnd; i++){for (int j = yStart; j <= yEnd; j++){bool isVisible = true;//当前点是否可见Node target =EyeManager.Instance.map[i, j];float dis = distance(player, target);//目标点和玩家的距离for (int n = 0; n < obstacles.Count; n++)//遍历障碍物{if (!isVisable(player,obstacles1[n],target)){//当前点有被周围一个障碍物遮挡就不可见isVisible = false;//设置标识不可见break;} } if(isVisible ){float intensity = Mathf.Clamp((float)((radius - dis) / (radius - (innerradius * radius))),0, 1);//按照目标点到玩家距离来设置可见度target.intensity += intensity;visibles.Add(target); //添加到可见列表 } }}return visibles;}
如何生成战争迷雾
由以上方法我们可以获得玩家周围的可见点和可见度
for (int i = 0; i < nodes.Count; i++)//循环遍历获得的可见点这些点是多线程计算获得的详细方法下一篇再说{float intensity= Mathf.Clamp((float)nodes[i].intensity, 0, 1.0f);Color color2 = Color.Lerp(renderTexture.GetPixel(nodes[i].x, nodes[i].y), Color.white * intensity, 0.8f);//进行一个插值计算这样变化就不会很生硬renderTexture.SetPixel(nodes[i].x, nodes[i].y, color2);//然后设置相应点的颜色nodes[i].intensity =0;}nodes.Clear();renderTexture.Apply();//这就是我们要的战争迷雾贴图
如何使用战争迷雾贴图
下一篇再讲