using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; using DG.Tweening; using Newtonsoft.Json; using Spine.Unity; using TowerClimberChronicles; using Unity.VisualScripting; using UnityEngine; public class CreatFlower : MonoBehaviour { // Start is called before the first frame update public Camera orthoCamera; public static CreatFlower instance; public List temp_slot_gameobject_list;//固定的暂存位置点位信息 public List flower_slot_gameobject_list_0; public List flower_slot_gameobject_list_1; public List flower_slot_gameobject_list_2; public List flower_slot_gameobject_list_3; public List pot_object_list; public List pot_object_type_image; public List pot_animation_list; public SkeletonAnimation clean_animation; public SkeletonAnimation refresh_animation; public List branch_list; public GameObject clean_pos_object; public List gray_pot_list; public List normal_branch_list; private List temp_slot_item_list = new List() { null,null,null,null,null };//暂存区的实例化的花 public List clean_item_list = new List();//使用道具后的item private List flower_slot_list0 = new List(); private List flower_slot_list1 = new List(); private List flower_slot_list2 = new List(); private List flower_slot_list3 = new List(); // private List all_flower_list = new List();//所有还没被销毁的花 public List slot_type_list = new List() { -1, -1, -1, -1 }; private List bubble_prefab_list = new List(); private List flower_image_list = new List(); private List pot_image_list = new List(); private List all_flower_in_pool_list = new List();//所有没被点击过的花; public bool CanClick = true; private GameObject top_area; // public bool slot_0_open = false; // public bool slot_1_open = false; private void Awake() { instance = this; // for (int i = 0; i < 16; i++) // { // img_list.Add(Resources.Load("card/card_sprite/" + i)); // } orthoCamera = GameObject.Find("GameCamera").GetComponent(); float size = (float)System.Math.Round(28.125f / ((float)Screen.width / Screen.height), 4); string type = SystemInfo.deviceModel.ToLower().Trim(); // //////Debug.Log($"type==========={type}"); if (type.Substring(0, 3) == "ipa") {//iPad机型 size = 49.9f; } orthoCamera.orthographicSize = size; GameObject target = GameObject.Find("qiang"); top_area = GameObject.Find("top_area"); FitObjectToScreenWidth(target, orthoCamera); AlignObjectBottom(target, orthoCamera); AlignObjectTop(top_area, orthoCamera); for (int i = 1; i < 6; i++) { bubble_prefab_list.Add(Resources.Load("flower/item/item_" + i)); } for (int i = 1; i < 13; i++) { flower_image_list.Add(Resources.Load("flower/image/" + i + "_b")); pot_image_list.Add(Resources.Load("flower/image/" + i + "_a")); } for (int i = 0; i < pot_animation_list.Count; i++) { pot_animation_list[i].gameObject.SetActive(false); } clean_animation.gameObject.SetActive(false); refresh_animation.gameObject.SetActive(false); // GameDispatcher.Instance.AddListener(GameMsg.FlowerEnd, ResetGame); GameDispatcher.Instance.AddListener(GameMsg.FlowerReset, ResetGame); } private GameObject Popup; // Update is called once per frame void Update() { if (Input.GetMouseButtonDown(0)) { if (!CanClick) return; if (Popup == null) Popup = GameObject.Find("Popup"); if (Popup.transform.childCount != 0) return; int layerMask = 1 << 7; // 如果射线与layerMask指定层的碰撞器发生碰撞 Ray ray = orthoCamera.ScreenPointToRay(Input.mousePosition); RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity, layerMask); if (hit.collider != null) { if (hit.collider.CompareTag("flower_mask")) { // 命中遮罩,不响应 return; } ChildItem child = hit.collider.GetComponent(); if (child != null) child.OnChildClicked(); } else { // //////Debug.Log("No hit"); } } if (show_finger) { finger_object.transform.rotation = Quaternion.identity; } } public void ResetGame(object a = null) { for (int i = bubble_parent.transform.childCount - 1; i >= 0; i--) { Destroy(bubble_parent.transform.GetChild(i).gameObject); } all_flower_in_pool_list.Clear(); for (int i = 0; i < temp_slot_item_list.Count; i++) { if (temp_slot_item_list[i] != null) Destroy(temp_slot_item_list[i]); } for (int i = 0; i < clean_item_list.Count; i++) { Destroy(clean_item_list[i]); } clean_item_list.Clear(); for (int i = 0; i < flower_slot_list0.Count; i++) { Destroy(flower_slot_list0[i]); } flower_slot_list0.Clear(); for (int i = 0; i < flower_slot_list1.Count; i++) { Destroy(flower_slot_list1[i]); } flower_slot_list1.Clear(); for (int i = 0; i < flower_slot_list2.Count; i++) { Destroy(flower_slot_list2[i]); } flower_slot_list2.Clear(); for (int i = 0; i < flower_slot_list3.Count; i++) { Destroy(flower_slot_list3[i]); } flower_slot_list3.Clear(); for (int i = 0; i < pot_object_list.Count; i++) { pot_object_list[i].SetActive(true); } for (int i = 0; i < pot_animation_list.Count; i++) { pot_animation_list[i].gameObject.SetActive(false); } GameDispatcher.Instance.Dispatch(GameMsg.RefreshFlowerCleanBtn); clean_item_list.Clear(); all_flower_in_pool_list.Clear(); slot_type_list = new List() { -1, -1, -1, -1 }; CanClick = true; DataMgr.FlowerLevelState.Value = 3; for (int i = 0; i < pot_object_list.Count; i++) { pot_object_list[i].transform.localScale = Vector3.one; } for (int i = 0; i < branch_list.Count; i++) { SpriteRenderer sr = branch_list[i].GetComponent(); Color c = sr.color; c.a = 1f; // 设置透明度为 1(完全不透明) sr.color = c; } CreatFlowerItem(); } public Transform AddFlowerInTemp(GameObject obj, int type) { FlowerUI.start_update = true; if (FlowerUI.Stop_time >= 5) { GameDispatcher.Instance.Dispatch(GameMsg.FlowerHideclickAni); } FlowerUI.Stop_time = 0; all_flower_in_pool_list.Remove(obj); List indices = new List(); for (int i = 0; i < slot_type_list.Count; i++) { if (slot_type_list[i] == type) { indices.Add(i); } } int index = -1; int in_slot_numbers = -1; if (indices.Count == 1) { index = indices[0]; } else if (indices.Count > 1) { for (int i = 0; i < indices.Count; i++) { int index_numbres = 0; if (indices[i] == 0) { index_numbres = flower_slot_list0.Count; } else if (indices[i] == 1) { index_numbres = flower_slot_list1.Count; } else if (indices[i] == 2) { index_numbres = flower_slot_list2.Count; } else if (indices[i] == 3) { index_numbres = flower_slot_list3.Count; } if (index_numbres > in_slot_numbers) { in_slot_numbers = index_numbres; index = indices[i]; } } } if (index >= 0) { if (index == 0 && flower_slot_list0.Count < 3) { flower_slot_list0.Add(obj); obj.GetComponent().sortingOrder = flower_slot_list0.Count; return flower_slot_gameobject_list_0[flower_slot_list0.Count - 1].transform; } else if (index == 1 && flower_slot_list1.Count < 3) { flower_slot_list1.Add(obj); obj.GetComponent().sortingOrder = flower_slot_list1.Count; return flower_slot_gameobject_list_1[flower_slot_list1.Count - 1].transform; } else if (index == 2 && flower_slot_list2.Count < 3) { flower_slot_list2.Add(obj); obj.GetComponent().sortingOrder = flower_slot_list2.Count; return flower_slot_gameobject_list_2[flower_slot_list2.Count - 1].transform; } else if (index == 3 && flower_slot_list3.Count < 3) { flower_slot_list3.Add(obj); obj.GetComponent().sortingOrder = flower_slot_list3.Count; return flower_slot_gameobject_list_3[flower_slot_list3.Count - 1].transform; } } int temp_numbers = 0; Transform transform_ = null; for (int i = 0; i < 5; i++) { if (temp_slot_item_list[i] == null) { transform_ = temp_slot_gameobject_list[i].transform; temp_slot_item_list[i] = obj; break; } } for (int i = 0; i < 5; i++) { if (temp_slot_item_list[i] != null) { temp_numbers++; } } if (temp_numbers >= 4) { bool next_have = false; for (int i = 0; i < temp_slot_item_list.Count; i++) { if (temp_slot_item_list[i] != null) { //if ((index >= 0) && ((temp_slot_item_list[i].GetComponent().type == next_type_list[index]))) if (next_type_list.Contains(temp_slot_item_list[i].GetComponent().type) || slot_type_list.Contains(temp_slot_item_list[i].GetComponent().type)) { next_have = true; break; } } } if (temp_numbers >= 5) { CanClick = false; if (!next_have) { if (DataMgr.FlowerLevelState.Value != 0) { UICtrlDispatcher.Instance.Dispatch(UICtrlMsg.FlowerRemakeUI_Open); FlowerUI.start_update = false; } else { float[] ch_array = GameHelper.GetRewardValue(2); var temp = new SuccessData(); temp.IsWin = false; temp.ch_number = ch_array[0]; temp.IsLevelSuccess = true; temp.IsH5Reward = false; temp.boost_array = GameHelper.GetRewardBoost(2); temp.level = DataMgr.FlowerLevel.Value; UICtrlDispatcher.Instance.Dispatch(UICtrlMsg.FlowerEndUI_Open, temp); } } } if (temp_numbers == 4) { if (!next_have) { GameDispatcher.Instance.Dispatch(GameMsg.FlowerFullTips); } } //////Debug.Log("满了"); } if (transform_ != null) return transform_; return null; } private int clear_pot_num; private int all_pot_num; private List next_type_list = new List() { -1,-1,-1,-1 }; public void CheckPot() { for (int i = 0; i < 4; i++) { int index = i; List slot_list = null; if (index == 0) slot_list = flower_slot_list0; else if (index == 1) slot_list = flower_slot_list1; else if (index == 2) slot_list = flower_slot_list2; else if (index == 3) slot_list = flower_slot_list3; if (slot_list.Count >= 3) { int old_type = slot_type_list[index]; slot_type_list[index] = -1; next_type_list[index] = CreatPotType(); // CanClick = false; DOVirtual.DelayedCall(0.5f, () => { for (int j = 0; j < 3; j++) { slot_list[j].GetComponent().DOFade(0f, 0.3f); } branch_list[index].GetComponent().DOFade(0f, 0.3f); }); DOVirtual.DelayedCall(0.9f, () => { int ani_type = old_type + 1; string ani_name; if (ani_type < 10) ani_name = "0" + ani_type; else ani_name = ani_type.ToString(); pot_animation_list[index].gameObject.SetActive(true); pot_animation_list[index].state.SetAnimation(0, "hua_" + ani_name, false); pot_animation_list[index].state.Complete += (trackEntry) => { pot_object_list[index].transform.DOScale(new Vector3(0f, 0f, 0f), 0.3f).OnComplete(() => { //////Debug.Log("缩放完成!"); pot_animation_list[index].gameObject.SetActive(false); if (next_type_list[index] >= 0) branch_list[index].GetComponent().sprite = pot_image_list[next_type_list[index]]; }); }; }); DOVirtual.DelayedCall(1, () => { for (int j = 0; j < 3; j++) { // all_flower_list.Remove(slot_list[j]); GameObject.Destroy(slot_list[j]); } slot_list.Clear(); clear_pot_num += 3; // CanClick = true; // //////Debug.Log("新创建的类型是:" + ne); // pot_object_list[index].SetActive(false); DOVirtual.DelayedCall(1.3f, () => { //////Debug.Log($"slot_type_list[{index}] = {next_type_list[index]}"); slot_type_list[index] = next_type_list[index]; CheckNewPot(index); }); }); } } if (all_flower_in_pool_list.Count == 0) { // bool temp_null = true; // for (int j = 0; j < temp_slot_item_list.Count; j++) // { // if (temp_slot_item_list[j] != null) // { // temp_null = false; // break; // } // } // if (temp_null) // { //////Debug.Log("游戏结束"); GameDispatcher.Instance.Dispatch(GameMsg.FlowelSuccess); // } } } // private int next_type = -1; void CheckNewPot(int index) { if (slot_type_list[index] >= 0) { List slot_list = null; if (index == 0) slot_list = flower_slot_list0; else if (index == 1) slot_list = flower_slot_list1; else if (index == 2) slot_list = flower_slot_list2; else if (index == 3) slot_list = flower_slot_list3; // pot_object_list[index].SetActive(true); if (slot_type_list[index] >= 0) { pot_object_type_image[index].sprite = flower_image_list[slot_type_list[index]]; } branch_list[index].GetComponent().DOFade(1f, 0.1f); pot_object_list[index].transform.DOScale(new Vector3(1f, 1f, 1f), 0.3f).OnComplete(() => { //////Debug.Log("放大完成!"); }); bool have_temp_ = false; for (int k = 0; k < temp_slot_item_list.Count; k++) { if (temp_slot_item_list[k] != null) { ChildItem ChildItem_ = temp_slot_item_list[k].GetComponent(); if (slot_type_list[index] == ChildItem_.type) { if (slot_list.Count < 3) { slot_list.Add(temp_slot_item_list[k]); List target_list = null; if (index == 0) target_list = flower_slot_gameobject_list_0; else if (index == 1) target_list = flower_slot_gameobject_list_1; else if (index == 2) target_list = flower_slot_gameobject_list_2; else if (index == 3) target_list = flower_slot_gameobject_list_3; ChildItem_.SetParentAndFly(top_area.transform, target_list[slot_list.Count - 1].transform, 0.5f); temp_slot_item_list[k].GetComponent().sortingOrder = slot_list.Count; temp_slot_item_list[k] = null; have_temp_ = true; CanClick = true; //////Debug.Log("有相同的!!!!!!!!!!!!!"); } } } } if (slot_list.Count < 3) { for (int n = 0; n < clean_item_list.Count; n++) { ChildItem ChildItem_ = clean_item_list[n].GetComponent(); if (ChildItem_.type == slot_type_list[index]) { if (slot_list.Count >= 3) break; slot_list.Add(clean_item_list[n]); List target_list = null; if (index == 0) target_list = flower_slot_gameobject_list_0; else if (index == 1) target_list = flower_slot_gameobject_list_1; else if (index == 2) target_list = flower_slot_gameobject_list_2; else if (index == 3) target_list = flower_slot_gameobject_list_3; ChildItem_.SetParentAndFly(top_area.transform, target_list[slot_list.Count - 1].transform, 0.5f); clean_item_list[n].GetComponent().sortingOrder = slot_list.Count; SpriteRenderer render = clean_item_list[n].GetComponent(); Color c = render.color; c.a = 1f; render.color = c; render.sortingOrder = slot_list.Count; clean_item_list[n] = null; have_temp_ = true; } } clean_item_list.RemoveAll(item => item == null); GameDispatcher.Instance.Dispatch(GameMsg.RefreshFlowerCleanBtn); } //////Debug.Log("再次调用检测方法"); if (have_temp_) { DOVirtual.DelayedCall(0.3f, () => { CheckPot(); }); } } } public GameObject bubble_parent; private FlowerMatch flowerMatch; float creatPotAccuracy;//生成的花盆可以直接被消除的概率 public void AddSlost(int index) { //////Debug.Log("解锁。。。。。。。。。。" + index); if (index == 0) { gray_pot_list[0].SetActive(false); normal_branch_list[0].SetActive(true); slot_type_list[2] = CreatPotType(); if (slot_type_list[2] >= 0) { pot_object_type_image[2].sprite = flower_image_list[slot_type_list[2]]; CheckNewPot(2); } else { pot_object_list[2].transform.DOScale(new Vector3(0f, 0f, 0f), 0.3f); } } else if (index == 1) { gray_pot_list[1].SetActive(false); normal_branch_list[1].SetActive(true); slot_type_list[3] = CreatPotType(); if (slot_type_list[3] >= 0) { pot_object_type_image[3].sprite = flower_image_list[slot_type_list[3]]; CheckNewPot(3); } else { pot_object_list[3].transform.DOScale(new Vector3(0f, 0f, 0f), 0.3f); } } // CheckPot(); } public void UseTipsItem() { List canremove_numbers = new List() { 0, 0, 0, 0 }; List canremove_obj = new List(); CanClick = false; for (int i = 0; i < all_flower_in_pool_list.Count; i++) { if (all_flower_in_pool_list[i].transform.position.y < (temp_slot_gameobject_list[0].transform.position.y))//视为可以点击的 { int item_type = all_flower_in_pool_list[i].GetComponent().type; for (int j = 0; j < 4; j++) { if (slot_type_list[j] == item_type) { canremove_obj.Add(all_flower_in_pool_list[i]); canremove_numbers[j]++; break; } } } } canremove_obj.Sort((a, b) => a.transform.position.y.CompareTo(b.transform.position.y)); List can_remove_index_array = new List(); for (int i = 0; i < canremove_numbers.Count; i++) { if (canremove_numbers[i] >= 3) { can_remove_index_array.Add(i);//0,1,2,3 } } int random_index = -1; if (can_remove_index_array.Count > 0) { random_index = can_remove_index_array[UnityEngine.Random.Range(0, can_remove_index_array.Count)]; } if (random_index >= 0) { int tips_type = slot_type_list[random_index]; List slot_list = null; if (random_index == 0) slot_list = flower_slot_list0; else if (random_index == 1) slot_list = flower_slot_list1; else if (random_index == 2) slot_list = flower_slot_list2; else if (random_index == 3) slot_list = flower_slot_list3; int slot_count = slot_list.Count; for (int i = 0; i < canremove_obj.Count; i++) { int item_type = canremove_obj[i].GetComponent().type; if (item_type == tips_type) { if (slot_count >= 3) break; canremove_obj[i].GetComponent().OnChildClicked(); slot_count++; } } CheckPot(); DataMgr.FlowerItem0.Value = DataMgr.FlowerItem0.Value - 1; GameHelper.ShowTips("Randomly clear a target flower"); } else { GameHelper.ShowTips("There are no flowers to remove"); } DOVirtual.DelayedCall(0.5f, () => { CanClick = true; }); //////Debug.Log(JsonConvert.SerializeObject(canremove_numbers)); } public void UseCleanItem() { bool is_null = true; CanClick = false; for (int i = 0; i < temp_slot_item_list.Count; i++) { if (temp_slot_item_list[i] != null) { is_null = false; break; } } if (is_null) { GameHelper.ShowTips("There are no flowers to clean"); CanClick = true; return; } clean_animation.gameObject.SetActive(true); clean_animation.state.SetAnimation(0, "animation", false); clean_animation.state.Complete += (trackEntry) => { clean_animation.gameObject.SetActive(false); }; for (int i = 0; i < temp_slot_item_list.Count; i++) { if (temp_slot_item_list[i] != null) { clean_item_list.Add(temp_slot_item_list[i]); GameObject temp = temp_slot_item_list[i]; DOVirtual.DelayedCall(1 - 0.1f * i, () => { temp.GetComponent().DOFade(0f, 0.1f); }); } temp_slot_item_list[i] = null; } DOVirtual.DelayedCall(1, () => { for (int i = 0; i < clean_item_list.Count; i++) { clean_item_list[i].transform.position = clean_pos_object.transform.position; } CanClick = true; }); GameDispatcher.Instance.Dispatch(GameMsg.RefreshFlowerCleanBtn); DataMgr.FlowerItem1.Value = DataMgr.FlowerItem1.Value - 1; } public void UseRefreshItem() { CanClick = false; refresh_animation.gameObject.SetActive(true); refresh_animation.state.SetAnimation(0, "animation", false); refresh_animation.state.Complete += (trackEntry) => { refresh_animation.gameObject.SetActive(false); }; FlyIntoCircle(all_flower_in_pool_list, refresh_animation.gameObject.transform.position, 4, 0.3f); } public void FlyIntoCircle(List objs, Vector3 center, float radius, float duration) { if (objs == null || objs.Count == 0) return; int count = objs.Count; for (int i = 0; i < count; i++) { GameObject obj = objs[i]; if (obj == null) continue; // 记录初始 localPosition Vector3 startLocalPos = obj.transform.localPosition; // 找到父物体上的 Rigidbody2D Rigidbody2D rb2d = obj.transform.parent != null ? obj.transform.parent.GetComponent() : null; if (rb2d != null && rb2d.simulated) { rb2d.simulated = false; } // 随机角度 float angle = UnityEngine.Random.Range(0f, Mathf.PI * 2f); // 半径用 sqrt(Random.value),保证均匀分布在圆内 float r = radius * Mathf.Sqrt(UnityEngine.Random.value); // 目标位置:圆心 + 半径 * (cos, sin) Vector3 targetPos = center + new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * r; // DOTween 移动到目标点位 obj.transform.DOMove(targetPos, duration).SetEase(Ease.OutQuad) .OnComplete(() => { // 停留 0.1 秒后再返回 DOVirtual.DelayedCall(0.3f, () => { // 在返回之前打乱 type 和 sprite ShuffleItems(objs); CanClick = true; obj.transform.DOLocalMove(startLocalPos, duration).SetEase(Ease.InQuad) .OnComplete(() => { if (rb2d != null && !rb2d.simulated) { rb2d.simulated = true; } }); }); }); } } void ShuffleItems(List objs) { // 收集所有 (type, sprite) 对 List<(int type, Sprite sprite)> pairs = new List<(int, Sprite)>(); foreach (var obj in objs) { if (obj == null) continue; ChildItem item = obj.GetComponent(); SpriteRenderer sr = obj.GetComponent(); if (item != null && sr != null) { pairs.Add((item.type, sr.sprite)); } } // 打乱 pairs 列表 System.Random rand = new System.Random(); pairs = pairs.OrderBy(x => rand.Next()).ToList(); // 重新分配,保持对应关系 int index = 0; foreach (var obj in objs) { if (obj == null) continue; ChildItem item = obj.GetComponent(); SpriteRenderer sr = obj.GetComponent(); if (item != null && sr != null) { item.type = pairs[index].type; sr.sprite = pairs[index].sprite; index++; } } } public int CreatPotType() { float[] Difficulty_array = flowerMatch.Difficulty; if (((float)clear_pot_num) / all_pot_num > Difficulty_array[1]) { creatPotAccuracy = flowerMatch.Accuracy[2]; } else if (((float)clear_pot_num) / all_pot_num > Difficulty_array[0]) { creatPotAccuracy = flowerMatch.Accuracy[1]; } else { creatPotAccuracy = flowerMatch.Accuracy[0]; } Debug.Log("flower---------当前完成进度:" + (float)clear_pot_num / all_pot_num); Debug.Log("flower---------当前击中率:" + creatPotAccuracy); List canremove_numbers = new List(); List all_numbers = new List(); for (int i = 0; i < all_flower_in_pool_list.Count; i++) { if (all_flower_in_pool_list[i].transform.position.y < (temp_slot_gameobject_list[0].transform.position.y))//视为可以点击的 { canremove_numbers.Add(all_flower_in_pool_list[i].GetComponent().type); } all_numbers.Add(all_flower_in_pool_list[i].GetComponent().type); } for (int i = 0; i < temp_slot_item_list.Count; i++) { if (temp_slot_item_list[i] != null) { canremove_numbers.Add(temp_slot_item_list[i].GetComponent().type); all_numbers.Add(temp_slot_item_list[i].GetComponent().type); } } for (int i = 0; i < clean_item_list.Count; i++) { canremove_numbers.Add(clean_item_list[i].GetComponent().type); all_numbers.Add(clean_item_list[i].GetComponent().type); } IEnumerable> grouped_all_number = all_numbers.GroupBy(x => x); List result_pot = new List(); foreach (IGrouping g in grouped_all_number) { int newCount = g.Count() / 3; // 出现次数除以3 for (int i = 0; i < newCount; i++) { result_pot.Add(g.Key); } } for (int i = 0; i < slot_type_list.Count; i++) { result_pot.Remove(slot_type_list[i]); } for (int i = 0; i < next_type_list.Count; i++) { result_pot.Remove(next_type_list[i]); } IEnumerable> grouped = canremove_numbers.GroupBy(x => x); System.Random rand = new System.Random(); int randomMore = -1; IEnumerable> moreThanThreeGroups = grouped.Where(g => g.Count() >= 3); List moreThanThreeKeys = moreThanThreeGroups.Select(g => g.Key).ToList(); if (moreThanThreeKeys.Count > 0) { int index = rand.Next(moreThanThreeKeys.Count); randomMore = moreThanThreeKeys[index]; } int randomLess = -1; IEnumerable> lessThanThreeGroups = grouped.Where(g => g.Count() < 3); List lessThanThreeKeys = lessThanThreeGroups.Select(g => g.Key).ToList(); if (lessThanThreeKeys.Count > 0) { int index = rand.Next(lessThanThreeKeys.Count); randomLess = lessThanThreeKeys[index]; } // Console.WriteLine("随机选取的 ≥3 元素: " + randomMore); // Console.WriteLine("随机选取的 <3 元素: " + randomLess); System.Random randdom_ = new System.Random(); double value = randdom_.NextDouble(); if (value < creatPotAccuracy)//生成可以消除的 { if (result_pot.Count <= 0) return -1; Debug.Log("flower---------当前击中了"); if (creatPotAccuracy < 0)//目前显示出的没有可以消除的了,随机一个出来 { Debug.Log("flower---------当前没有可以消除的元素,随机一个"); return result_pot[UnityEngine.Random.Range(0, result_pot.Count)]; } if (result_pot.Contains(randomMore)) { Debug.Log("flower---------当前有可以消除的元素,生成一个"); return randomMore; } else { Debug.Log("flower---------当前没有可以消除的元素,随机一个"); return result_pot[UnityEngine.Random.Range(0, result_pot.Count)]; } } else { if (result_pot.Count <= 0) return -1; Debug.Log("flower---------当前没有击中"); if (randomLess < 0) { Debug.Log("flower---------当前没有不能消除的元素,随机一个"); return result_pot[UnityEngine.Random.Range(0, result_pot.Count)]; } if (result_pot.Contains(randomLess)) { Debug.Log("flower---------生成不能消除的元素"); return randomLess; } else { Debug.Log("flower---------当前没有不能消除的元素,随机一个"); return result_pot[UnityEngine.Random.Range(0, result_pot.Count)]; } } } private bool show_finger = false; private GameObject finger_object; public void DestoryFinger() { show_finger = false; Destroy(finger_object); } public void CreatFlowerItem() { int level = DataMgr.FlowerLevel.Value; //////Debug.Log(ConfigSystem.GetConfig()[level]); flowerMatch = ConfigSystem.GetConfig()[level]; #if UNITY_EDITOR // flowerMatch.ElementCount = 21; #endif List elements = Allocate(flowerMatch.ElementCount, 12, flowerMatch.ElementTypes); //////Debug.Log(JsonConvert.SerializeObject(elements)); // 输出示例: [3, 7, 7, 5, 2, 2, 9, 9, 9, ...] 共 30 个 // 每个数字代表种类编号,数量分布是两个 6、两个 9 all_pot_num = flowerMatch.ElementCount; int[] counts = Allocate(flowerMatch.ElementCount, (float)flowerMatch.TypeDistribution / 100); //////Debug.Log(JsonConvert.SerializeObject(counts)); // 1. 收集所有要生成的对象 List toSpawn = new List(); for (int i = 0; i < 5; i++) { for (int j = 0; j < counts[i]; j++) { toSpawn.Add(bubble_prefab_list[i]); } } // 2. 打乱顺序 toSpawn = toSpawn.OrderBy(x => UnityEngine.Random.value).ToList(); //////Debug.Log(JsonConvert.SerializeObject(slot_type_list) + "??????????????8"); // 3. 按顺序生成并摆放 Vector3 basePos = bubble_parent.transform.position; float xSpacing = 20f; float ySpacing = 20f; int maxPerRow = 3; int image_index = 0; for (int counter = 0; counter < toSpawn.Count; counter++) { int row = counter / maxPerRow; int col = counter % maxPerRow; Vector3 pos = basePos + new Vector3(col * xSpacing, row * ySpacing, 0); GameObject piece = Instantiate(toSpawn[counter], pos, Quaternion.identity, bubble_parent.transform); // 获取所有子物体的 SpriteRenderer(排除自己) SpriteRenderer[] childRenderers = piece.transform.Cast() // 遍历直接子物体 .Select(t => t.GetComponent()) // 获取子物体上的 SpriteRenderer .Where(r => r != null) // 过滤掉没有 SpriteRenderer 的 .ToArray(); // 遍历使用 for (int i = 0; i < childRenderers.Length; i++) { childRenderers[i].sprite = flower_image_list[elements[image_index]]; all_flower_in_pool_list.Add(childRenderers[i].gameObject); // 获取对应子物体上的脚本 ChildItem script = childRenderers[i].gameObject.GetComponent(); script.type = elements[image_index]; // 举例调用 image_index++; } if (DataMgr.FlowerLevel.Value == 0 && counter == 0) { GameObject spinePrefab = Resources.Load("flower/effect/guide/guide"); //////Debug.Log(piece.transform.Find("child_0")); finger_object = Instantiate(spinePrefab, piece.transform.Find("child_0").transform); finger_object.transform.rotation = Quaternion.identity; SkeletonAnimation skeletonAnimation = finger_object.transform.Find("ani_parent").GetComponent(); skeletonAnimation.state.SetAnimation(0, "animation", true); show_finger = true; } Rigidbody2D rb = piece.GetComponent(); if (rb != null) { rb.angularVelocity = UnityEngine.Random.Range(-200f, 200f); } } slot_type_list[0] = CreatPotType(); branch_list[0].GetComponent().sprite = pot_image_list[slot_type_list[0]]; pot_object_type_image[0].sprite = flower_image_list[slot_type_list[0]]; slot_type_list[1] = CreatPotType(); if (slot_type_list[1] >= 0) { pot_object_type_image[1].sprite = flower_image_list[slot_type_list[1]]; branch_list[1].GetComponent().sprite = pot_image_list[slot_type_list[1]]; } gray_pot_list[0].SetActive(true); gray_pot_list[1].SetActive(true); normal_branch_list[0].SetActive(false); normal_branch_list[1].SetActive(false); } public static List Allocate(int total, int kinds, int choose) { if (total % 3 != 0) throw new ArgumentException("总数必须是3的倍数"); System.Random rand = new System.Random(); // 随机选出指定数量的种类(范围 0..kinds-1) var chosen = Enumerable.Range(0, kinds) // 改成从 0 开始 .OrderBy(_ => rand.Next()) .Take(choose) .ToArray(); //////Debug.Log("当前随机出的花的种类" + JsonConvert.SerializeObject(chosen)); // 以3为单位来分配 int units = total / 3; // 总共多少个“单位” int basePerKind = units / choose; // 每种基础单位数 int remainderUnits = units % choose; // 余下的单位数 // 分配数量 int[] counts = new int[choose]; for (int i = 0; i < choose; i++) counts[i] = basePerKind * 3; for (int i = 0; i < remainderUnits; i++) counts[i] += 3; // 打乱分配顺序 counts = counts.OrderBy(_ => rand.Next()).ToArray(); // 展开成元素列表 var result = new List(total); for (int i = 0; i < choose; i++) { for (int j = 0; j < counts[i]; j++) { result.Add(chosen[i]); } } // 打乱元素顺序 result = result.OrderBy(_ => rand.Next()).ToList(); return result; } ////////////////////计算方法 /// // 返回各类型道具数量:[type1, type2, type3, type4, type5] // N:总元素数量(必须精确满足) // rBig:大道具占比目标(按“道具数量”定义) // ratioTolerance:容错范围(例如 0.05 表示 ±5%) public static int[] Allocate(int N, float rBig, float ratioTolerance = 0.05f, int maxIters = 10000) { if (N < 0) throw new ArgumentOutOfRangeException(nameof(N)); if (rBig < 0f || rBig > 1f) throw new ArgumentOutOfRangeException(nameof(rBig)); if (ratioTolerance < 0f || ratioTolerance > 1f) throw new ArgumentOutOfRangeException(nameof(ratioTolerance)); // 容量: 1..5 int[] caps = { 1, 2, 3, 4, 5 }; // 小/大索引集合 int[] smallIdx = { 0, 1, 2 }; int[] bigIdx = { 3, 4 }; // 1) 基于目标占比估算平均容量,估算总道具数 M float avgSmall = (1 + 2 + 3) / 3f; // 2.0 float avgBig = (4 + 5) / 2f; // 4.5 float avgCap = (1f - rBig) * avgSmall + rBig * avgBig; int M = Math.Max(1, (int)Math.Round(N / avgCap)); // 2) 先按占比分道具数量,再组内平均 int bigCount = (int)Math.Round(M * rBig); int smallCount = M - bigCount; int[] counts = new int[5]; EvenSplitInto(counts, smallIdx, smallCount); EvenSplitInto(counts, bigIdx, bigCount); // 3) 容量校正:保证 sum(caps[i]*counts[i]) == N int S = TotalCapacity(counts, caps); // 贪心迭代:每次增加/减少一个道具,选择对“容量差”和“占比偏差”综合更优的类型 for (int iter = 0; iter < maxIters && S != N; iter++) { int sumProps = counts.Sum(); float currentBigRatio = sumProps > 0 ? (counts[3] + counts[4]) / (float)sumProps : 0f; float ratioError = Math.Abs(currentBigRatio - rBig); // 我们构造一个候选集合:当 S < N 需要增加一个道具;当 S > N 需要减少一个道具(数量必须 >0) bool needAdd = S < N; int diff = Math.Abs(N - S); // 评分函数:优先弥补容量差,同时尽量减小占比偏差 // score 越小越好 double bestScore = double.PositiveInfinity; int bestType = -1; for (int i = 0; i < 5; i++) { if (!needAdd && counts[i] == 0) continue; // 不能减到负数 // 试探性变更 int dProps = needAdd ? +1 : -1; int newSumProps = sumProps + dProps; if (newSumProps <= 0) continue; int newS = S + (needAdd ? +caps[i] : -caps[i]); // 新的大道具比例 int newBigCount = counts[3] + counts[4]; if (i == 3 || i == 4) newBigCount += needAdd ? 1 : -1; float newBigRatio = newBigCount / (float)newSumProps; // 容量误差与占比误差 int newDiff = Math.Abs(N - newS); float newRatioError = Math.Abs(newBigRatio - rBig); // 打分:容量误差权重高,细微平衡占比误差 // 你可以根据需要调整权重 wRatio 以强化/弱化占比优先级。 const double wRatio = 0.5; // 越大越重视靠近占比 double score = newDiff + wRatio * Math.Max(0f, newRatioError - ratioError); // 为了平滑地贴近 diff,也考虑容量步长的合适性(越接近 diff 越好) score += 0.01 * Math.Abs(caps[i] - diff); if (score < bestScore) { bestScore = score; bestType = i; } } if (bestType < 0) break; // 没有可行动作(理论上不应该发生),保护性退出 // 应用最佳动作 if (needAdd) { counts[bestType]++; S += caps[bestType]; } else { counts[bestType]--; S -= caps[bestType]; } } // 4) 若仍未达成精确容量(极少数边缘案例),回退到纯容量贪心补齐 if (S != N) { // 简单补齐:优先用 5/4 增加或用 1/2 减少 if (S < N) { S += GreedyCapacityFix(counts, caps, N - S, add: true); } else { S -= GreedyCapacityFix(counts, caps, S - N, add: false); } } // 5) 可选:如果你希望严格将大道具比例限制在 [rBig ± ratioTolerance] 范围, // 可以在此做一次微调,但必须保持 S == N(通过“等容量替换”实现)。 // 示例策略:在小/大组内等容量交换(比如用一个3替代一个1+2),保证容量不变只改比例。 // 为简洁,这里先不给出额外等容量替换;若需要,我可以加一个安全的交换器。 return counts; } private static void EvenSplitInto(int[] counts, int[] indices, int total) { if (indices.Length == 0 || total <= 0) return; int q = total / indices.Length; int r = total % indices.Length; for (int i = 0; i < indices.Length; i++) counts[indices[i]] += q; for (int i = 0; i < r; i++) counts[indices[i]] += 1; // 轮询余数 } private static int TotalCapacity(int[] counts, int[] caps) { int sum = 0; for (int i = 0; i < counts.Length; i++) sum += counts[i] * caps[i]; return sum; } // 只考虑容量差的贪心修正(作为兜底) private static int GreedyCapacityFix(int[] counts, int[] caps, int diff, bool add) { int changed = 0; if (add) { // 优先用高容量填补 for (int i = caps.Length - 1; i >= 0 && changed < diff; i--) { int step = caps[i]; int canDo = (diff - changed) / step; if (canDo <= 0) continue; counts[i] += canDo; changed += canDo * step; } // 若仍有剩余,用最小步长补到位 for (int i = caps.Length - 1; i >= 0 && changed < diff; i--) { counts[i] += 1; changed += caps[i]; } } else { // 优先从低容量减 for (int i = 0; i < caps.Length && changed < diff; i++) { int step = caps[i]; int canDo = Math.Min(counts[i], (diff - changed) / step); if (canDo <= 0) continue; counts[i] -= canDo; changed += canDo * step; } // 若仍有剩余,从最低容量逐个减 for (int i = 0; i < caps.Length && changed < diff; i++) { if (counts[i] <= 0) continue; counts[i] -= 1; changed += caps[i]; i--; // 继续在同一类型尝试 } } return changed; } void AlignObjectTop(GameObject obj, Camera cam) { // 相机顶部的世界坐标 float topY = cam.transform.position.y + cam.orthographicSize; // 物体一半高度 float objHalfHeight = 50f; Vector3 pos = obj.transform.position; pos.y = topY - objHalfHeight; obj.transform.position = pos; } void FitObjectToScreenWidth(GameObject obj, Camera cam) { float worldWidth = 2f * cam.orthographicSize * cam.aspect; float objWidth = obj.GetComponent().bounds.size.x; float scale = worldWidth / objWidth; obj.transform.localScale = new Vector3(scale, scale, 1f); } void AlignObjectBottom(GameObject obj, Camera cam) { float bottomY = cam.transform.position.y - cam.orthographicSize; float objHalfHeight = obj.GetComponent().bounds.extents.y; Vector3 pos = obj.transform.position; pos.y = bottomY + objHalfHeight + 12; obj.transform.position = pos; } }