unity如何实现战争迷雾?思路一

unity如何实现战争迷雾?思路一

断更很久了,刚好今天放假,写一个unity下实现战争迷雾的思路.

效果如下: 

 

思路如下:

建一个plane作为地面,UI中的rawimage放在最上层作为迷雾显示,cube作为主角移动.cube每次移动,将它的坐标转化为rawimage上相对位置的点,然后用texture2dsetpixel方法逐像素清除出一个区域出来.

扫描二维码关注公众号,回复: 11161849 查看本文章

 

 左下角rawimage显示小地图,有单独一个camera专门将迷雾绘制到小地图中.

 

具体实现:

1.新建plane,cube,分别作为地面和主角,并把场景中的Main Camera作为cube的子物体.如下设置.

 

 

 

 project窗口创建一个material并赋给cube方便改颜色.

 

2.新建一个canvas和一个rawimage,并按如下设置.

 

 

 

  

3.新建一个gameobject,在它的下面,新建一个camera,新建一个canvas并在它的下面新建image,rawimage.设置如下.

 

 

 project窗口创建一个rendertexture并赋给camerarawimage.

 

 

 

 image用于小地图的背景框,也可忽略.

 

 

  

3.新建一个gameobject,并加上脚本.

 

4.首先,先将迷雾初始化出来.打开编辑FogOfWar脚本.定义fogRawImage,worldcanvas下的rawimage.定义fogDensity ,迷雾的像素密度,由多少个点组成.定义fogTexture,赋给fogRawImage,后续的像素颜色更改,只需对fogTexture进行.InitializeTheFog方法将迷雾初始化为黑色.

 1 public RawImage fogRawImage;
 2 
 3 public Vector2Int fogDensity = new Vector2Int(100, 100);
 4 
 5 private Texture2D fogTexture; 
 6 
 7 void Start()
 8 {
 9     fogTexture = new Texture2D(fogDensity.x, fogDensity.y);
10 
11     fogRawImage.texture = fogTexture; 
12 
13     InitializeTheFog();
14 }
15 
16 void InitializeTheFog()
17 {
18     int pixelCount = fogDensity.x * fogDensity.y;
19     //将迷雾的默认颜色设置为黑色
20     Color[] blackColors = new Color[pixelCount];
21     for (int i = 0; i < pixelCount; i++)
22     {
23       blackColors[i] = Color.black;
24     }
25     fogTexture.SetPixels(blackColors); 
26 
27     fogTexture.Apply();
28 }

   

5.接着,设置要消除的形状的坐标数组.定义beEliminatedShapeSize ,要消除的形状的长和宽.定义shapeLocalPosition,这个形状的点分布数组,假设中心为(0,0),后续只需要将要消除的点的坐标跟这个数组所有值相加,即可得到该点出现的形状的所有坐标.InitializeTheShape方法是初始化视野的形状,此处是矩形,如果想将视野做成椭圆形,三角形,六角形,修改InitializeTheShape中的写法然后赋给shapeLocalPosition.

 1   public Vector2Int beEliminatedShapeSize = new Vector2Int(8, 6);
 2   private Vector2Int[] shapeLocalPosition;
 3   void Start()
 4   {
 5       //...
 6 
 7       InitializeTheShape();
 8   }
 9 
10     void InitializeTheShape()
11     {
12         int pixelCount = beEliminatedShapeSize.x * beEliminatedShapeSize.y;
13         shapeLocalPosition = new Vector2Int[pixelCount];
14 
15         int halfX = Mathf.FloorToInt(beEliminatedShapeSize.x * 0.5f);
16         int remainingX = beEliminatedShapeSize.x - halfX;
17         int halfY = Mathf.FloorToInt(beEliminatedShapeSize.y * 0.5f);
18         int remainingY = beEliminatedShapeSize.y - halfY;
19 
20         int index = 0;
21         for (int y = -halfY; y < remainingY; y++)
22         {
23             for (int x = -halfX; x < remainingX; x++)
24             {
25                 shapeLocalPosition[index] = new Vector2Int(x, y);
26                 index++;
27             }
28         }
29   }

6.接着是在texture中消除出一个形状来.这里需要注意的是,cube是在世界坐标中,通过消除rawimage中的像素透明度来实现获得视野,所以需要将cube的坐标转换为rawimage(texture2d)相对应的点.因为texture是左下角为原点,向右为正x,向上为正y,如下图.

 

 所以,一种思路就是将cube的世界最左下的一点作为它的原点,然后根据cube的位置和这个原点的位置偏移量,换算成texture中相对应的点,也就是plane的左下角的坐标.下图,是从上往下看的视角.

 

定义cubeTransform,cubetransform.定义planeMeshCollider,用于获取plane的尺寸.定义planeOriginPoint,储存世界坐标中cube的假定原点.定义worldSize,地面的尺寸,也就是plane的尺寸.EliminateFog方法,获得当前cube位置的视野.

 1     public Transform cubeTransform;
 2     public MeshCollider planeMeshCollider;
 3 
 4     private Vector2 planeOriginPoint;
 5     private Vector2 worldSize;
 6     
 7     void Start()
 8     {
 9         //...
10 
11         worldSize = new Vector2(planeMeshCollider.bounds.size.x, planeMeshCollider.bounds.size.z);
12      //将plane的坐标减去它尺寸的一半,即可得到它的左下角的坐标
13         planeOriginPoint = new Vector2(planeMeshCollider.transform.position.x - worldSize.x * 0.5f, planeMeshCollider.transform.position.z - worldSize.y * 0.5f);
14 
15         InitializeTheShape();
16         InitializeTheFog();
17 
18         EliminateFog();
19     }
20 
21     void EliminateFog()
22     {
23         Vector2 cubePos = new Vector2(cubeTransform.position.x, cubeTransform.position.z);
24      //相对假定原点的距离比例,因为是世界坐标,两个点相减有可能是负数,texture中不存在负数的坐标,所以转化为正数.
25         Vector2 originDistanceRatio = (cubePos - planeOriginPoint) / worldSize;
26         originDistanceRatio.Set(Mathf.Abs(originDistanceRatio.x), Mathf.Abs(originDistanceRatio.y));
27      //距离比例乘以密度,即可知道cube相当在texture中的点即可计算出来
28         Vector2Int fogCenter = new Vector2Int(Mathf.RoundToInt(originDistanceRatio.x * fogDensity.x), Mathf.RoundToInt(originDistanceRatio.y * fogDensity.y));
29         for (int i = 0; i < shapeLocalPosition.Length; i++)
30         {
31             int x = shapeLocalPosition[i].x + fogCenter.x;
32             int y = shapeLocalPosition[i].y + fogCenter.y;
33        //因为消除迷雾的形状是比cube的位置还要大的,在最边缘的时候,消除的像素点的坐标会超出texture范围,所以超出部分忽略.
34             if (x < 0 || x >= fogDensity.x || y < 0 || y >= fogDensity.y)
35                 continue;
36 
37             fogTexture.SetPixel(x, y, Color.clear);
38         }
39 
40         fogTexture.Apply();
41     }

7.设置cube的移动控制,并在每次移动消除迷雾.这里简单写一个.

 1    public float cubeMoveSpeed = 0.1f;
 2     private void Update()
 3     {
 4         if (Input.anyKey)
 5         {
 6             if (Input.GetKey(KeyCode.W))
 7             {
 8                 cubeTransform.position += Vector3.forward * cubeMoveSpeed;
 9             }
10             else if (Input.GetKey(KeyCode.S))
11             {
12                 cubeTransform.position += Vector3.back * cubeMoveSpeed;
13             }
14             else if (Input.GetKey(KeyCode.A))
15             {
16                 cubeTransform.position += Vector3.left * cubeMoveSpeed;
17             }
18             else if (Input.GetKey(KeyCode.D))
19             {
20                 cubeTransform.position += Vector3.right * cubeMoveSpeed;
21             }
22 
23             EliminateFog();
24         }
25 }

8.完成后的场景结构和FogOfQar脚本设置如下.

 

