import AvatarPanel from "../AvatarPanel/AvatarPanel"; import CSMessage from "../Common/Message/CSMessage"; import { CoroutineV2 } from "../Engine/CatanEngine/CoroutineV2/CoroutineV2"; import HoldButton from "../Engine/Component/Button/HoldButton"; import LocalStorageData from "../Engine/Data/LocalStorageData"; import HistoryPanel from "../HistoryPanel/HistoryPanel"; import Lobby from "../Lobby/Lobby"; import ScoreBoard from "../ScoreBoard/ScoreBoard"; import VoicePanel from "../VoicePanel/VoicePanel"; import NodePackageManager from "../_BootLoader/Npm/NodePackageManager"; import ConfigManager from "./ConfigManager"; import { GameRecord, MemberData, ScoreResult } from "./MemberData"; import RecordManager from "./RecordManager"; import { URLSchemeHandler } from "./URLSchemeHandler"; const { ccclass, property } = cc._decorator; @ccclass export class Badminton extends cc.Component { //#region property @property({ type: cc.Prefab }) public toggleItem: cc.Prefab = null; @property({ type: cc.Prefab }) public teamItem: cc.Prefab = null; @property({ type: cc.EditBox }) public inputNameText: cc.EditBox = null; @property({ type: cc.Label }) public storageText: cc.Label = null; @property({ type: cc.Node }) public ToggleItemContent: cc.Node = null; @property({ type: cc.Node }) public TeamItemContent: cc.Node = null; @property({ type: ScoreBoard }) public ScoreBoard: ScoreBoard = null; @property({ type: AvatarPanel }) public AvatarPanel: AvatarPanel = null; @property({ type: HistoryPanel }) public HistoryPanel: HistoryPanel = null; @property({ type: VoicePanel }) public VoicePanel: VoicePanel = null; @property({ type: Lobby }) public Lobby: Lobby = null; // @property({ type: AudioListSwitch }) // public GameBGM: AudioListSwitch = null; // @property({ type: AudioListSwitch }) // public TextToSpeech: TextToSpeech { get; private set; } //#endregion //#region 實例 /** Badminton實例 */ private static _instance: Badminton = null; public static get Instance(): Badminton { return this._instance; } //#endregion //#region public public TeamMemberList: MemberData[] = []; /** 目前所有可用玩家名單 */ public CurMemberList: string[] = []; /** 預設球員(塞空格) */ public DefaultMember: MemberData = new MemberData("那個"); /** RecordManager */ public Record: RecordManager = new RecordManager(this); /** ConfigManager */ public Config: ConfigManager = new ConfigManager(this); //#endregion //#region private private _m_toggleList: cc.Toggle[] = []; private _m_teamList: cc.Node[] = []; /** 各玩家分數比賽次數記錄 */ private _m_results: Map = new Map(); /** 比賽歷史記錄(記錄每場次的參賽玩家組合與順序) [{time,team:[[name1,name2],[name3,name4]],type,score:[t1,t2] },] */ private _m_history: GameRecord[] = []; private _isLoopStartDistribution: boolean = false; //#endregion //#region get set public static get Today(): string { return NodePackageManager.Instance.Dayjs().format("YYYYMMDD"); } public get TeamCount(): number { return this._m_teamList.length; } /** 比賽歷史記錄(記錄每場次的參賽玩家組合與順序) [{time,team:[[name1,name2],[name3,name4]],type,score:[t1,t2] },] */ public get History(): GameRecord[] { return this._m_history; } //#endregion //#region 初始化 protected onLoad(): void { Badminton._instance = this; let self: this = this; new NodePackageManager(); new LocalStorageData(); let AsyncFunction: () => IterableIterator = function* (): IterableIterator { yield CoroutineV2.Parallel( self.Config.Init(), self.Record.Init(), ).Start(); CoroutineV2.Parallel( self.Lobby.Show(), self.ScoreBoard.Show(), ).Start(); if (self.HistoryPanel != null) { self.HistoryPanel.LoadRecord(); self.HistoryPanel.Hide(); CoroutineV2.Single(self.HistoryPanel.Hide()).Start(); } // textToSpeech = FindObjectOfType(); self.HistoryPanel.Initial(self); self.AvatarPanel.Initial(self); CoroutineV2.Single(self.Show()).Start(); }; CoroutineV2.Single(AsyncFunction()).Start(); } protected update(dt: number): void { if (this._isLoopStartDistribution) { this.OnClickStartDistribution(); } } public *Show(): IterableIterator { CoroutineV2.Single(this.ScoreBoard.Hide()).Start(); this._initUI(); this.LoadStatus(); // 跨日後計分清除 if (LocalStorageData.Instance.Date !== Badminton.Today) { cc.warn("跨日後計分清除"); this.OnClickClearAllGameResult(); } URLSchemeHandler.Init(); } //#endregion //#region Custom private _initUI(): void { let self: this = this; this._updateCurSelMember(); // this.toggleItem.gameObject.SetActive(false); // this.teamItem.gameObject.SetActive(false); let parent: cc.Node = this.TeamItemContent; // for (let i: number = parent.childrenCount - 1; i > 0; i--) { // parent.children[i].destroy(); // } parent.removeAllChildren(); this._m_teamList.Clear(); parent = this.ToggleItemContent; // for (let i: number = parent.childrenCount - 1; i > 0; i--) { // parent.children[i].destroy(); // } parent.removeAllChildren(); this._m_toggleList.Clear(); for (let idx: number = 0; idx < this.TeamMemberList.length; idx++) { let memberName: string = this.TeamMemberList[idx].Name; let item: cc.Toggle = parent.ExAddChild(this.toggleItem).getComponent(cc.Toggle); item.node.getChildByName("Name").getComponent(cc.Label).string = memberName; item.node.active = true; item.node.getChildByName("Btn_Del").on("click", () => { this.OnDelMember(idx); }, this); let picObj: cc.Node = item.node.getChildByName("Avatar").getChildByName("Pic"); if (picObj != null) { picObj.getComponent(cc.Sprite).spriteFrame = this.Config.GetAvatarPicById(this.TeamMemberList[idx].AvatarId); picObj.parent.getComponent(HoldButton).OnInvoke.AddListener(() => { this.OnChangeAvatar(+idx); }); picObj.parent.on("click", () => { item.isChecked = !item.isChecked; self._onChangeSelMember(item); }, this); } this._m_toggleList.push(item); item.isChecked = this.CurMemberList.indexOf(memberName) !== -1; item.node.on("toggle", this._onChangeSelMember, this); } } public ReloadUI(): void { let chkMemberList: string[] = this.GetMemberListFromTeamView(); this._initUI(); this._updateTeamShow(chkMemberList); } private _onChangeSelMember(toggle: cc.Toggle): void { let val: boolean = toggle.isChecked; this._updateCurSelMember(); let chkMemberList: string[] = this.GetMemberListFromTeamView(); let dName: string = this.GetDefaultMemberName(); let selName: string = null; if (val) { for (let i: number = 0; i < this.CurMemberList.length; i++) { if (chkMemberList.indexOf(this.CurMemberList[i]) === -1) { selName = this.CurMemberList[i]; break; } } for (let i: number = 0; i < chkMemberList.length; i++) { if (chkMemberList[i] === dName) { chkMemberList[i] = selName; this._updateTeamShow(chkMemberList); return; } } if (selName != null) { chkMemberList.push(selName); } this._updateTeamShow(chkMemberList); } else { for (let i: number = 0; i < chkMemberList.length; i++) { if (this.CurMemberList.indexOf(chkMemberList[i]) === -1) { selName = chkMemberList[i]; if (i === chkMemberList.length - 1) { chkMemberList.ExRemoveAt(chkMemberList.length - 1); } else { chkMemberList[i] = this.GetDefaultMemberName(); } this._updateTeamShow(chkMemberList); break; } } } } private _updateCurSelMember(): void { this.CurMemberList.Clear(); this._m_toggleList.forEach((member: cc.Toggle) => { if (member.isChecked) { this.CurMemberList.push(member.node.getChildByName("Name").getComponent(cc.Label).string); } }); if (this.TeamMemberList != null && this.TeamMemberList.length > 0) { this.CurMemberList.push(this.GetDefaultMemberName()); } } public OnClickStartDistribution(): void { this.CurMemberList.Clear(); let chkMemberList: string[] = []; for (let member of this._m_toggleList) { if (member.isChecked) { chkMemberList.push(member.node.getChildByName("Name").getComponent(cc.Label).string); } } chkMemberList = this.GetListRandomize(chkMemberList); this._updateTeamShow(chkMemberList); } public OnClickLoopStartDistribution(): void { this._isLoopStartDistribution = !this._isLoopStartDistribution; } public GetMemberListFromTeamView(): string[] { let chkMemberList: string[] = []; for (let i: number = 0; i < this._m_teamList.length; i++) { let team: cc.Node = this._m_teamList[i]; if (!team.active) { break; } for (let j: number = 0; j < 2; j++) { let memberName: string = team.getChildByName("Member_" + (j + 1)).getChildByName("Name").getComponent(cc.Label).string; chkMemberList.push(memberName); } } return chkMemberList; } public GetDefaultMemberName(): string { return "那個"; } private _updateTeamShow(chkMemberList: string[]): void { let teamCount: number = Math.floor(chkMemberList.length / 2); let maxTeam: number = Math.ceil(chkMemberList.length / 2.0); while (this._m_teamList.length > maxTeam) { this._m_teamList[this._m_teamList.length - 1].destroy(); this._m_teamList.ExRemoveAt(this._m_teamList.length - 1); } if (maxTeam === 0 || (chkMemberList.length === 1 && chkMemberList[0] === this.GetDefaultMemberName())) { return; } for (let i: number = 0; i < maxTeam; i++) { let obj: cc.Node; if (i >= this._m_teamList.length) { obj = this.TeamItemContent.ExAddChild(this.teamItem); this._m_teamList.push(obj); } else { obj = this._m_teamList[i]; } obj.getChildByName("Member_1").getChildByName("Name").getComponent(cc.Label).string = ""; obj.getChildByName("Member_2").getChildByName("Name").getComponent(cc.Label).string = ""; obj.getChildByName("Member_1").getComponent(cc.Sprite).enabled = false; obj.getChildByName("Member_2").getComponent(cc.Sprite).enabled = false; obj.active = false; } let index: number = 0; for (let idx: number = 0; idx < teamCount && idx < maxTeam; idx++) { if (chkMemberList[0] === chkMemberList[1] && chkMemberList[0] === this.GetDefaultMemberName()) { chkMemberList.splice(0, 2); continue; } let team: cc.Node = this._m_teamList[index++]; team.getChildByName("No").getComponent(cc.Label).string = index.toString(); for (let j: number = 0; j < 2; j++) { let name: string = chkMemberList[0]; if (j === 0 && name === this.GetDefaultMemberName()) { name = chkMemberList[1]; chkMemberList.ExRemoveAt(1); } else { chkMemberList.ExRemoveAt(0); } team.getChildByName("Member_" + (j + 1)).getChildByName("Name").getComponent(cc.Label).string = name; team.getChildByName("Member_" + (j + 1)).getComponent(cc.Sprite).enabled = name !== this.GetDefaultMemberName(); team.getChildByName("Member_" + (j + 1)).getComponent(cc.Sprite).spriteFrame = this.Config.GetAvatarPicByName(name); team.active = true; } } if (chkMemberList.length > 0 && teamCount < maxTeam) { let name_1: string = chkMemberList[0]; let name_2: string = this.GetDefaultMemberName(); let team: cc.Node = this._m_teamList[teamCount]; team.getChildByName("Member_1").getChildByName("Name").getComponent(cc.Label).string = name_1; team.getChildByName("Member_2").getChildByName("Name").getComponent(cc.Label).string = name_2; team.getChildByName("Member_1").getComponent(cc.Sprite).enabled = true; team.getChildByName("Member_1").getComponent(cc.Sprite).spriteFrame = this.Config.GetAvatarPicByName(name_1); team.getChildByName("No").getComponent(cc.Label).string = (index + 1).toString(); team.active = true; } } public OnClickCleanTeam(): void { for (let obj of this._m_toggleList) { obj.isChecked = false; this._onChangeSelMember(obj); } } public OnDelMember(index: number): void { let viewTeamList: string[] = this.GetMemberListFromTeamView(); let player: MemberData = this.TeamMemberList[index]; let teamIndex: number = viewTeamList.indexOf(player.Name); if (teamIndex !== -1) { viewTeamList[teamIndex] = this.GetDefaultMemberName(); } this.TeamMemberList.ExRemoveAt(index); this._initUI(); this._updateTeamShow(viewTeamList); if (teamIndex !== -1) { this._updateCurSelMember(); } } public GetListRandomize(list: any[]): any[] { list.sort(function (): number { return (0.5 - Math.random()); }); return list; } public OnClickAddMember(): void { let newName: string = this.inputNameText.string; if (String.IsNullOrWhiteSpace(newName)) { return; } let members: string[] = this.TeamMemberList.map(m => m.Name); if (members.includes(newName)) { CSMessage.CreateYesMsg(newName + "已經在名單內"); return; } this.TeamMemberList.push(new MemberData(newName)); this.inputNameText.string = ""; let viewTeamList: string[] = this.GetMemberListFromTeamView(); this._initUI(); this._updateTeamShow(viewTeamList); this._updateGameResult(); } public OnChangeAvatar(index: number): void { CoroutineV2.Single(this.AvatarPanel.Show(this.TeamMemberList[index])).Start(); } public SaveStatus(): void { // member let member_list: string[] = this.GetMemberListFromTeamView(); LocalStorageData.Instance.Member = member_list; let avatar_list: number[] = member_list.map(m => this.Config.GetAvatarDataByName(m).ID); LocalStorageData.Instance.Avatar = avatar_list; LocalStorageData.Instance.IsSingleMode = this.ScoreBoard.isSingleMode ? 1 : 0; let selected_list: string[] = this.ScoreBoard.selectedList; LocalStorageData.Instance.Selected = selected_list; let firstTeam: number = this.ScoreBoard.firstTeam; LocalStorageData.Instance.FirstTeam = firstTeam; // TODO ScoreBoard // let score_list = this.ScoreBoard.GetScoreWinList(); // LocalStorageData.Instance.Score = score_list; let result_dict: Map = new Map(); this._m_results.forEach((item: ScoreResult, key: string, map: Map) => { let obj: Object = { win: item.Win, total: item.Total, }; result_dict.set(key, obj); }); LocalStorageData.Instance.Results = result_dict; // // 增加紀錄日期 LocalStorageData.Instance.Date = Badminton.Today; if (this.HistoryPanel != null) { // 增加隊伍歷史紀錄 // 格式 json: {"日期":[玩家1,玩家2,...],"日期":[玩家1,玩家2,...]} let history_dict: Map = this.HistoryPanel.History; LocalStorageData.Instance.HistoryTeam = history_dict; } } public LoadStatus(): void { console.log("LoadStatus ======= "); try { let members: string[] = this.TeamMemberList.map(m => m.Name); let member_list: string[] = LocalStorageData.Instance.Member; let avatar_list: number[] = LocalStorageData.Instance.Avatar; for (let i: number = 0; i < member_list.length; i++) { let member: string = member_list[i]; if (!members.includes(member)) { if (member !== this.GetDefaultMemberName()) { this.TeamMemberList.push(new MemberData(member, avatar_list[i])); } } else { this.TeamMemberList.find((m) => m.Name === member).AvatarId = avatar_list[i]; } } this.CurMemberList.Clear(); for (const members of this._m_toggleList) { members.isChecked = false; } this.CurMemberList = member_list.Copy(); this._initUI(); for (let i: number = 0; i < member_list.length; i++) { let member: string = member_list[i]; let index: number = members.indexOf(member); if (index !== -1) { this._m_toggleList[index].isChecked = true; this._onChangeSelMember(this._m_toggleList[index]); } else { // 那個 } } this._updateTeamShow(member_list); this._loadScoreResult(); // TODO voicePanel // voicePanel.SetProps(MiniJSON.Json.Deserialize(PlayerPrefs.GetString("voice", "null")) as Dictionary); this._updateGameResult(); } catch (err: any) { console.log(err); } } private _loadScoreResult(): void { let self: this = this; this.ScoreBoard.isSingleMode = LocalStorageData.Instance.IsSingleMode === 1; let selected_list: string[] = LocalStorageData.Instance.Selected; if (selected_list.length > 0) { // TODO ScoreBoard // this.ScoreBoard.ResetScore(); // this.ScoreBoard.SetPlayerList(selected_list); let firstTeam: number = LocalStorageData.Instance.FirstTeam; this.ScoreBoard.firstTeam = firstTeam; // TODO ScoreBoard // if (firstTeam !== -1) { // let score_list: number[] = LocalStorageData.Instance.Score; // this.ScoreBoard.SetScoreWinList(score_list); // } } this._m_results.clear(); let result_list: Map = LocalStorageData.Instance.Results; if (result_list.size > 0) { result_list.forEach((item: Object, key: string) => { let val: Object = item; let result: ScoreResult = new ScoreResult(+item["win"], +item["total"]); self._m_results.set(key, result); this.Config.GetMemberDataByName(key).Score = result; }); } } private _updateGameResult(): void { let self: this = this; this._m_toggleList.forEach((member: cc.Toggle, index: number, array: cc.Toggle[]) => { if (self._m_results.has(member.node.Find("Name").getComponent(cc.Label).string)) { let result: ScoreResult = self._m_results.get(member.node.Find("Name").getComponent(cc.Label).string); member.node.Find("Score").getComponent(cc.Label).string = "" + result.Total; } else { member.node.Find("Score").getComponent(cc.Label).string = ""; } }); } public OnClickClearAllGameResult(): void { this._m_results.clear(); this._m_history.Clear(); this._updateGameResult(); // 清除計分後 寫入紀錄 this.SaveStatus(); } public OnClickBtn_History(): void { CoroutineV2.Single(this.HistoryPanel.Show()).Start(); } public OnClickBtn_Sound(): void { CoroutineV2.Single(this.VoicePanel.Show()).Start(); } //#endregion public Log(a: any, b: any): void { console.log(b); } }