zoukankan      html  css  js  c++  java
  • 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 }

    欢迎交流.

    转载注明出处.

  • 相关阅读:
    8 -- 深入使用Spring -- 5...3 使用@CacheEvict清除缓存
    8 -- 深入使用Spring -- 5...2 使用@Cacheable执行缓存
    tomcat 的 server.xml配置文件
    WEB-INF目录与META-INF目录的作用
    一个tomcat设置多个端口,多个端口对应多个应用
    8 -- 深入使用Spring -- 5...1 启用Spring缓存
    8 -- 深入使用Spring -- 5... Spring 3.1 新增的缓存机制
    8 -- 深入使用Spring -- 4...6 AOP代理:基于注解的XML配置文件的管理方式
    eclipse中设置文件的编码格式为utf-8
    MySQL 触发器简单实例
  • 原文地址:https://www.cnblogs.com/JinT-Hwang/p/12813028.html
Copyright © 2011-2022 走看看