9.完整代码如下:

  1 using UnityEngine;
  2 using UnityEngine.UI;
  3 
  4 public class FogOfWar : MonoBehaviour
  5 {
  6     public RawImage fogRawImage;
  7     public MeshCollider planeMeshCollider;
  8     public Transform cubeTransform;
  9 
 10     public float cubeMoveSpeed = 0.1f;
 11 
 12     public Vector2Int fogDensity = new Vector2Int(100, 100);
 13     public Vector2Int beEliminatedShapeSize = new Vector2Int(8, 6);
 14 
 15     private Texture2D fogTexture;
 16 
 17     private Vector2Int[] shapeLocalPosition;
 18 
 19     private Vector2 planeOriginPoint;
 20     private Vector2 worldSize;
 21 
 22     // Start is called before the first frame update
 23     void Start()
 24     {
 25         fogTexture = new Texture2D(fogDensity.x, fogDensity.y);
 26         fogRawImage.texture = fogTexture;
 27 
 28         worldSize = new Vector2(planeMeshCollider.bounds.size.x, planeMeshCollider.bounds.size.z);
 29         //将plane的坐标减去它尺寸的一半,即可得到它的左下角的坐标
 30         planeOriginPoint = new Vector2(planeMeshCollider.transform.position.x - worldSize.x * 0.5f, planeMeshCollider.transform.position.z - worldSize.y * 0.5f);
 31 
 32         InitializeTheShape();
 33         InitializeTheFog();
 34 
 35         EliminateFog();
 36     }
 37 
 38     private void Update()
 39     {
 40         if (Input.anyKey)
 41         {
 42             if (Input.GetKey(KeyCode.W))
 43             {
 44                 cubeTransform.position += Vector3.forward * cubeMoveSpeed;
 45             }
 46             else if (Input.GetKey(KeyCode.S))
 47             {
 48                 cubeTransform.position += Vector3.back * cubeMoveSpeed;
 49             }
 50             else if (Input.GetKey(KeyCode.A))
 51             {
 52                 cubeTransform.position += Vector3.left * cubeMoveSpeed;
 53             }
 54             else if (Input.GetKey(KeyCode.D))
 55             {
 56                 cubeTransform.position += Vector3.right * cubeMoveSpeed;
 57             }
 58 
 59             EliminateFog();
 60         }
 61     }
 62 
 63     void InitializeTheShape()
 64     {
 65         int pixelCount = beEliminatedShapeSize.x * beEliminatedShapeSize.y;
 66         shapeLocalPosition = new Vector2Int[pixelCount];
 67 
 68         int halfX = Mathf.FloorToInt(beEliminatedShapeSize.x * 0.5f);
 69         int remainingX = beEliminatedShapeSize.x - halfX;
 70         int halfY = Mathf.FloorToInt(beEliminatedShapeSize.y * 0.5f);
 71         int remainingY = beEliminatedShapeSize.y - halfY;
 72 
 73         int index = 0;
 74         for (int y = -halfY; y < remainingY; y++)
 75         {
 76             for (int x = -halfX; x < remainingX; x++)
 77             {
 78                 shapeLocalPosition[index] = new Vector2Int(x, y);
 79                 index++;
 80             }
 81         }
 82     }
 83 
 84     void InitializeTheFog()
 85     {
 86         int pixelCount = fogDensity.x * fogDensity.y;
 87         //将迷雾的默认颜色设置为黑色
 88         Color[] blackColors = new Color[pixelCount];
 89         for (int i = 0; i < pixelCount; i++)
 90         {
 91             blackColors[i] = Color.black;
 92         }
 93         fogTexture.SetPixels(blackColors);
 94 
 95         fogTexture.Apply();
 96     }
 97 
 98     void EliminateFog()
 99     {
100         Vector2 cubePos = new Vector2(cubeTransform.position.x, cubeTransform.position.z);
101         //相对假定原点的距离比例,因为是世界坐标,两个点相减有可能是负数,texture中不存在负数的坐标,所以转化为正数.
102         Vector2 originDistanceRatio = (cubePos - planeOriginPoint) / worldSize;
103         originDistanceRatio.Set(Mathf.Abs(originDistanceRatio.x), Mathf.Abs(originDistanceRatio.y));
104         //距离比例乘以密度,即可知道cube相当在texture中的点即可计算出来
105         Vector2Int fogCenter = new Vector2Int(Mathf.RoundToInt(originDistanceRatio.x * fogDensity.x), Mathf.RoundToInt(originDistanceRatio.y * fogDensity.y));
106         for (int i = 0; i < shapeLocalPosition.Length; i++)
107         {
108             int x = shapeLocalPosition[i].x + fogCenter.x;
109             int y = shapeLocalPosition[i].y + fogCenter.y;
110             //因为消除迷雾的形状是比cube的位置还要大的,在最边缘的时候,消除的像素点的坐标会超出texture范围,所以超出部分忽略.
111             if (x < 0 || x >= fogDensity.x || y < 0 || y >= fogDensity.y)
112                 continue;
113 
114             fogTexture.SetPixel(x, y, Color.clear);
115         }
116 
117         fogTexture.Apply();
118     }
119 }

欢迎交流.

转载注明出处.

猜你喜欢

转载自www.cnblogs.com/JinT-Hwang/p/12813028.html