_xiaofang/xiaofang/Assets/Script/UI/PanelUI/EvacuationPanel.cs
2024-12-12 15:21:07 +08:00

566 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
//}
}