海淀天下城电子沙盘单机版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

676 lines
24 KiB

using AX.MessageSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[Serializable]
public class FireSettingData
{
public long id;
public string name;
public string rsw;
public string pos;
public int type;
public int time;
public List<Vector3> pathPointList;
public string temperature; //火焰温度
public string radiation; //热辐射
}
public class FireSettingPanel : ResourceLoadPanel<FireSettingPanel>
{
public InputField RSWInput;
public InputField PosInput;
public InputField WDInput;
public InputField RFSInput;
public Toggle StraightSpread;
public Toggle AreaSpread;
public Toggle AroundSpread;
public InputField TimeInput;
public Text ErrorText;
public Button ResetBtn;
public Button SaveBtn;
public Button CloseBtn;
public List<Vector3> PathPointList = new List<Vector3>();
private RaycastHit hit;
private Ray ray;
public Vector3 startPosition = Vector3.zero;//定义一个Vector3,用来存储鼠标点击的位置
private Vector3 endPosition = Vector3.zero;//定义一个Vector3,用来存储鼠标点击的位置
public LayerMask layerMask = -1;
public Transform lineObjParent;
public Transform lineObj;
private GameObject lineObjChild;
private GameObject linePrefab;
private Line line1 = new Line();//多边形最后一条边
private Line line2 = new Line();//多边形除最后一条边的其他各边
private Line line3 = new Line();//多边形倒数第二边
private FireSettingData NowData = new FireSettingData();
private GameObject NowObj;
// Use this for initialization
void Start()
{
RSWInput.onValueChanged.AddListener(RSWInput_valueChanged);
PosInput.onValueChanged.AddListener(PosInput_valueChanged);
TimeInput.onValueChanged.AddListener(TimeInput_valueChanged);
WDInput.onValueChanged.AddListener(WDInput_valueChanged);
RFSInput.onValueChanged.AddListener(RFSInput_valueChanged);
StraightSpread.onValueChanged.AddListener(StraightSpread_valueChanged);
AreaSpread.onValueChanged.AddListener(AreaSpread_valueChanged);
AroundSpread.onValueChanged.AddListener(AroundSpread_valueChanged);
ResetBtn.onClick.AddListener(ResetBtn_Click);
SaveBtn.onClick.AddListener(SaveBtn_Click);
CloseBtn.onClick.AddListener(CloseBtn_Click);
MessageDispatcher.AddListener("SelectChange", selectchange);
}
private void OnDestroy()
{
MessageDispatcher.RemoveListener("SelectChange", selectchange);
}
private void selectchange(IMessage obj)
{
gameObject.SetActive(false);
}
public void AddRecordEventFire(GameObject obj, FireSettingData data)
{
if (ReplaySetting.PlayStatus == PlayStatus.isEditor && RecordManager.Instance.recordStatus == RecordStatus.normal)
{
var eventData = new EventData();
eventData.time = RecordManager.Instance.RecordTimer;
eventData.cloneObjType = obj.GetComponent<CloneGameObjInfo>().gameObjType;
eventData.eventType = RecordEventType.Fire;
eventData.json = JsonUtility.ToJson(data);
RecordManager.Instance.jsonData.eventDataList.Add(eventData);
}
}
public void AddRecordEventFireReset(GameObject obj, FireSettingData data)
{
if (ReplaySetting.PlayStatus == PlayStatus.isEditor && RecordManager.Instance.recordStatus == RecordStatus.normal)
{
var eventData = new EventData();
eventData.time = RecordManager.Instance.RecordTimer;
eventData.cloneObjType = obj.GetComponent<CloneGameObjInfo>().gameObjType;
eventData.eventType = RecordEventType.FireReset;
eventData.json = JsonUtility.ToJson(data);
RecordManager.Instance.jsonData.eventDataList.Add(eventData);
}
}
public void SettingFire(GameObject Fire)
{
NowObj = Fire;
NowData = Fire.GetComponent<FireControl>().MyData;
RSWInput.text = NowData.rsw;
PosInput.text = NowData.pos;
TimeInput.text = NowData.time.ToString();
WDInput.text = NowData.temperature;
RFSInput.text = NowData.radiation;
StraightSpread.isOn = NowData.type == 1;
AreaSpread.isOn = NowData.type == 2;
AroundSpread.isOn = NowData.type == 3;
PathPointList = NowData.pathPointList;
ErrorText.text = "";
if (PathPointList.Count > 0)
{
GetLineObj();
//Debug.Log("Line"+lineObj.name);
startPosition = PathPointList[PathPointList.Count - 1];
}
else
{
startPosition = Fire.transform.position;
}
}
private void CloseBtn_Click()
{
gameObject.SetActive(false);
//隐藏或删除路径
NowData = null;
if (lineObj != null)
lineObj.gameObject.SetActive(false);
lineObj = null;
NowObj = null;
}
public void SaveBtn_Click()
{
NowObj.GetComponent<FireControl>().SetTemperatureText();
NowObj.GetComponent<FireControl>().SetRadiationText();
if (!StraightSpread.group.AnyTogglesOn())
{
ErrorText.text = "请先选择蔓延方式!";
return;
}
if (string.IsNullOrEmpty(TimeInput.text))
{
ErrorText.text = "请输入时间!";
return;
}
//if (NowData.time == 0)
//{
// ErrorText.text = "请输入正整数时间!";
// return;
//}
if (NowData.pathPointList.Count == 0)
{
ErrorText.text = "请划定蔓延区域!";
return;
}
if (NowObj.GetComponent<FireSpreadCtrl>().isSpreading)
{
ResourceLoadWindow.Instance.LoadTipWindow("当前火焰正在蔓延,是否结束并开始新的蔓延?",
() =>
{
AddRecordEventFire(NowObj, NowData);
if (ReplaySetting.PlayStatus != PlayStatus.isReplay)
NowObj.GetComponent<FireSpreadCtrl>().Spread(NowData);
CloseBtn_Click();
},
() => CloseBtn_Click());
return;
}
AddRecordEventFire(NowObj, NowData);
if (ReplaySetting.PlayStatus != PlayStatus.isReplay)
NowObj.GetComponent<FireSpreadCtrl>().Spread(NowData);
CloseBtn_Click();
}
private void ResetBtn_Click()
{
ResetPath();
}
private void PosInput_valueChanged(string value)
{
NowData.pos = value;
}
private void RSWInput_valueChanged(string value)
{
NowData.rsw = value;
}
private void WDInput_valueChanged(string value)
{
NowData.temperature = value;
}
private void RFSInput_valueChanged(string value)
{
NowData.radiation = value;
}
private void AroundSpread_valueChanged(bool Ison)
{
if (Ison)
{
if (NowData.type != 3)
ResetLinePath();
TimeInput.interactable = true;
NowData.type = 3;
}
else
{
if (!StraightSpread.group.AnyTogglesOn())
{
TimeInput.interactable = false;
NowData.type = 0;
}
}
}
private void AreaSpread_valueChanged(bool Ison)
{
if (Ison)
{
if (NowData.type != 2)
ResetLinePath();
TimeInput.interactable = true;
NowData.type = 2;
}
else
{
if (!StraightSpread.group.AnyTogglesOn())
{
TimeInput.interactable = false;
NowData.type = 0;
}
}
}
private void StraightSpread_valueChanged(bool Ison)
{
if (Ison)
{
if (NowData.type != 1)
ResetLinePath();
TimeInput.interactable = true;
NowData.type = 1;
}
else
{
if (!StraightSpread.group.AnyTogglesOn())
{
TimeInput.interactable = false;
NowData.type = 0;
}
}
}
private void TimeInput_valueChanged(string value)
{
if (string.IsNullOrEmpty(value))
return;
int time = int.Parse(value);
if (time < 0)
{
ErrorText.text = "请输入正整数时间!";
TimeInput.text = "";
}
else
{
NowData.time = time;
ErrorText.text = "";
}
}
private void ResetPath()
{
PathPointList.Clear();
ResetLinePath();
//重置路径时,如果是已经蔓延过一次及存在蔓延出来的火,重置删除蔓延路径的同时,删除蔓延出来的火
Transform pfire = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_SpreadFire");
foreach (Transform child in pfire)
{
if (child.GetComponent<SpreadFire>() && child.GetComponent<SpreadFire>().SourceId == NowData.id)
{
Destroy(child.gameObject);
}
}
AddRecordEventFireReset(NowObj, NowData);
NowObj.GetComponent<FireSpreadCtrl>().Reset();
}
private void ResetLinePath()
{
GetLineObj();
//重置路线
if (lineObj != null)
{
foreach (Transform child in lineObj)
{
Destroy(child.gameObject);
}
PathPointList.Clear();
startPosition = EntitiesManager.Instance.GetEntityByID(NowData.id).transform.position;
}
}
private void GetLineObj()
{
if (lineObjParent == null)
{
lineObjParent = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_FireLine");
}
foreach (Transform t in lineObjParent)
{
if (t.name == NowData.id.ToString())
{
lineObj = t;
if (!lineObj.gameObject.activeSelf)
{
lineObj.gameObject.SetActive(true);
}
}
else
{
if (t.gameObject.activeSelf)
{
t.gameObject.SetActive(false);
}
}
}
}
// Update is called once per frame
void Update()
{
if (gameObject.activeSelf)
{
if ((StraightSpread.isOn || AreaSpread.isOn || AroundSpread.isOn) && InputManager.cloneObjType == CloneObjType.None)
{
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
{
//if (hit.transform.gameObject.layer == LayerMask.NameToLayer("PathFinding")
// || hit.transform.gameObject.layer == LayerMask.NameToLayer("shineiFloor"))
if (hit.transform.GetComponent<CloneableEnums>() &&
hit.transform.GetComponent<CloneableEnums>().CloneableTypes.Contains(CloneObjType.FireNormal)
)
{
if (NowObj.GetComponent<CloneGameObjInfo>().gameObjType == CloneObjType.FireHuge)
{
if (Mathf.Abs(hit.transform.position.y - NowObj.transform.position.y) > 7)
return;
}
else
{
if (Mathf.Abs(hit.transform.position.y - NowObj.transform.position.y) > 3)
return;
}
if (PathPointList.Count == 0)//第一次设置或重置后再设置蔓延路径的情况
{
if (StraightSpread.isOn || AreaSpread.isOn)
{
PathPointList.Add(startPosition);
}
else if (AroundSpread.isOn)
{
startPosition = hit.point;
}
CloneFireSpreadPath();
}
else
{
startPosition = PathPointList[PathPointList.Count - 1];
CloneFireSpreadPath();
}
}
}
}
}
}
}
private void CloneFireSpreadPath()
{
bool isintersection1 = false;
bool isintersection2 = false;
PathPointList.Add(hit.point);
endPosition = hit.point;
if (startPosition == endPosition)
{
return;
}
Vector3 tempPos = (startPosition + endPosition) / 2;
if (linePrefab == null)
linePrefab = Resources.Load<GameObject>("Prefab/Diaster/FireSpreadLine");
lineObjChild = Instantiate(linePrefab, tempPos, Quaternion.identity) as GameObject;
if (lineObjParent == null)
lineObjParent = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_FireLine");
if (lineObj == null)
lineObj = new GameObject().transform;
lineObj.name = NowData.id.ToString();
lineObj.SetParent(lineObjParent);
lineObjChild.transform.parent = lineObj.transform;
lineObjChild.transform.up = (-(endPosition - startPosition)).normalized;//改变线条的朝向
float distance = Vector3.Distance(startPosition, endPosition);//计算两点的距离
lineObjChild.transform.localScale = new Vector3(5f, distance * 18, 5f);//延长线条,连接两点。
if (StraightSpread.isOn)
{
startPosition = endPosition;
}
//如果是区域蔓延方式或四周蔓延,在顶点数大于2的情况下,画出终点与起始点连接成的边
if (AreaSpread.isOn || AroundSpread.isOn)
{
if (PathPointList.Count > 2)
{
line1.Start = new Vector2(endPosition.x, endPosition.z);
line1.End = new Vector2(PathPointList[0].x, PathPointList[0].z);
line3.Start = new Vector2(PathPointList[PathPointList.Count - 2].x, PathPointList[PathPointList.Count - 2].z);
line3.End = new Vector2(endPosition.x, endPosition.z);
for (int i = 0; i < PathPointList.Count; i++)
{
if ((i + 1) <= (PathPointList.Count - 1))
{
line2.Start = new Vector2(PathPointList[i].x, PathPointList[i].z);
line2.End = new Vector2(PathPointList[i + 1].x, PathPointList[i + 1].z);
isintersection1 = CheckTwoLineCrose(line1, line2, PathPointList);
if (isintersection1)
{
break;
}
}
}
for (int i = 0; i < PathPointList.Count; i++)
{
if ((i + 1) <= (PathPointList.Count - 1))
{
line2.Start = new Vector2(PathPointList[i].x, PathPointList[i].z);
line2.End = new Vector2(PathPointList[i + 1].x, PathPointList[i + 1].z);
if ((line3.Start != line2.Start) && line3.End != line2.End)//排除line3和自己比
{
isintersection2 = CheckTwoLineCrose(line3, line2, PathPointList);
}
if (isintersection2)
{
break;
}
}
}
if (!isintersection1 && !isintersection2)
{
Vector3 tempPos1 = (endPosition + PathPointList[0]) / 2;
lineObjChild = Instantiate(linePrefab, tempPos1, Quaternion.identity) as GameObject;
lineObjChild.transform.parent = lineObj.transform;
lineObjChild.transform.up = (-(PathPointList[0] - endPosition)).normalized;
float distance1 = Vector3.Distance(endPosition, PathPointList[0]);
lineObjChild.transform.localScale = new Vector3(5f, distance1 * 18, 5f);
startPosition = endPosition;
if (PathPointList.Count > 3)//如果是区域蔓延方式或四周蔓延,要删除前一次终点到起始点的边
Destroy(lineObj.transform.GetChild(lineObj.transform.childCount - 3).gameObject);
}
else
{
Destroy(lineObj.transform.GetChild(lineObj.transform.childCount - 1).gameObject);
PathPointList.RemoveAt(PathPointList.Count - 1);
//messageBox.GetComponent<MessageTool>().showMessage(ShowMessageType.prompt, "提示信息", "不能形成多边形");
ResourceLoadWindow.Instance.LoadTextHintWindow("不能形成多边形", 1f);
}
}
}
}
struct Line
{
public Vector2 Start, End;
}
/// <summary>
/// 判断直线2的两点是否在直线1的两边。
/// </summary>
/// <param name="line1">直线1</param>
/// <param name="line2">直线2</param>
/// <returns></returns>
private bool CheckCrose(Line line1, Line line2)
{
Vector2 v1 = new Vector2();
Vector2 v2 = new Vector2();
Vector2 v3 = new Vector2();
v1.x = line2.Start.x - line1.End.x;
v1.y = line2.Start.y - line1.End.y;
v2.x = line2.End.x - line1.End.x;
v2.y = line2.End.y - line1.End.y;
v3.x = line1.Start.x - line1.End.x;
v3.y = line1.Start.y - line1.End.y;
return (CrossMul(v1, v3) * CrossMul(v2, v3) <= 0);
}
/// <summary>
/// 判断两条线段是否相交,若相交且交点不是端点。
/// </summary>
/// <param name="line1">线段1</param>
/// <param name="line2">线段2</param>
/// <returns>相交返回真,否则返回假。</returns>
private bool CheckTwoLineCrose(Line line1, Line line2, List<Vector3> PathPointList)
{
//return CheckCrose(line1, line2) && CheckCrose(line2, line1);
bool isintersection = CheckCrose(line1, line2) && CheckCrose(line2, line1);
Vector2 intersection = GetIntersection(line1.Start, line1.End, line2.Start, line2.End);
bool dengYuDuanDian = true;
if (intersection != line1.Start
&& intersection != line1.End
&& intersection != line2.Start
&& intersection != line2.End)
{
dengYuDuanDian = false;
}
if (isintersection && !dengYuDuanDian)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 计算两个向量的叉乘。
/// </summary>
/// <param name="pt1"></param>
/// <param name="pt2"></param>
/// <returns></returns>
private float CrossMul(Vector2 pt1, Vector2 pt2)
{
return pt1.x * pt2.y - pt1.y * pt2.x;
}
/// <summary>
/// 求两条线段的交点
/// </summary>
/// <param name="a">线段1起点坐标</param>
/// <param name="b">线段1终点坐标</param>
/// <param name="c">线段2起点坐标</param>
/// <param name="d">线段2终点坐标</param>
/// <param name="intersection">相交点坐标</param>
private Vector2 GetIntersection(Vector2 a, Vector2 b, Vector2 c, Vector2 d)
{
Vector2 intersection = new Vector2();
intersection.x = ((b.x - a.x) * (c.x - d.x) * (c.y - a.y) - c.x * (b.x - a.x) * (c.y - d.y) + a.x * (b.y - a.y) * (c.x - d.x))
/ ((b.y - a.y) * (c.x - d.x) - (b.x - a.x) * (c.y - d.y));
intersection.y = ((b.y - a.y) * (c.y - d.y) * (c.x - a.x) - c.y * (b.y - a.y) * (c.x - d.x) + a.y * (b.x - a.x) * (c.y - d.y))
/ ((b.x - a.x) * (c.y - d.y) - (b.y - a.y) * (c.x - d.x));
if ((intersection.x - a.x) * (intersection.x - b.x) <= 0
&& (intersection.x - c.x) * (intersection.x - d.x) <= 0
&& (intersection.y - a.y) * (intersection.y - b.y) <= 0
&& (intersection.y - c.y) * (intersection.y - d.y) <= 0)
{
Debug.Log("线段相交于点(" + intersection.x + "," + intersection.y + ")!");
return intersection; //相交
}
else
{
return Vector2.zero;
}
}
// wn_PnPoly(): winding number test for a point in a polygon
// Input: point = a point,
// polygon = anticlockwise vertex points of a polygon polygon[n]
// Return: wn = the winding number (=0 only when P is outside)
// See:"http://geomalgorithms.com/a03-_inclusion.html"
int wn_PnPoly(List<Vector2> polygon, Vector2 point)
{
//polygon顶点的X,Y数组
float[] polyline = new float[2 * polygon.Count];
for (int i = 0; i < polygon.Count; i++)
{
polyline[i + i] = polygon[i].x;
polyline[i + i + 1] = polygon[i].y;
}
float maxx = 0, minx = 0, maxy = 0, miny = 0;
int pointcount = 0;
if (polyline != null)
{
pointcount = polyline.Length / 2;
maxx = minx = polyline[0];
maxy = miny = 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 (maxy < polyline[i + i + 1])
maxy = polyline[i + i + 1];
if (miny > polyline[i + i + 1])
miny = polyline[i + i + 1];
}
}
int n = polygon.Count;
int wn = 0; // the winding number counter
//首先判断是否在多边形的外框范围内
if (point.x < minx || point.x > maxx
|| point.y < miny || point.y > maxy)
{
return 0;
}
else
{
// loop through all edges of the polygon
for (int i = 0; i < n; i++)
{ // edge from polygon[i] to polygon[i+1]
if (polygon[i].y <= point.y)
{ // start y <= P.y
if (polygon[(i + 1) % n].y > point.y) // an upward crossing
if (isLeft(polygon[i], polygon[(i + 1) % n], point) > 0) // P left of edge
++wn; // have a valid up intersect
}
else
{ // start y > P.y (no test needed)
if (polygon[(i + 1) % n].y <= point.y) // a downward crossing
if (isLeft(polygon[i], polygon[(i + 1) % n], point) < 0) // P right of edge
--wn; // have a valid down intersect
}
}
return wn;
}
}
//isLeft(): tests if a point is Left|On|Right of an infinite line.
//Input: three points P0, P1, and P2
//Return: >0 for P2 left of the line through P0 and P1
// =0 for P2 on the line
// <0 for P2 right of the line
// See:"http://geomalgorithms.com/a03-_inclusion.html":Algorithm 1 "Area of Triangles and Polygons"
// Or "http://geomalgorithms.com/a01-_area.html"
float isLeft(Vector2 P0, Vector2 P1, Vector2 P2)
{
return ((P1.x - P0.x) * (P2.y - P0.y)
- (P2.x - P0.x) * (P1.y - P0.y));
}
}