using AX.InputSystem; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class OriginFire { public string comburent = "";//燃烧物 public string position = "";//火位置 public int initialSize = 30;//火初始大小 public SpreadWay spreadWay = SpreadWay.None;//蔓延方式 public int spreadSpeed = 0;//蔓延速度 public List pathPoints = new List();//设置蔓延路径或范围点击的点;或者是自动蔓延燃烧物的坐标点 } /// /// 火蔓延控制 /// public class FireSpreadCtrl : MonoBehaviour { public OriginFire fireAttribute = new OriginFire(); public bool combustibleInputWay;//燃烧物输入方式:true表示输入;false表示从下拉框选择 public List spreadPoints = new List();//根据pathPoints算出的蔓延火的位置数组 private float spreadDis = 3.0f;//蔓延出的火之间的距离(蔓延出来的火的预设的碰撞盒边长为3.163) private int index;//火蔓延位置spreadPoints的索引 public bool isSpreading;//是否正在蔓延 public bool flag; private bool flag1; private float spreadSpeed;//蔓延速度 public int SpreadTime;//蔓延时间间隔 public float repeatRate;//蔓延方法再次调用频率 public const float factor = 0.00625f;//一级风力对应的火的蔓延速度为:(1/160) private float windForce;//风力 private Vector3 windDir;//风向 private float windForceOnSpreadDir;//风力在蔓延方向上的分量 private float angle;//风向与蔓延方向的夹角 private float cosAngle; private Vector3 spreadDir;//蔓延方向 private float width = 3.163f;//蔓延出来的火的宽 public bool beController=false;//是否被控制(是否可蔓延),true为被控制住(不可蔓延) public bool BeController { get { return beController; } set { beController = value; if (value) { CancelInvoke("FireSpreadControl"); isSpreading = false; //flag = false; flag1 = false; } else { isSpreading = true; } //蔓延同步 } } // Use this for initialization void Start() { } // Update is called once per frame void Update() { if (GameSettings.othersSettings.isStartDrill) { if (!flag) { isSpreading = true; flag = true; } } if (!flag1) { if (isSpreading) { if (fireAttribute.spreadWay == SpreadWay.None) { return; } if (fireAttribute.spreadWay == SpreadWay.Road) { bool isSpreaded = false; //控制index,以控制蔓延过火后重新设置路径(接着以前路径增加)后,接着蔓延; //若是换蔓延方式或者重置路径后再重新设置路径,则从头开始蔓延 foreach (Transform child in transform.parent) { if (child.GetComponent() && child.GetComponent().fireGameObjID == transform.GetComponent().gameObjID) { isSpreaded = true; break; } } if (!isSpreaded) { index = 0; } windForce = GameObject.Find("WindZone").GetComponent().windMain;//风力 spreadDir = fireAttribute.pathPoints[fireAttribute.pathPoints.Count - 1] - fireAttribute.pathPoints[0];//蔓延方向 windDir = transform.GetComponent().dirVec;//风向 angle = Vector3.Angle(windDir, spreadDir);//风向与蔓延方向之间的夹角 cosAngle = Mathf.Cos(angle * Mathf.PI / 180); windForceOnSpreadDir = windForce * cosAngle;//风力在蔓延方向上的大小 spreadSpeed = fireAttribute.spreadSpeed + windForce * factor * windForceOnSpreadDir; //width * width:十平方; //spreadSpeed * spreadSpeed:每分钟蔓延面积 //SpreadTime:蔓延十平方需要多少秒 SpreadTime = Mathf.RoundToInt((width * width) / (spreadSpeed * spreadSpeed) * 60); repeatRate = SpreadTime; } else { index = 0; //区域蔓延,四周蔓延暂时不考虑风向风力的影响 spreadSpeed = fireAttribute.spreadSpeed; //width * width:十平方; //spreadSpeed * spreadSpeed:每分钟蔓延面积 //SpreadTime:蔓延十平方需要多少秒 SpreadTime = Mathf.RoundToInt((width * width) / (spreadSpeed * spreadSpeed) * 60); repeatRate = SpreadTime; } InvokeRepeating("FireSpreadControl", spreadSpeed, repeatRate); flag1 = true; } } } public void ResetSpreadPathsAndPoints() { fireAttribute.pathPoints.Clear(); spreadPoints.Clear(); //停止火的蔓延 CancelInvoke("FireSpreadControl"); isSpreading = false; flag = false; flag1 = false; } /// /// 火蔓延控制 /// private void FireSpreadControl() { var arg = new CloneSpreadFireCmdArgs(); arg.cloneObjType = CloneObjType.SpreadedFire; arg.parentFireGameObjID = transform.GetComponent().gameObjID; arg.parentFireBuildNum = transform.GetComponent().buildNum; arg.parentFireFloorNum = transform.GetComponent().floorNum; arg.parentFireInterlayerNum = transform.GetComponent().interlayerNum; if (index < spreadPoints.Count) { //List tempFirePosList = spreadPoints[index++]; //for (int i = 0; i < tempFirePosList.Count; i++) //{ // arg.hitPos = tempFirePosList[i]; // CloneSpreadedFireCommand.Instance.Execute(EntitiesManager.Instance.CreateObjID(), arg); //} arg.hitPos = spreadPoints[index++]; CloneSpreadedFireCommand.Instance.Execute(EntitiesManager.Instance.CreateObjID(CurrentUserInfo.mySelf.Id), arg); } if (index == spreadPoints.Count) { CancelInvoke("FireSpreadControl"); isSpreading = false; } } /// /// 获取蔓延火生成的位置 /// public void GetSpreadFirePositions() { spreadPoints.Clear(); var sideLength = transform.GetComponent().size.x;//火源火的边长 var r = sideLength / 2; if (fireAttribute.spreadWay == SpreadWay.Road) { for (int i = 0; i < fireAttribute.pathPoints.Count; i++) { if ((i + 1) <= (fireAttribute.pathPoints.Count - 1)) { var pathDir = fireAttribute.pathPoints[i + 1] - fireAttribute.pathPoints[i];//每段路径的方向 //叉积求出垂直于 蔓延路径方向与竖直方向Y形成的平面 的向量的单位向量 var vertical = Vector3.Cross(pathDir, new Vector3(0,1,0)).normalized; var distance = Vector3.Distance(fireAttribute.pathPoints[i], fireAttribute.pathPoints[i + 1]); var result = (int)(distance / spreadDis); for (int j = 1; j <= result; j++) { var spreadFirePoint = Vector3.MoveTowards(fireAttribute.pathPoints[i], fireAttribute.pathPoints[i + 1], spreadDis * j); var spreadFirePoint_xz = new Vector2(spreadFirePoint.x, spreadFirePoint.z); var firePoint_xz = new Vector2(transform.position.x, transform.position.z); float dis = Vector2.Distance(firePoint_xz, spreadFirePoint_xz); if (dis > r) {//火源范围之外 var fireSide = transform.GetComponent().size.x; var fireSide_int = Mathf.Round(fireSide); var width_int = Mathf.Round(width); var spreadFireNum = (int)Mathf.Round(fireSide_int / width_int); if (spreadFireNum % 2 == 1) {//奇数的情况 if (spreadFireNum == 1) { spreadPoints.Add(spreadFirePoint); } else {//spreadFireNum等于3,5,7,9,11...... int oneSide = (spreadFireNum - 1) / 2;//除设置路径上一条蔓延火外,蔓延路径两边各有和蔓延路径方向一致的几条火 for (int n = oneSide; n > 0; n--) { var tempSpreadFirePoint = spreadFirePoint + (spreadDis * n) * vertical; spreadPoints.Add(tempSpreadFirePoint); } spreadPoints.Add(spreadFirePoint); for (int n = 1; n <= oneSide; n++) { var tempSpreadFirePoint = spreadFirePoint + (spreadDis * n) * (-vertical); spreadPoints.Add(tempSpreadFirePoint); } } } else if (spreadFireNum % 2 == 0) {//偶数的情况,及spreadFireNum等于4,6,8,10,12...... int oneSide = spreadFireNum / 2;//除设置路径上一条蔓延火外,蔓延路径两边各有和蔓延路径方向一致的几条火 for (int n = oneSide; n > 0; n--) { var tempSpreadFirePoint = spreadFirePoint + (spreadDis * n - spreadDis/2) * vertical; spreadPoints.Add(tempSpreadFirePoint); } for (int n = 1; n <= oneSide; n++) { var tempSpreadFirePoint = spreadFirePoint + (spreadDis * n - spreadDis/2) * (-vertical); spreadPoints.Add(tempSpreadFirePoint); } } } } } } } if (fireAttribute.spreadWay == SpreadWay.Are || fireAttribute.spreadWay == SpreadWay.Around) { //找出蔓延范围多边形xz平面包围盒 float[] polyline = new float[2 * fireAttribute.pathPoints.Count]; for (int i = 0; i < fireAttribute.pathPoints.Count; i++) { polyline[i + i] = fireAttribute.pathPoints[i].x; polyline[i + i + 1] = fireAttribute.pathPoints[i].z; } float maxx = 0, minx = 0, maxz = 0, minz = 0; int pointcount = 0; if (polyline != null) { pointcount = polyline.Length / 2; maxx = minx = polyline[0]; maxz = minz = polyline[1]; for (int i = 0; i < pointcount; i++) { if (maxx < polyline[i + i]) maxx = polyline[i + i]; if (minx > polyline[i + i]) minx = polyline[i + i]; if (maxz < polyline[i + i + 1]) maxz = polyline[i + i + 1]; if (minz > polyline[i + i + 1]) minz = polyline[i + i + 1]; } } //包围盒内按spreadDis等距分割的所有点 int count_z = (int)((maxz - minz) / spreadDis); int count_x = (int)((maxx - minx) / spreadDis); List temp = new List(); for (int i = 0; i <= count_x; i++) { for (int j = 0; j <= count_z; j++) { temp.Add(new Vector2(minx + spreadDis * i, minz + spreadDis * j)); } } List pathPointList_xz = new List();//蔓延范围xz平面多边形 for (int i = 0; i < fireAttribute.pathPoints.Count; i++) { pathPointList_xz.Add(new Vector2(fireAttribute.pathPoints[i].x, fireAttribute.pathPoints[i].z)); } List spreadFirePositions_xz = new List();//蔓延范围xz平面多边形内部的点 for (int i = 0; i < temp.Count; i++) { int wn = CloneFireSpreadLine.instance.wn_PnPoly(pathPointList_xz, temp[i]); if (wn != 0) { spreadFirePositions_xz.Add(new Vector3(temp[i].x, temp[i].y)); } } //分批次构建蔓延火点数据结构 Vector2 firePos_xz = new Vector2(transform.position.x, transform.position.z); float maxFanWei = Vector2.Distance(temp[0], temp[temp.Count - 1]); int pici = (int)(maxFanWei / spreadDis);//蔓延批次 pici = pici + 1; for (int i = 1; i <= pici; i++) { List tempList1 = new List(); //List tempList = new List(); for (int j = 0; j < spreadFirePositions_xz.Count; j++) { float dis = Vector2.Distance(firePos_xz, spreadFirePositions_xz[j]); if (dis != 0 && dis <= i * spreadDis) { if (dis > r) {//火源范围之外 tempList1.Add(spreadFirePositions_xz[j]); } } } for (int n = 0; n < tempList1.Count; n++) { Vector3 tempPoint = new Vector3(tempList1[n].x, transform.position.y, tempList1[n].y); //使蔓延火位置的高度始终在地面上 RaycastHit hitUp; RaycastHit hitDown; Physics.Raycast(tempPoint, Vector3.up, out hitUp, Mathf.Infinity); Physics.Raycast(tempPoint, Vector3.down, out hitDown, Mathf.Infinity); if (hitUp.transform != null) { NavMeshHit hit = new NavMeshHit(); bool isFindedPath = NavMesh.SamplePosition(hitUp.point, out hit, 0.5f, NavMesh.AllAreas); if (/*hitUp.transform.gameObject.layer == LayerMask.NameToLayer("CarRoad") || hitUp.transform.gameObject.layer == LayerMask.NameToLayer("SoldierRoad")*/ isFindedPath) { tempPoint = new Vector3(tempPoint.x, hitUp.transform.position.y, tempPoint.z); } } if (hitDown.transform != null) { NavMeshHit hit = new NavMeshHit(); bool isFindedPath = NavMesh.SamplePosition(hitDown.point, out hit, 0.5f, NavMesh.AllAreas); if (/*hitDown.transform.gameObject.layer == LayerMask.NameToLayer("CarRoad") || hitDown.transform.gameObject.layer == LayerMask.NameToLayer("SoldierRoad")*/ isFindedPath) { tempPoint = new Vector3(tempPoint.x, hitDown.transform.position.y, tempPoint.z); } } spreadPoints.Add(tempPoint); //tempList.Add(tempPoint); } //spreadPoints.Add(tempList); for (int m = 0; m < tempList1.Count; m++) { if (spreadFirePositions_xz.Contains(tempList1[m])) { spreadFirePositions_xz.Remove(tempList1[m]); } } } //因为批次是按包围盒最大点到最小点的距离除以一个批次的蔓延距离,所以可能出现没有点的批次,需要去除 //for (int i = spreadPoints.Count - 1; i >= 0; i--) //{ // if (spreadPoints[i].Count == 0) // { // spreadPoints.RemoveAt(i); // } //} } } }