475 lines
17 KiB
C#
475 lines
17 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Xml.Serialization;
|
||
using Unity.VisualScripting;
|
||
using UnityEditor.Experimental.GraphView;
|
||
using UnityEngine;
|
||
using UnityEngine.Networking.Types;
|
||
using UnityEngine.UI;
|
||
using static System.Collections.Specialized.BitVector32;
|
||
using static UnityEditor.Progress;
|
||
|
||
public class EvacuationPanel : MonoBehaviour
|
||
{
|
||
public List<PersonnelItem> personnelItems;//左侧区域
|
||
public Transform personnelContent;
|
||
public Panel panel;
|
||
public GameObject personnelPrefabs;
|
||
public GameObject classPrefab;
|
||
public GameObject classCount;//
|
||
public GameObject scenePrefab;//区域预制体
|
||
public Transform sceneCount;//区域预制体的容器
|
||
public GameObject jueseChoicePanel;
|
||
public Transform content;
|
||
public Text topText;
|
||
private GameObject selectedScene = null;//当前选中场景
|
||
public Sprite[] showImage;
|
||
|
||
public List<ClassItem> classItemList = new List<ClassItem>();
|
||
public List<ClassMate> classMateList = new List<ClassMate>();
|
||
|
||
[Header("学生数量")]
|
||
public InputField StuCountInputField;
|
||
public Button CountsubmitBtn;
|
||
public Sprite rsprite;
|
||
public Sprite fsprite;
|
||
public GameObject JuesechoicePop;
|
||
|
||
public JueseChoicePop jc = new JueseChoicePop();
|
||
public JSONReader js;
|
||
|
||
[Header("总按钮")]
|
||
public Button redistributeBtn;
|
||
public Button submitBtn;
|
||
|
||
[Header("Npc数量")]
|
||
public int npcNum;
|
||
|
||
[Header("Npc类型")]
|
||
public string npcType;
|
||
public string roleid;
|
||
public int isHere;
|
||
|
||
[Header("可分配列表")]
|
||
List<int> nonZeroAreas = new List<int>();
|
||
public SelectScenePanel selectScene;
|
||
[Header("被清除的区域")] public List<int> clearRegion=new List<int>();
|
||
[Header("被重新分配的区域")] private HashSet<int> excludedAreas = new HashSet<int>();
|
||
// Start is called before the first frame update
|
||
void Start()
|
||
{
|
||
redistributeBtn.interactable = false;
|
||
ChangeImage(redistributeBtn.interactable);
|
||
jc = JuesechoicePop.GetComponent<JueseChoicePop>();
|
||
CountsubmitBtn.onClick.AddListener(Submit);
|
||
submitBtn.onClick.AddListener(totalSubmit);
|
||
StuCountInputField.onEndEdit.AddListener(CheckInput);
|
||
SetScene();
|
||
SetClass();
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
CheckInput(StuCountInputField.text);
|
||
//IsRedistribution();
|
||
IsOpen(selectScene.difficultyId);
|
||
}
|
||
//上传数据
|
||
public void totalSubmit()
|
||
{
|
||
createTemplateInfo.Instance.auth_CreateTemplate.npcList = new List<NpcList>();
|
||
foreach(var npcInfo in personnelItems)
|
||
{
|
||
NpcList nPC = new NpcList();
|
||
nPC.npcId = npcInfo.npcId.ToString();
|
||
nPC.areaId = npcInfo.sceneId.ToString();
|
||
nPC.isHere=npcInfo.isHere;
|
||
nPC.npcNum = npcInfo.NpcNum;
|
||
createTemplateInfo.Instance.auth_CreateTemplate.npcList.Add(nPC);
|
||
}
|
||
panel.panelToggle[3].interactable = true; // 启用第二个Toggle
|
||
panel.panelToggle[3].gameObject.transform.GetComponent<Image>().sprite = panel.toggleImage[1];
|
||
panel.panelToggle[4].interactable = true; // 启用第三个Toggle
|
||
panel.panelToggle[4].gameObject.transform.GetComponent<Image>().sprite = panel.toggleImage[1];
|
||
}
|
||
|
||
//设置Npc类型
|
||
public void SetNpcType()
|
||
{
|
||
foreach (var scene in panel.sceneDataDictionary)
|
||
{
|
||
foreach (var npcData in js.locationDictionary)
|
||
{
|
||
// 解析角色限制字段
|
||
string roleLimit = npcData.Value.NpcRatio;
|
||
if(npcData.Value.NpcRatio=="-1")
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
// 先按“,”分隔
|
||
string[] roleLimitSections = roleLimit.Split(',');
|
||
if (scene.Key == npcData.Value.Note)
|
||
{
|
||
// 只有当 scene.Key 和 npcData.Value.Note 匹配时才执行
|
||
this.npcType = roleLimitSections[1];
|
||
roleid = roleLimitSections[0];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//文字框提交按钮
|
||
public void Submit()
|
||
{
|
||
// 输入验证
|
||
int count;
|
||
if (!int.TryParse(StuCountInputField.text, out count) || count <= 0)
|
||
{
|
||
Debug.LogError("请输入有效的总人数!");
|
||
return;
|
||
}
|
||
|
||
//StuCountInputField.text = "";
|
||
|
||
// 调用分配方法
|
||
var result = DistributeNpcByRatio(personnelItems, count);
|
||
|
||
// 更新 UI 和数据
|
||
foreach (var kvp in result)
|
||
{
|
||
PersonnelItem item = personnelItems.Find(p => p.sceneId == kvp.Key);
|
||
if (item != null)
|
||
{
|
||
item.SetInfo(kvp.Value.ToString()); // 更新UI显示
|
||
item.NpcNum = kvp.Value; // 更新Npc数量
|
||
|
||
item.personnelImage.gameObject.SetActive(true); // 显示图标
|
||
Debug.Log($"Scene ID: {kvp.Key}, Assigned NPC Count: {kvp.Value}");
|
||
}
|
||
}
|
||
}
|
||
|
||
//Npc分配
|
||
public Dictionary<int, int> DistributeNpcByRatio(List<PersonnelItem> personnelItems, int totalNpcCount)
|
||
{
|
||
Dictionary<int, float> sceneRatios = new Dictionary<int, float>(); // 存储场景ID和比例
|
||
float totalRatio = 0; // 所有场景的比例之和
|
||
|
||
// 遍历所有可以分配的区域,解析NpcRatio,提取分配比例
|
||
foreach (var item in personnelItems)
|
||
{
|
||
LocationData locationData = js.GetAreaDateById(item.sceneId);
|
||
string[] allLimits = locationData.NpcRatio.Split('|'); // 多个比例段
|
||
|
||
foreach (string limit in allLimits)
|
||
{
|
||
string[] parts = limit.Split(',');
|
||
if (parts.Length >= 5) // 确保数据有效
|
||
{
|
||
int sceneId = item.sceneId; // 使用 PersonnelItem 的 sceneId
|
||
float ratio = float.Parse(parts[4]); // 第五项是分配比例
|
||
item.npcId = int.Parse(parts[2]);
|
||
item .isHere=int.Parse(parts[3]);
|
||
if (!sceneRatios.ContainsKey(sceneId))
|
||
{
|
||
sceneRatios.Add(sceneId, ratio);
|
||
totalRatio += ratio; // 累加所有场景的比例
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有有效的分配比例,直接返回空结果
|
||
if (sceneRatios.Count == 0 || totalRatio == 0)
|
||
{
|
||
Debug.LogError("没有找到有效的分配比例!");
|
||
return new Dictionary<int, int>();
|
||
}
|
||
|
||
// 根据比例分配人数
|
||
Dictionary<int, int> finalDistribution = new Dictionary<int, int>();
|
||
int remainingNpc = totalNpcCount;
|
||
|
||
foreach (var entry in sceneRatios)
|
||
{
|
||
int allocatedNpc = Mathf.FloorToInt(totalNpcCount * (entry.Value / totalRatio)); // 按比例分配
|
||
finalDistribution[entry.Key] = allocatedNpc; // 添加到分配结果
|
||
remainingNpc -= allocatedNpc; // 更新剩余NPC数量
|
||
}
|
||
|
||
// 将剩余人数分配给当前人数最少的场景
|
||
while (remainingNpc > 0)
|
||
{
|
||
int minScene = finalDistribution.OrderBy(kvp => kvp.Value).First().Key; // 找到当前人数最少的场景
|
||
finalDistribution[minScene]++;
|
||
remainingNpc--;
|
||
}
|
||
|
||
return finalDistribution;
|
||
}
|
||
|
||
//设置左侧场景显示2.0
|
||
public void SetScene()
|
||
{
|
||
foreach (var item in js.locationDictionary)
|
||
{
|
||
|
||
if(item.Value.NpcRatio=="-1")
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
string[] npcratio = item.Value.NpcRatio.Split('|');
|
||
foreach(var npcLimit in npcratio)
|
||
{
|
||
string[] limit = npcLimit.Split(',');
|
||
if (limit[0] == selectScene.idcidentId.ToString()&& limit[1] == selectScene.difficultyId.ToString())
|
||
{
|
||
GameObject sceneitem = GameObject.Instantiate(personnelPrefabs, personnelContent);
|
||
PersonnelItem personnelItem = sceneitem.GetComponent<PersonnelItem>();
|
||
Button button = personnelItem.transform.Find("sceneText").GetComponent<Button>();
|
||
personnelItem.sceneText.text = js.SetUIText(item.Value.Name);
|
||
personnelItem.sceneId = item.Key;
|
||
personnelItem.Num = 1; // 设置初始值为 1
|
||
// 点击事件监听
|
||
button.onClick.AddListener(() =>
|
||
{
|
||
// 标记当前选择的区域
|
||
OnSceneItemClicked(sceneitem, Color.yellow, selectedScene);
|
||
|
||
// 如果被点击的区域已经有人员
|
||
if (personnelItem.NpcNum > 0)
|
||
{
|
||
redistributeBtn.interactable = true;
|
||
ChangeImage(redistributeBtn.interactable);
|
||
redistributeBtn.transform.GetComponent<Image>().sprite = showImage[1];
|
||
|
||
// 清除所有之前的监听器,确保只有最新的事件被执行
|
||
redistributeBtn.onClick.RemoveAllListeners();
|
||
|
||
// 添加最新的监听器
|
||
redistributeBtn.onClick.AddListener(() =>
|
||
{
|
||
// 清除选定区域的人员数据
|
||
RedistributeLogic(personnelItem.sceneId, personnelItem.NpcNum);
|
||
redistributeBtn.interactable = false;
|
||
ChangeImage(redistributeBtn.interactable);
|
||
});
|
||
}
|
||
|
||
// 清空现有场景下的所有人员UI
|
||
foreach (Transform child in sceneCount)
|
||
{
|
||
Destroy(child.gameObject);
|
||
}
|
||
// 执行后续的场景级别配置
|
||
LocationData locationData = js.GetAreaDateById(personnelItem.sceneId);
|
||
if (locationData.Level.ToString() != "0")
|
||
{
|
||
GameObject levelItem = GameObject.Instantiate(scenePrefab, sceneCount);
|
||
Button levelBtn = levelItem.transform.Find("chooseBtn2").GetComponent<Button>();
|
||
levelBtn.onClick.AddListener(() =>
|
||
{
|
||
JueseChoicePop jueseChoicePop = jueseChoicePanel.GetComponent<JueseChoicePop>();
|
||
jueseChoicePop.SetClass(personnelItem.sceneId);
|
||
jueseChoicePanel.gameObject.SetActive(true);
|
||
});
|
||
ClassItem classItem = levelItem.GetComponent<ClassItem>();
|
||
classItem.classname.text = locationData.Level.ToString();
|
||
}
|
||
});
|
||
personnelItems.Add(personnelItem);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 判断重新分配按钮是否可以点击
|
||
public void IsRedistribution()
|
||
{
|
||
// 遍历 personnelItems,检查是否有任何 PersonnelItem 的 gameObject 处于激活状态
|
||
bool canRedistribute = personnelItems.Any(item =>
|
||
item.personnelImage != null && item.personnelImage.gameObject.activeSelf);
|
||
|
||
// 设置重新分配按钮的交互状态
|
||
redistributeBtn.interactable = canRedistribute;
|
||
}
|
||
|
||
//判断输入框的数字是否大于1
|
||
void CheckInput(string input)
|
||
{
|
||
// 尝试将输入转换为数字
|
||
if (float.TryParse(input, out float result))
|
||
{
|
||
// 判断数字是否大于1
|
||
if (result > 1)
|
||
{
|
||
CountsubmitBtn.GetComponent<Image>().sprite = rsprite;
|
||
CountsubmitBtn.onClick.AddListener(Countsubmit);
|
||
}
|
||
}
|
||
}
|
||
|
||
//Npc数量设置按钮置灰设置
|
||
public void Countsubmit()
|
||
{
|
||
//按钮置灰
|
||
CountsubmitBtn.GetComponent<Image>().sprite = fsprite;
|
||
StuCountInputField.text = string.Empty;
|
||
//按配置对输入的Npc数量进行 分配
|
||
//取消监听
|
||
CountsubmitBtn.onClick.RemoveAllListeners();
|
||
}
|
||
|
||
//场景ID进行配置
|
||
public void SettopText()
|
||
{
|
||
topText.text = "以下班级需要设定班主任老师:";
|
||
topText.text = "以下楼层需要设定搜救老师:";
|
||
}
|
||
|
||
//实例化ClassItem
|
||
public void SetClass()
|
||
{
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
GameObject item = GameObject.Instantiate<GameObject>(classPrefab, content);
|
||
ClassItem classItem = item.GetComponent<ClassItem>();
|
||
classItem.JuesechoicePop = JuesechoicePop;
|
||
classItemList.Add(classItem);
|
||
}
|
||
}
|
||
|
||
//重新分配
|
||
public void RedistributeLogic(int excludedSceneId, int excludedNum)
|
||
{
|
||
// 1. 计算需要重新分配的 NPC 总数
|
||
int totalRedistributePeople = excludedNum;
|
||
|
||
// 2. 标记当前重新分配的区域
|
||
if (!excludedAreas.Contains(excludedSceneId))
|
||
{
|
||
excludedAreas.Add(excludedSceneId); // 将被重新分配的区域加入到排除列表中
|
||
Debug.Log($"Scene ID {excludedSceneId} added to excluded areas.");
|
||
}
|
||
|
||
// 修改被重新分配区域的数据
|
||
PersonnelItem excludedItem = personnelItems.FirstOrDefault(item => item.sceneId == excludedSceneId);
|
||
if (excludedItem != null)
|
||
{
|
||
excludedItem.NpcNum = 0; // 清空 NPC 数量
|
||
excludedItem.SetInfo(""); // 更新 UI 显示为空
|
||
excludedItem.personnelImage.gameObject.SetActive(false); // 隐藏图标
|
||
Debug.Log($"Cleared NPCs from Scene ID: {excludedSceneId}");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"Scene ID {excludedSceneId} not found in personnelItems.");
|
||
return;
|
||
}
|
||
|
||
// 3. 筛选有效的分配区域(跳过已排除的区域)
|
||
List<PersonnelItem> validAreas = personnelItems.Where(item => !excludedAreas.Contains(item.sceneId)).ToList();
|
||
if (validAreas.Count == 0)
|
||
{
|
||
Debug.LogWarning("No valid areas available for redistribution.");
|
||
return;
|
||
}
|
||
|
||
// 4. 随机分配人数到有效区域
|
||
System.Random random = new System.Random(); // 随机数生成器
|
||
Dictionary<int, int> redistributionResult = new Dictionary<int, int>();
|
||
|
||
// 初始化分配结果
|
||
foreach (var item in validAreas)
|
||
{
|
||
redistributionResult[item.sceneId] = 0;
|
||
}
|
||
|
||
// 随机分配 NPC
|
||
int remainingNpc = totalRedistributePeople;
|
||
|
||
while (remainingNpc > 0)
|
||
{
|
||
// 随机选择一个区域
|
||
int randomIndex = random.Next(0, validAreas.Count);
|
||
PersonnelItem targetItem = validAreas[randomIndex];
|
||
|
||
// 更新分配结果
|
||
redistributionResult[targetItem.sceneId]++;
|
||
remainingNpc--;
|
||
}
|
||
|
||
// 5. 更新有效区域的 UI 显示和数据
|
||
foreach (var kvp in redistributionResult)
|
||
{
|
||
PersonnelItem targetItem = validAreas.FirstOrDefault(item => item.sceneId == kvp.Key);
|
||
if (targetItem != null)
|
||
{
|
||
targetItem.NpcNum += kvp.Value; // 更新 NPC 数量
|
||
targetItem.SetInfo(targetItem.NpcNum.ToString()); // 更新 UI 显示
|
||
targetItem.personnelImage.gameObject.SetActive(true); // 确保图标可见
|
||
|
||
Debug.Log($"Redistributed {kvp.Value} NPCs to Scene ID: {kvp.Key}");
|
||
}
|
||
}
|
||
}
|
||
|
||
//设置文字颜色
|
||
public void OnSceneItemClicked(GameObject clickedItem, Color color, GameObject select)
|
||
{
|
||
// 如果有之前选中的角色,重置其视觉效果
|
||
if (selectedScene != null && select != clickedItem)
|
||
{
|
||
Text prevText = selectedScene.GetComponentInChildren<Text>();
|
||
if (prevText != null)
|
||
{
|
||
prevText.fontSize = 32; // 恢复原始字号
|
||
prevText.color = Color.white; // 恢复原始颜色
|
||
}
|
||
}
|
||
|
||
// 设置当前选中的角色为选中状态
|
||
selectedScene = clickedItem; // 更新选中人物
|
||
Text personText = clickedItem.GetComponentInChildren<Text>();
|
||
if (personText != null)
|
||
{
|
||
// 字号变大和颜色变更(选中状态)
|
||
personText.fontSize = 36;
|
||
personText.color = color; // 选中颜色
|
||
}
|
||
}
|
||
|
||
//判断分管区域是否打开
|
||
public void IsOpen(int id)
|
||
{
|
||
if (selectScene.difficultyId > 3)
|
||
{
|
||
classCount.gameObject.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
classCount.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
//重新分配的按钮图片修改
|
||
public void ChangeImage(bool isSure)
|
||
{
|
||
if (isSure)
|
||
{
|
||
redistributeBtn.transform.GetComponent<Image>().sprite = showImage[1];
|
||
}
|
||
else
|
||
{
|
||
redistributeBtn.transform.GetComponent<Image>().sprite = showImage[0];
|
||
}
|
||
}
|
||
}
|