unity如何实现战争迷雾?思路一
unity如何实现战争迷雾?思路一
断更很久了,刚好今天放假,写一个unity下实现战争迷雾的思路.
效果如下:
思路如下:
建一个plane作为地面,用UI中的rawimage放在最上层作为迷雾显示,用cube作为主角移动.cube每次移动,将它的坐标转化为rawimage上相对位置的点,然后用texture2d的setpixel方法逐像素清除出一个区域出来.
左下角rawimage显示小地图,有单独一个camera专门将迷雾绘制到小地图中.
具体实现:
1.新建plane,cube,分别作为地面和主角,并把场景中的Main Camera作为cube的子物体.如下设置.
在project窗口创建一个material并赋给cube方便改颜色.
2.新建一个canvas和一个rawimage,并按如下设置.
3.新建一个gameobject,在它的下面,新建一个camera,新建一个canvas并在它的下面新建image,rawimage.设置如下.
在project窗口创建一个rendertexture并赋给camera和rawimage.
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,cube的transform.定义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 }
欢迎交流.
转载注明出处.