566 lines
20 KiB
C#
566 lines
20 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Xml.Serialization;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.Networking.Types;
|
||
using UnityEngine.UI;
|
||
using static System.Collections.Specialized.BitVector32;
|
||
using static UnityEditor.Progress;
|
||
|
||
public class EvacuationPanel : MonoBehaviour
|
||
{
|
||
public Dictionary<string, int> distributePeople = new Dictionary<string, int>();// 分配给各个场景的人数
|
||
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 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;
|
||
|
||
[Header("可分配列表")]
|
||
List<int> nonZeroAreas = new List<int>();
|
||
|
||
Dictionary<int, PersonnelItem> personnelItemsDict = new Dictionary<int, PersonnelItem>();
|
||
private HashSet<int> excludedAreas = new HashSet<int>(); // 被清空的区域 ID
|
||
public SelectScenePanel selectScene;
|
||
private HashSet<int> clearedAreas = new HashSet<int>();
|
||
// Start is called before the first frame update
|
||
void Start()
|
||
{
|
||
SetNpcType();
|
||
nonZeroAreas= GetNonZeroNpcRatioAreas();
|
||
jc = JuesechoicePop.GetComponent<JueseChoicePop>();
|
||
//redistributeBtn.onClick.AddListener(ClearData);
|
||
redistributeBtn.onClick.AddListener(() =>
|
||
{
|
||
if (redistributeBtn.interactable)
|
||
{
|
||
Debug.Log("Redistribute button clicked!");
|
||
RedistributeLogic();
|
||
}
|
||
});
|
||
CountsubmitBtn.onClick.AddListener(Submit);
|
||
submitBtn.onClick.AddListener(totalSubmit);
|
||
StuCountInputField.onEndEdit.AddListener(CheckInput);
|
||
SetClass();
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
CheckInput(StuCountInputField.text);
|
||
IsRedistribution();
|
||
IsOpen(selectScene.difficultyId);
|
||
}
|
||
//上传数据
|
||
public void totalSubmit()
|
||
{
|
||
Debug.Log(createTemplateInfo.Instance.auth_CreateTemplate + "===============");
|
||
NpcList nPC = new NpcList();
|
||
nPC.npcId = npcType;
|
||
nPC.areaId = roleid;
|
||
createTemplateInfo.Instance.auth_CreateTemplate.npcList = new List<NpcList>();
|
||
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];
|
||
}
|
||
|
||
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];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void Submit()
|
||
{
|
||
// 获取输入的总人数
|
||
int count = int.Parse(StuCountInputField.text); // 总人数
|
||
StuCountInputField.text = "";
|
||
|
||
foreach (var item in personnelItems)
|
||
{
|
||
personnelItemsDict[item.sceneId] = item; // 使用 sceneId 作为键
|
||
}
|
||
|
||
// 将 nonZeroAreas 转换为场景 ID 数组
|
||
int[] sceneIds = nonZeroAreas.ToArray();
|
||
|
||
// 调用分配方法
|
||
var result = DistributePeopleWithBalance(sceneIds, personnelItemsDict, count);
|
||
|
||
// 更新 UI 显示
|
||
foreach (var kvp in result)
|
||
{
|
||
if (personnelItemsDict.ContainsKey(kvp.Key))
|
||
{
|
||
personnelItemsDict[kvp.Key].SetInfo(kvp.Value.ToString()); // 更新UI
|
||
personnelItemsDict[kvp.Key].personnelImage.gameObject.SetActive(true);
|
||
}
|
||
}
|
||
}
|
||
public Dictionary<int, int> DistributePeopleWithBalance(int[] scenes, Dictionary<int, PersonnelItem> personnelItemsDict, int totalPeople)
|
||
{
|
||
// 1. 计算当前每个区域的总人数(初始人数 + 已分配人数)
|
||
Dictionary<int, int> totalPeoplePerScene = new Dictionary<int, int>();
|
||
foreach (var scene in scenes)
|
||
{
|
||
// 如果 personnelItemsDict 中包含该场景,取其初始人数;否则设为 0
|
||
if (personnelItemsDict.ContainsKey(scene))
|
||
{
|
||
totalPeoplePerScene[scene] = personnelItemsDict[scene].Num; // 初始人数
|
||
}
|
||
else
|
||
{
|
||
totalPeoplePerScene[scene] = 0;
|
||
}
|
||
|
||
// Debug 输出每个场景的初始人数
|
||
Debug.Log($"Scene {scene}: Initial People = {totalPeoplePerScene[scene]}");
|
||
}
|
||
|
||
// 保存初始人数以便后续计算
|
||
Dictionary<int, int> initialPeoplePerScene = new Dictionary<int, int>(totalPeoplePerScene);
|
||
|
||
// 2. 分配剩余人数
|
||
int remainingPeople = totalPeople;
|
||
while (remainingPeople > 0)
|
||
{
|
||
// 找出当前人数最少的区域
|
||
int minScene = -1; // 用于记录人数最少的场景 ID
|
||
int minPeople = int.MaxValue;
|
||
|
||
foreach (var scene in totalPeoplePerScene)
|
||
{
|
||
if (scene.Value < minPeople)
|
||
{
|
||
minPeople = scene.Value;
|
||
minScene = scene.Key;
|
||
}
|
||
}
|
||
|
||
// 分配一个 NPC 到人数最少的区域
|
||
if (minScene != -1) // 确保找到有效的场景
|
||
{
|
||
totalPeoplePerScene[minScene]++;
|
||
remainingPeople--;
|
||
}
|
||
else
|
||
{
|
||
break; // 如果没有找到有效的场景,终止分配
|
||
}
|
||
}
|
||
|
||
// 3. 计算分配结果,减去初始人数
|
||
Dictionary<int, int> allocatedPeople = new Dictionary<int, int>();
|
||
foreach (var scene in totalPeoplePerScene)
|
||
{
|
||
int initialPeople = initialPeoplePerScene.GetValueOrDefault(scene.Key, 0);
|
||
allocatedPeople[scene.Key] = scene.Value - initialPeople; // 分配人数 = 总人数 - 初始人数
|
||
}
|
||
|
||
return allocatedPeople;
|
||
}
|
||
|
||
//清除
|
||
//private void ClearData()
|
||
//{
|
||
// jc.classItem.isSet = false;
|
||
// foreach (var item in classItemList)
|
||
// {
|
||
// item.isSet = false;
|
||
// item.setClassItem("");
|
||
// }
|
||
// jc.classMate.isBeSet = false;
|
||
// foreach(var item in jc.classMateList)
|
||
// {
|
||
// item.isBeSet = false;
|
||
// item.setName();
|
||
// }
|
||
//}
|
||
|
||
//判断NPC的比例字段,列出分配比例不为0的所有区域名称。
|
||
public List<int> GetNonZeroNpcRatioAreas()
|
||
{
|
||
List<int> nonZeroAreas = new List<int>();
|
||
|
||
foreach (var sceneEntry in panel.sceneDataDictionary)
|
||
{
|
||
foreach (var sceneInfo in sceneEntry.Value)
|
||
{
|
||
foreach (var npcData in js.locationDictionary)
|
||
{
|
||
LocationData locationData = npcData.Value;
|
||
|
||
// 如果场景的 ID 匹配当前 NPC 的 ID
|
||
if (locationData.ID == int.Parse(sceneInfo.sceneId))
|
||
{
|
||
// 获取每个区域的 NpcRatio 字段
|
||
string npcRatio = locationData.NpcRatio;
|
||
|
||
// 将 NpcRatio 字符串按 '|' 分割,获取每一项
|
||
string[] npcRatioEntries = npcRatio.Split('|');
|
||
|
||
// 遍历每一项
|
||
foreach (var entry in npcRatioEntries)
|
||
{
|
||
// 将每一项按 ',' 分割,获取事故位置、NPCID、归属和分配比例
|
||
string[] entryData = entry.Split(',');
|
||
|
||
if (entryData.Length == 4)
|
||
{
|
||
string allocationRatio = entryData[3]; // 获取分配比例
|
||
|
||
// 检查分配比例是否不为 "0" 和 "-1"
|
||
if (allocationRatio != "0" && allocationRatio != "-1")
|
||
{
|
||
// 如果比例不为0,将该区域 ID 添加到列表
|
||
nonZeroAreas.Add(locationData.ID);
|
||
Debug.Log("locationData.ID"+ locationData.ID);
|
||
break; // 一旦找到有效的分配比例,就不再检查当前区域的其他项
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 输出所有分配比例不为0的区域 ID
|
||
foreach (var area in nonZeroAreas)
|
||
{
|
||
Debug.Log("区域 ID:" + area);
|
||
}
|
||
// 返回符合条件的区域 ID 列表
|
||
return nonZeroAreas;
|
||
}
|
||
|
||
//设置左侧场景显示
|
||
public void SetPersonnel()
|
||
{
|
||
// 清空现有的UI项
|
||
foreach (Transform child in personnelContent)
|
||
{
|
||
Destroy(child.gameObject);
|
||
}
|
||
// 清空人员列表
|
||
personnelItems.Clear();
|
||
foreach (var sceneEntry in panel.sceneDataDictionary)
|
||
{
|
||
foreach (var sceneInfo in sceneEntry.Value)
|
||
{
|
||
LocationData area = js.GetAreaDateById(int.Parse(sceneInfo.sceneId));
|
||
// 如果NpcRatio不为"-1"表示该场景有效
|
||
if (area.NpcRatio != "-1")
|
||
{
|
||
// 检查 personnelItems 是否已经包含该 sceneText.text
|
||
var existingItem = personnelItems.Find(item => item.sceneText.text == sceneEntry.Key);
|
||
if (existingItem != null)
|
||
{
|
||
// 如果已经存在,增加 Num
|
||
existingItem.Num++;
|
||
}
|
||
else
|
||
{
|
||
// 如果没有重复的 personnelItem,创建并添加
|
||
GameObject item = GameObject.Instantiate(personnelPrefabs, personnelContent);
|
||
PersonnelItem personnelItem = item.GetComponent<PersonnelItem>();
|
||
Button button = personnelItem.transform.Find("sceneText").GetComponent<Button>();
|
||
personnelItem.sceneText.text = sceneEntry.Key;
|
||
personnelItem.sceneId = area.ID;
|
||
personnelItem.Num = 1; // 设置初始值为 1
|
||
button.onClick.AddListener(() =>
|
||
{
|
||
OnSceneItemClicked(item, Color.yellow, selectedScene);
|
||
foreach (Transform child in sceneCount)
|
||
{
|
||
Destroy(child.gameObject);
|
||
}
|
||
LocationData locationData = js.GetAreaDateById(personnelItem.sceneId);
|
||
if(locationData.Level.ToString() != "0")
|
||
{
|
||
GameObject levelItem = GameObject.Instantiate<GameObject>(scenePrefab, sceneCount);
|
||
Button levelBtn = levelItem.transform.Find("chooseBtn2").GetComponent<Button>();
|
||
levelBtn.onClick.AddListener(() =>
|
||
{
|
||
JueseChoicePop jueseChoicePop= jueseChoicePanel.gameObject.GetComponent<JueseChoicePop>();
|
||
jueseChoicePop.SetClass(personnelItem.sceneId);
|
||
jueseChoicePanel.gameObject .SetActive(true);
|
||
});
|
||
ClassItem classItem = levelItem.GetComponent<ClassItem>();
|
||
classItem.classname.text = locationData.Level.ToString();
|
||
}
|
||
});
|
||
//Debug.Log("New PersonnelItem created. SceneId: " + personnelItem.sceneId + ", Num: " + personnelItem.Num);
|
||
personnelItems.Add(personnelItem);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break; // 如果遇到无效场景(NpcRatio为-1),跳出当前循环
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 判断重新分配按钮是否可以点击
|
||
public void IsRedistribution()
|
||
{
|
||
// 遍历 personnelItemsDict,检查是否有任何 PersonnelItem 的 gameObject 处于激活状态
|
||
bool canRedistribute = false;
|
||
|
||
foreach (var kvp in personnelItemsDict)
|
||
{
|
||
if (kvp.Value.personnelImage.gameObject.activeSelf) // 检查 gameObject 是否显示
|
||
{
|
||
canRedistribute = true;
|
||
break;
|
||
}
|
||
}
|
||
// 设置重新分配按钮的交互状态
|
||
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()
|
||
{
|
||
// 计算需要重新分配的 NPC 总数
|
||
int totalRedistributePeople = 0;
|
||
|
||
foreach (var kvp in personnelItemsDict)
|
||
{
|
||
PersonnelItem item = kvp.Value;
|
||
// 如果 gameObject 是激活的,表示需要清空 NPC
|
||
if (item.personnelImage.gameObject.activeSelf)
|
||
{
|
||
totalRedistributePeople += item.Num; // 累加需要重新分配的 NPC 数量
|
||
item.Num = 0; // 清空该区域的 NPC 数量
|
||
item.SetInfo(""); // 更新 UI 显示
|
||
item.personnelImage.gameObject.SetActive(false); // 隐藏图标
|
||
excludedAreas.Add(kvp.Key); // 记录清空的区域 ID
|
||
Debug.Log($"Cleared NPCs from Scene ID: {kvp.Key}");
|
||
}
|
||
}
|
||
|
||
// 准备有效分配区域列表(排除被清空的区域)
|
||
List<int> validAreas = new List<int>();
|
||
foreach (var kvp in personnelItemsDict)
|
||
{
|
||
if (!excludedAreas.Contains(kvp.Key)) // 排除清空的区域
|
||
{
|
||
validAreas.Add(kvp.Key);
|
||
}
|
||
}
|
||
|
||
// 如果没有有效区域,则提示
|
||
if (validAreas.Count == 0)
|
||
{
|
||
Debug.LogWarning("No valid areas available for redistribution.");
|
||
return;
|
||
}
|
||
|
||
// 将有效区域转换为数组
|
||
int[] validSceneIds = validAreas.ToArray();
|
||
|
||
// 调用分配方法,将清空区域的 NPC 分配到有效区域
|
||
var redistributionResult = DistributePeopleWithBalance(validSceneIds, personnelItemsDict, totalRedistributePeople);
|
||
|
||
// 更新分配结果到 UI
|
||
foreach (var kvp in redistributionResult)
|
||
{
|
||
if (personnelItemsDict.ContainsKey(kvp.Key))
|
||
{
|
||
personnelItemsDict[kvp.Key].Num += kvp.Value; // 更新人数
|
||
personnelItemsDict[kvp.Key].SetInfo(personnelItemsDict[kvp.Key].Num.ToString()); // 更新 UI 显示
|
||
personnelItemsDict[kvp.Key].personnelImage.gameObject.SetActive(true); // 确保图标显示
|
||
personnelItemsDict[kvp.Key].personnelNum.gameObject.SetActive(true); // 确保图标显示
|
||
Debug.Log($"Assigned {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);
|
||
}
|
||
}
|
||
//// 1. 把所选区域的NPC分配到其它区域
|
||
//public void RedistributeNpc(int selectedAreaId)
|
||
//{
|
||
// // 获取所有非已清空的区域ID
|
||
// var availableAreas = GetNonZeroNpcRatioAreas().Where(areaId => areaId != selectedAreaId && !clearedAreas.Contains(areaId)).ToList();
|
||
|
||
// // 从选中的区域获取NPC
|
||
// int npcToRedistribute = distributePeople[selectedAreaId.ToString()];
|
||
|
||
// if (npcToRedistribute == 0) return;
|
||
|
||
// // 移除该区域的NPC
|
||
// distributePeople[selectedAreaId.ToString()] = 0;
|
||
// //personnelItemsDict[selectedAreaId].UpdateNpcCount(0); // 假设你有一个更新UI的方法
|
||
|
||
// // 将这些NPC分配到其它区域
|
||
// DistributeNpcToOtherAreas(npcToRedistribute, availableAreas);
|
||
//}
|
||
|
||
//// 2. 记录被清空NPC分布的区域ID,下次重新分配时这些区域不参与分配
|
||
//private void DistributeNpcToOtherAreas(int npcToRedistribute, List<int> availableAreas)
|
||
//{
|
||
// if (availableAreas.Count == 0) return;
|
||
|
||
// // 简单的均分方式,你可以根据自己的需要修改分配策略
|
||
// int npcPerArea = npcToRedistribute / availableAreas.Count;
|
||
// foreach (var areaId in availableAreas)
|
||
// {
|
||
// distributePeople[areaId.ToString()] += npcPerArea;
|
||
// //personnelItemsDict[areaId].UpdateNpcCount(distributePeople[areaId]);
|
||
// }
|
||
|
||
// // 如果有剩余的NPC,可以将其分配到其他区域
|
||
// int remainder = npcToRedistribute % availableAreas.Count;
|
||
// for (int i = 0; i < remainder; i++)
|
||
// {
|
||
// distributePeople[availableAreas[i]] += 1;
|
||
// //personnelItemsDict[availableAreas[i]].UpdateNpcCount(distributePeople[availableAreas[i]]);
|
||
// }
|
||
//}
|
||
|
||
//// 重新分配前,清空区域时调用此方法,记录清空区域
|
||
//public void MarkAreaAsCleared(int areaId)
|
||
//{
|
||
// clearedAreas.Add(areaId);
|
||
//}
|
||
}
|