UGUI实践
UGUI实践项目
目录
- 项目示意图
- 项目流程图
- 项目类图
- BasePanel面板基类
- UIManager面板管理器
- LoginBKPanel背景面板
- TipPanel提示面板
- LoginPanel登录面板
- RegisterPanel注册面板
- ServerPanel服务器面板
- ServerLeftItem选服面板左侧区间按钮
- ServerRightItem选服面板右侧服务器按钮
- ChooseServerPanel选服面板
- LoginMgr登录管理器
- LoginData登录信息
- RegisterData注册信息
- ServerInfo服务器信息
- ServerInfo.json服务器配置文件
项目示意图:
提示面板:

登录面板:

注册面板:

服务器面板:

选服面板:
项目流程图:
返回目录

项目类图:
返回目录


面板预制体和面板代码
BasePanel面板基类
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
public abstract class BasePanel : MonoBehaviour
{
//整体控制淡入淡出的画布组组件
private CanvasGroup canvasGroup;
private bool isShow;
//淡入淡出的速度
private float alphaSpeed = 10f;
private UnityAction hideCallBack;
protected virtual void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = this.AddComponent<CanvasGroup>();
}
}
protected virtual void Start()
{
Init();
}
/// <summary>
/// 主要用于初始化按钮监听 初始化
/// </summary>
protected abstract void Init();
protected virtual void Update()
{
//淡入
if (isShow && canvasGroup.alpha != 1)
{
canvasGroup.alpha += alphaSpeed * Time.deltaTime;
if (canvasGroup.alpha > 1)
{
canvasGroup.alpha = 1;
}
}
//淡出
else if (!isShow)
{
canvasGroup.alpha -= alphaSpeed * Time.deltaTime;
if (canvasGroup.alpha <= 0)
{
canvasGroup.alpha = 0;
hideCallBack?.Invoke();
}
}
}
/// <summary>
/// 显示自己
/// </summary>
public virtual void ShowMe()
{
isShow = true;
canvasGroup.alpha = 0;
}
/// <summary>
/// 隐藏自己
/// </summary>
public virtual void HideMe(UnityAction callback)
{
isShow = false;
canvasGroup.alpha = 1;
hideCallBack = callback;
}
}
UIManager面板管理器
using System;
using System.Collections.Generic;
using UnityEngine;
public class UIManager
{
private static UIManager instance = new UIManager();
public static UIManager Instance => instance;
//存储面板的容器
public Dictionary<Type, BasePanel> panelDic = new Dictionary<Type, BasePanel>();
//应该在一开始 得到Canvas对象
private Transform canvasTrans;
private UIManager()
{
//得到场景上创建好的Canvas对象
canvasTrans = GameObject.Find("Canvas").transform;
//让Canvas对象过场景不移除
//我们都是通过 动态创建和动态删除 来显示 隐藏面板的 所以不删除它 影响不大
GameObject.DontDestroyOnLoad(canvasTrans.gameObject);
}
/// <summary>
/// 获取面板
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="panel"></param>
public T GetPanel<T>() where T : BasePanel
{
if (panelDic.ContainsKey(typeof(T)))
{
return (T)panelDic[typeof(T)];
}
return null;
}
/// <summary>
/// 显示面板
/// </summary>
/// <typeparam name="T"></typeparam>
public T ShowPanel<T>() where T : BasePanel
{
T panel = GetPanel<T>();
//是否已经显示了该面板 如果有 不用创建 直接返回给外部使用
if (panel != null)
{
return panel;
}
//根据得到的 类名 就是面板名 直接创建
GameObject obj = GameObject.Instantiate(Resources.Load<GameObject>("UI/" + typeof(T).Name));
panel = obj.GetComponent<T>();
obj.transform.SetParent(canvasTrans, false);
panelDic.Add(typeof(T), panel);
//调用显示自己的逻辑
panel.ShowMe();
return panel;
}
/// <summary>
/// 隐藏面板
/// </summary>
/// <typeparam name="T">要隐藏的面板类</typeparam>
/// <param name="isFade">淡出:true,直接隐藏:false</param>
public void HidePanel<T>(bool isFade = true) where T : BasePanel
{
//得到根据泛型类型 得到 面板名字
T panel = GetPanel<T>();
//判断字典有没有要隐藏的面板
if (panel!=null)
{
if (isFade)
{
panel.HideMe(() =>
{
//面板淡出成功后删除面板
GameObject.Destroy(panel.gameObject);
//删除面板后 从字典中移除
panelDic.Remove(typeof(T));
});
}
else
{
//直接删除面板
GameObject.Destroy(panel.gameObject);
//从字典移除
panelDic.Remove(typeof(T));
}
}
}
}
LoginBKPanel背景面板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LoginBKPanel : BasePanel
{
protected override void Init()
{
}
}
TipPanel提示面板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TipPanel : BasePanel
{
public Button btnSure;
public Text tipInfo;
protected override void Init()
{
btnSure.onClick.AddListener(() =>
{
UIManager.Instance.HidePanel<TipPanel>();
});
}
/// <summary>
/// 提示内容供外部使用
/// </summary>
/// <param name="info">提示内容</param>
public void ChangeInfo(string info)
{
tipInfo.text = info;
}
}
LoginPanel登录面板
using System;
using UnityEditor.Build.Content;
using UnityEngine.UI;
using UnityEngine;
public class LoginPanel : BasePanel
{
public InputField inputUN;
public InputField inputPW;
public Toggle togPW;
public Toggle togAuto;
public Button btnRe;
public Button btnSure;
protected override void Init()
{
//点击注册
btnRe.onClick.AddListener(() =>
{
//显示注册面板
UIManager.Instance.ShowPanel<RegisterPanel>();
//隐藏自己
UIManager.Instance.HidePanel<LoginPanel>();
});
//点击登录
btnSure.onClick.AddListener(() =>
{
//判断输入的账号密码是否合理
if (inputUN.text.Length <= 6 || inputPW.text.Length <= 6)
{
//显示提示面板及内容
TipPanel panel = UIManager.Instance.ShowPanel<TipPanel>();
panel.ChangeInfo("账号和密码必须大于6位");
return;
}
//点击登录过后 验证用户名密码是否正确
if (LoginMgr.Instance.CheckInfo(inputUN.text, inputPW.text))
{
//正确
//保存登录数据
LoginMgr.Instance.LoginData.userName = inputUN.text;
LoginMgr.Instance.LoginData.passWord = inputPW.text;
LoginMgr.Instance.LoginData.rememberPW = togPW.isOn;
LoginMgr.Instance.LoginData.autoLogin = togAuto.isOn;
LoginMgr.Instance.SaveLoginData();
Debug.Log(togPW.isOn);
Debug.Log(togAuto.isOn);
Debug.Log("111");
//根据服务器信息 判断显示哪个面板
if (LoginMgr.Instance.LoginData.frontServerID <= 0)
{
//如果没有选择过服务器 id小于等于0时 就应该直接打开选服面板
UIManager.Instance.ShowPanel<ChooseServerPanel>();
}
else
{
//打开服务器面板
ServerPanel serverPanel = UIManager.Instance.ShowPanel<ServerPanel>();
}
//隐藏自己
UIManager.Instance.HidePanel<LoginPanel>();
}
else
{
//错误
//显示提示面板及内容
TipPanel tipPanel = UIManager.Instance.ShowPanel<TipPanel>();
tipPanel.ChangeInfo("账号或密码错误");
}
});
//点击记住密码
togPW.onValueChanged.AddListener((isOn) =>
{
//当取消选中记住密码 自动登录也应该取消
if (!isOn)
{
togAuto.isOn = false;
}
});
//点击自动登录
togAuto.onValueChanged.AddListener((isOn) =>
{
//当我们选中自动登录 如果记住密码没有被选中 应该自动选中
if (isOn)
{
togPW.isOn = true;
}
});
}
public override void ShowMe()
{
base.ShowMe();
//显示自己时 根据数据 更新面板上的内容
//得到数据
LoginData loginData = LoginMgr.Instance.LoginData;
//初始化面板显示
togPW.isOn = loginData.rememberPW;
togAuto.isOn = loginData.autoLogin;
//更新账号 密码
inputUN.text = loginData.userName;
//根据上一次是否勾选记住密码
if (togPW.isOn)
{
inputPW.text = loginData.passWord;
}
//如果是自动登录 做什么
if (togAuto.isOn)
{
//自动去验证账号密码相关
//验证用户名密码是否正确
if (LoginMgr.Instance.CheckInfo(inputUN.text, inputPW.text))
{
//根据服务器信息 判断显示哪个面板
if (LoginMgr.Instance.LoginData.frontServerID <= 0)
{
//如果没有选择过服务器 id小于等于0时 就应该直接打开选服面板
UIManager.Instance.ShowPanel<ChooseServerPanel>();
}
else
{
//打开服务器面板
ServerPanel serverPanel = UIManager.Instance.ShowPanel<ServerPanel>();
}
//隐藏自己
UIManager.Instance.HidePanel<LoginPanel>(false);
}
else
{
TipPanel tipPanel = UIManager.Instance.ShowPanel<TipPanel>();
tipPanel.ChangeInfo("账号或密码错误");
}
}
}
public void SetInfo(string userName, string passWord)
{
inputUN.text = userName;
inputPW.text = passWord;
}
}
RegisterPanel注册面板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RegisterPanel : BasePanel
{
public InputField inputUN;
public InputField inputPW;
public Button btnCancel;
public Button btnSure;
protected override void Init()
{
//点击取消按钮
btnCancel.onClick.AddListener(() =>
{
//显示登录面板
UIManager.Instance.ShowPanel<LoginPanel>();
//隐藏自己
UIManager.Instance.HidePanel<RegisterPanel>();
});
//点击确定按钮
btnSure.onClick.AddListener(() =>
{
//判断输入的账号密码是否合理
if (inputUN.text.Length <= 6|| inputPW.text.Length <= 6)
{
//显示提示面板及内容
TipPanel panel = UIManager.Instance.ShowPanel<TipPanel>();
panel.ChangeInfo("账号和密码必须大于6位");
return;
}
//注册账号密码
if (LoginMgr.Instance.RegisterUser(inputUN.text, inputPW.text))
{
//注册成功
//清空登录信息 用于 新注册账号的 数据重置 不然会残留上一个账号的相关数据
LoginMgr.Instance.ClearLoginData();
//显示登录面板
LoginPanel loginPanel = UIManager.Instance.ShowPanel<LoginPanel>();
//保留账号密码
loginPanel.SetInfo(inputUN.text, inputPW.text);
//显示提示面板及内容
TipPanel tipPanel = UIManager.Instance.ShowPanel<TipPanel>();
tipPanel.ChangeInfo("注册成功");
//隐藏自己
UIManager.Instance.HidePanel<RegisterPanel>();
}
//存在:
else
{
//注册失败
//显示提示面板及内容
TipPanel tipPanel = UIManager.Instance.ShowPanel<TipPanel>();
tipPanel.ChangeInfo("该用户名已存在");
//方便别人输入
inputUN.text = "";
inputPW.text = "";
}
});
}
}
ServerPanel服务器面板
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ServerPanel : BasePanel
{
public Button btnChange;
public Button btnStart;
public Button btnBack;
public Text txtName;
protected override void Init()
{
btnChange.onClick.AddListener(() =>
{
//打开选服面板
UIManager.Instance.ShowPanel<ChooseServerPanel>();
//隐藏自己
UIManager.Instance.HidePanel<ServerPanel>();
});
btnStart.onClick.AddListener(() =>
{
//进入游戏场景
//保存选中的服务器信息到本地
LoginMgr.Instance.SaveLoginData();
//由于过场景 Canvas对象不会被移除 所以 下面的面板也应该隐藏
//隐藏自己
UIManager.Instance.HidePanel<ServerPanel>();
//隐藏背景面板
UIManager.Instance.HidePanel<LoginBKPanel>();
//切场景
SceneManager.LoadScene("GameScene");
});
btnBack.onClick.AddListener(() =>
{
//避免自动登录时 返回登录界面出问题
if (LoginMgr.Instance.LoginData.autoLogin)
{
LoginMgr.Instance.LoginData.autoLogin = false;
}
//返回登录面板
UIManager.Instance.ShowPanel<LoginPanel>();
//隐藏自己
UIManager.Instance.HidePanel<ServerPanel>();
});
}
public override void ShowMe()
{
base.ShowMe();
//刷新内容
//之后会根据记录的服务器ID更新内容
int id = LoginMgr.Instance.LoginData.frontServerID;
if (id <= 0)
{
txtName.text = "无选择";
}
else
{
ServerInfo info = LoginMgr.Instance.ServerData[id - 1];
txtName.text = info.id + "区 " + info.name;
}
}
}
ServerLeftItem选服面板左侧区间按钮
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ServerLeftItem : MonoBehaviour
{
//按钮自己
public Button btnSelf;
//显示区间内容
public Text txtInfo;
//区间范围
private int beginIndex;
private int endIndex;
// Start is called before the first frame update
void Start()
{
btnSelf.onClick.AddListener(() =>
{
//通知选服面板 改变右侧区间内容
ChooseServerPanel chooseServerPanel = UIManager.Instance.GetPanel<ChooseServerPanel>();
chooseServerPanel.UpdatePanel(beginIndex, endIndex);
});
}
public void InitInfo(int beginIndex,int endIndex)
{
//记录当前按钮的区间值
this.beginIndex = beginIndex;
this.endIndex = endIndex;
//把区间显示的内容更新
txtInfo.text = beginIndex + " - " + endIndex + "区";
}
}
ServerRightItem选服面板右侧服务器按钮
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
public class ServerRightItem : MonoBehaviour
{
//按钮自己
public Button btnSelf;
//是否是新服
public Image imgNew;
//服务区状态
public Image imgState;
//名字
public Text txtFront;
//当前按钮 代表哪个服务器 之后 会使用其中的数据
public ServerInfo nowServerInfo;
// Start is called before the first frame update
void Start()
{
btnSelf.onClick.AddListener(() =>
{
//保存选中的服务区到文件中
LoginMgr.Instance.LoginData.frontServerID = nowServerInfo.id;
//打开服务器面板
ServerPanel serverPanel = UIManager.Instance.ShowPanel<ServerPanel>();
//隐藏选服面板
UIManager.Instance.HidePanel<ChooseServerPanel>();
});
}
/// <summary>
/// 初始化方法 用于 更新按钮显示相关
/// </summary>
/// <param name="serverInfo"></param>
public void InitInfo(ServerInfo info)
{
//记录下数据
nowServerInfo = info;
//更新按钮上的信息
this.txtFront.text = info.id + "区 " + info.name;
//根据状态 读取图集
imgState.gameObject.SetActive(true);
SpriteAtlas spriteAtlas = Resources.Load<SpriteAtlas>("Login");
switch (info.state)
{
case 0:
this.imgState.gameObject.SetActive(false);
break;
case 1://流畅
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_liuchang_01");
break;
case 2://繁忙
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_fanmang_01");
break;
case 3://火爆
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_huobao_01");
break;
case 4://维护
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_weihu_01");
break;
}
//是否是新服
imgNew.gameObject.SetActive(info.isNew);
}
}
ChooseServerPanel选服面板
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
public class ChooseServerPanel : BasePanel
{
//左右滚动视图
public ScrollRect svLeft;
public ScrollRect svRight;
//上一次服务器登录信息
public Text txtFront;
public Image imgState;
//当前选择的区间范围
public Text txtRange;
//用于存储右侧按钮们
private List<GameObject> itemList = new List<GameObject>();
protected override void Init()
{
//获取到服务器列表的数据
List<ServerInfo> infoList = LoginMgr.Instance.ServerData;
//动态创建左侧区间按钮
//得到一共要循环创建多少个区间按钮
//向上取整 创建n个按钮
int num = Mathf.CeilToInt(infoList.Count/5);
for (int i = 0; i < num; i++)
{
//动态创建预设体对象
GameObject item = Instantiate(Resources.Load<GameObject>("UI/ServerLeftItem"));
item.transform.SetParent(svLeft.content, false);
//初始化
ServerLeftItem serverLeft = item.GetComponent<ServerLeftItem>();
int beginIndex = i * 5 + 1;
int endIndex = (i + 1) * 5;
//判断最大是不是超过了服务器总数
if (endIndex > infoList.Count)
{
endIndex = infoList.Count;
}
//初始化区间按钮
serverLeft.InitInfo(beginIndex, endIndex);
}
}
public override void ShowMe()
{
base.ShowMe();
//显示自己时
//应该初始化 上一次选择的服务器
int id = LoginMgr.Instance.LoginData.frontServerID;
if ( id<=0)
{
txtFront.text = " 无";
imgState.gameObject.SetActive(false);
}
else
{
//根据上一次登录的 服务器ID 获取到服务器信息 用于界面数据更新
ServerInfo info = LoginMgr.Instance.ServerData[id - 1];
//拼接显示上一次登录的服务器名字
txtFront.text = info.id + "区 " + info.name;
imgState.gameObject.SetActive(true);
SpriteAtlas spriteAtlas = Resources.Load<SpriteAtlas>("Login");
switch (info.state)
{
case 0:
this.imgState.gameObject.SetActive(false);
break;
case 1://流畅
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_liuchang_01");
break;
case 2://繁忙
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_fanmang_01");
break;
case 3://火爆
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_huobao_01");
break;
case 4://维护
this.imgState.sprite = spriteAtlas.GetSprite("ui_DL_weihu_01");
break;
}
}
//第一次进入选服面板时 应该显示右侧1-5按钮
//三目运算判断5是否大于服务器数量,如果是就使用服务器数量,如果不是 使用5
UpdatePanel(1, 5 > LoginMgr.Instance.ServerData.Count ? LoginMgr.Instance.ServerData.Count : 5);
}
/// <summary>
/// 提供给其它地方 用于更新 当前选择区间的右侧按钮
/// </summary>
/// <param name="beginIndex"></param>
/// <param name="endInxdex"></param>
public void UpdatePanel(int beginIndex, int endIndex)
{
//更新服务器区间显示
txtRange.text = "服务器 " + beginIndex + "—" + endIndex;
//删除之前的单个按钮
for (int i = 0; i < itemList.Count; i++)
{
//删除之前的对象
Destroy(itemList[i]);
}
itemList.Clear();
//动态创建右侧按钮
for (int i = beginIndex; i <= endIndex; i++)
{
//获取当前服务区数据
ServerInfo info = LoginMgr.Instance.ServerData[i - 1];
//动态创建预设体对象
GameObject serverItem = Instantiate(Resources.Load<GameObject>("UI/ServerRightItem"));
serverItem.transform.SetParent(svRight.content,false);
//根据信息 更新按钮数据
ServerRightItem serverRight = serverItem.GetComponent<ServerRightItem>();
serverRight.InitInfo(info);
//创建成功后 将它记录到列表
itemList.Add(serverItem);
}
}
}
LoginMgr登录管理器
using System.Collections.Generic;
public class LoginMgr
{
private static LoginMgr instance = new LoginMgr();
public static LoginMgr Instance => instance;
//静态变量 不要在外面去new
private LoginData loginData;
//公共属性 方便外面获取
public LoginData LoginData => loginData;
//注册数据
private RegisterData registerData;
public RegisterData RegissterData => registerData;
//服务器数据
private List<ServerInfo> serverData;
public List<ServerInfo> ServerData => serverData;
private LoginMgr()
{
//通过json管理器获取对应数据
loginData = JsonDataMgr.Instance.LoadData<LoginData>("LoginData");
//读取注册数据
registerData = JsonDataMgr.Instance.LoadData<RegisterData>("RegisterData");
//读取服务器数据
serverData = JsonDataMgr.Instance.LoadData<List<ServerInfo>>("ServerInfo");
}
#region 登录数据
//存储登录相关数据
//账号 密码 保存密码 自动登录 与 上次服务器信息是分开记录的 不提供一个接口同时存储这些内容 请使用LoginData存储
public void SaveLoginData()
{
JsonDataMgr.Instance.SaveData(loginData, "LoginData");
}
//主要用于注册成功后 清理登录数据
public void ClearLoginData()
{
loginData.rememberPW = false;
loginData.autoLogin = false;
loginData.frontServerID = 0;
}
#endregion
#region 注册数据
//存储注册数据
public void SavaRegisterData()
{
JsonDataMgr.Instance.SaveData(registerData, "RegisterData");
}
//注册方法
public bool RegisterUser(string userName,string passWord)
{
// 判断是否存在用户
if (registerData.registerInfo.ContainsKey(userName))
{
return false;
}
//如果不存在 证明可以注册
//存储新用户名和密码
registerData.registerInfo.Add(userName, passWord);
//本地存储
SavaRegisterData();
return true;
}
//验证用户名密码是否合法
public bool CheckInfo(string userName,string passWord)
{
//判断是否有该用户
if (registerData.registerInfo.ContainsKey(userName))
{
//密码相同 证明 登录成功
if (registerData.registerInfo[userName] == passWord)
{
return true;
}
}
// 用户名和密码不合法
return false;
}
#endregion
}
LoginData登录信息
/// <summary>
/// 登录界面可能需要记住的玩家操作相关数据
/// </summary>
public class LoginData
{
//用户名
public string userName;
//密码
public string passWord;
//是否记住密码
public bool rememberPW;
//是否自动登录
public bool autoLogin;
//服务器相关 0代表没有选择过服务器
public int frontServerID = 0;
}
RegisterData注册信息
using System.Collections.Generic;
public class RegisterData
{
public Dictionary<string,string> registerInfo = new Dictionary<string,string>();
}
ServerInfo服务器信息
using System.Collections.Generic;
public class ServerInfo
{
//区号 ID
public int id;
//服务器名
public string name;
//0-4种状态
public int state;
//是否为new
public bool isNew;
}
ServerInfo.json服务器配置文件
返回目录
(可由Excel转Json)
[
{"id":1,"name":"天下无双1","state":0,"isNew":false},
{"id":2,"name":"天下无双2","state":1,"isNew":false},
{"id":3,"name":"天下无双3","state":2,"isNew":false},
{"id":4,"name":"天下无双4","state":3,"isNew":false},
{"id":5,"name":"天下无双5","state":4,"isNew":false},
{"id":6,"name":"天下无双6","state":0,"isNew":false},
{"id":7,"name":"天下无双7","state":1,"isNew":false},
{"id":8,"name":"天下无双8","state":2,"isNew":false},
{"id":9,"name":"天下无双9","state":3,"isNew":false},
{"id":10,"name":"天下无双10","state":4,"isNew":false},
{"id":11,"name":"天下无双11","state":0,"isNew":false},
{"id":12,"name":"天下无双12","state":1,"isNew":false},
{"id":13,"name":"天下无双13","state":2,"isNew":false},
{"id":14,"name":"天下无双14","state":3,"isNew":false},
{"id":15,"name":"天下无双15","state":4,"isNew":false},
{"id":16,"name":"天下无双16","state":0,"isNew":false},
{"id":17,"name":"天下无双17","state":1,"isNew":false},
{"id":18,"name":"天下无双18","state":2,"isNew":false},
{"id":19,"name":"天下无双19","state":3,"isNew":false},
{"id":20,"name":"天下无双20","state":4,"isNew":false},
{"id":21,"name":"天下无双21","state":0,"isNew":false},
{"id":22,"name":"天下无双22","state":1,"isNew":false},
{"id":23,"name":"天下无双23","state":2,"isNew":false},
{"id":24,"name":"天下无双24","state":3,"isNew":true},
{"id":25,"name":"天下无双25","state":4,"isNew":true}
]










浙公网安备 33010602011771号