unity如何實現戰爭迷霧?思路一


unity如何實現戰爭迷霧?思路一

 

斷更很久了,剛好今天放假,寫一個unity下實現戰爭迷霧的思路.

 

 

效果如下: 

 

 

 

思路如下:

建一個plane作為地面,UI中的rawimage放在最上層作為迷霧顯示,cube作為主角移動.cube每次移動,將它的坐標轉化為rawimage上相對位置的點,然后用texture2dsetpixel方法逐像素清除出一個區域出來.

 

 

 左下角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 }

歡迎交流.

轉載注明出處.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM