UGUI架构的应用案例——选择英雄界面
效果展示
描述
通过右边的英雄选择列表,将对应的英雄置于镜头前面,并更新英雄介绍。
步骤
- 每个英雄有两个模型,一个位于尽头远点,默认显示并播放Idle动画,一个位于镜头前方,默认隐藏显示时播放hit动画
- 选择英雄界面为三个单选按钮,每个单选按钮与两个英雄模型关联,在点击时间中进行处理,对应模型的隐藏和显示
- UIInfo初始化时调用PhotoManager从后台取英雄介绍数据并缓存
- UIInfo注册UISenceWidget的PointerClick事件,每当按钮进行点击更新对应英雄的介绍面板
目录结构
组件情况
UI_CharacterSelection->UIInfo
UIScene_Bottom->UIScene
UIScene_SelectHero->UIScene
UIScene_HeroInfo->UIScene
togHero1->UISceneWidget
togHero2->UISceneWidget
togHero3->UISceneWidget
实现
1.创建英雄近点和远点(目前只有两个英雄),并挂上对应角色模型
2.单选按钮与角色模型对应,并实现按钮选中后对应模型的显示和隐藏
[RequireComponent(typeof(Toggle))]
public class UIToggleObject : MonoBehaviour {
public GameObject Show;
public GameObject Hide;
void Awake()
{
GetComponent<Toggle>().onValueChanged.AddListener(OnSelectChanged);
}
private void OnSelectChanged(bool isChecked)
{
Show.SetActive(isChecked);
Hide.SetActive(!isChecked);
}
}
3.英雄信息的读取和缓存
表结构
两个字段一个ID一个描述
服务端修改
ALI.ARPG.Operations
构造Entity
[Serializable]
public class HeroEntity : IEntityIntKey
{
public virtual int ID { get; set; }
public virtual string Desc { get; set; }
}
由于后面代码需要,对服务端架构做了调整,对Entity做了接口约束,这里把IntKey单独抽取出来是为了扩展以后主键不是int类型的实体,如GUID
public interface IEntity
{
}
public interface IEntityIntKey : IEntity
{
int ID { get; set; }
}
增加一个OperationCode
public enum OperationCode : byte
{
Register,
Login,
GetHeroInfo
}
ALI.ARPG.Data
设置Entity与数据库的映射及构造Hero对应的Repository
public class HeroMap: ClassMap<HeroEntity>
{
public HeroMap()
{
Table("heroinfo");
Id(x => x.ID).Column("id");
Map(x => x.Desc).Column("Desc");
}
}
public class HeroRepository : Repository<HeroEntity>
{
public HeroRepository(ISession session) : base(session)
{
}
}
ALI.ARPG.Domain
构造ICommand和ICommandHandler,由于获取数据不需要验证,所以不需要ICommandValidate
public class HeroInfoCommand : ICommand
{
public int ID;
}
由于是获取所有数据,是不需要参数的,但是因为需要通过反射查找对应的Handler所以这里还是需要定义ICommand
public class GetAllHeroInfoHandler : ICommandHandler<HeroInfoCommand>
{
private readonly HeroRepository heroRepository;
private UnitOfWork unitOfWork;
public GetAllHeroInfoHandler()
{
unitOfWork = new UnitOfWork();
heroRepository = new HeroRepository(unitOfWork.Session);
}
public ICommandResult Excute(HeroInfoCommand command)
{
IEnumerable<HeroEntity> heroinfos = heroRepository.All();
unitOfWork.Commit();
return new CommandResult<HeroEntity>(true, heroinfos);
}
}
ALI.ARPG.Server
设置Entity和Command的转换
public class ViewModelToDomainMappingProfile : Profile
{
public ViewModelToDomainMappingProfile()
{
this.CreateMap<AccountEntity, UserRegisterCommand>();
this.CreateMap<AccountEntity, UserLoginCommand>();
this.CreateMap<HeroEntity, HeroInfoCommand>();
}
}
public class DomainToViewModelMappingProfile : Profile
{
public DomainToViewModelMappingProfile()
{
this.CreateMap<UserRegisterCommand, AccountEntity>();
this.CreateMap<UserLoginCommand, AccountEntity>();
this.CreateMap<HeroInfoCommand, HeroEntity>();
}
}
AliPeer中增加对OprationCode.GetHeroInfo的响应
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
if (AliPeer.log.IsDebugEnabled)
{
AliPeer.log.DebugFormat("OnOperationRequest. Code={0}", operationRequest.OperationCode);
}
switch (operationRequest.OperationCode)
{
case (byte)OperationCode.Register:
HandleRegisterOperation(operationRequest, sendParameters);
break;
case (byte)OperationCode.Login:
HandleLoginOperation(operationRequest, sendParameters);
break;
case (byte)OperationCode.GetHeroInfo:
HandleGetHeroinfoOperation(operationRequest, sendParameters);
break;
default:
break;
}
}
protected virtual void HandleGetHeroinfoOperation(OperationRequest operationRequest, SendParameters sendParameters)
{
try
{
OperationResponse response = new OperationResponse((byte)OperationCode.GetHeroInfo);
//因为没有ValidateHandler所以直接执行CommandHandler
CommandResult<HeroEntity> result = commandBus.Submit(new HeroInfoCommand()) as CommandResult<HeroEntity>;
if (result.Success)
{
response.ReturnCode = (short)ReturnCode.Sucess;
Dictionary<byte, object> dict = new Dictionary<byte, object>();
string strJson = JsonMapper.ToJson(result.Result);
dict.Add((byte)ReturnCode.Sucess, strJson);
response.Parameters = dict;
}
else
{
response.ReturnCode = (short)ReturnCode.Faild;
}
SendOperationResponse(response, sendParameters);
}
catch (Exception ex)
{
if (AliPeer.log.IsDebugEnabled)
{
AliPeer.log.DebugFormat("Error: {0}", ex.Message);
}
}
}
客户端
PhotonManager
增加一个连接上服务器的事件
public event Action OnConnected;
public void OnStatusChanged(StatusCode statusCode)
{
switch (statusCode)
{
case StatusCode.Connect:
Debug.Log("服务器连接成功");
IsConnected = true;
if(OnConnected != null)
{
OnConnected();
}
break;
case StatusCode.Disconnect:
case StatusCode.DisconnectByServer:
case StatusCode.DisconnectByServerUserLimit:
Debug.Log("服务器已断开连接, StarusCode:" + statusCode);
IsConnected = false;
break;
default:
break;
}
UIHeroInfo
监听服务器连接的事件,连接上就向服务器发起获取英雄列表请求
public class UIHeroInfo : UIScene {
private Text m_LblDesc;
protected override void Start()
{
base.Start();
InitWidget();
//监听服务器连接事件
PhotonManager.Instance.OnConnected += PhotonServerOnConnected;
}
void InitWidget()
{
m_LblDesc = UIHelper.FindChild<Text>(transform, "lblDesc");
}
private void PhotonServerOnConnected()
{
//获取英雄信息列表
GetAllHeroInfo();
}
public void GetAllHeroInfo()
{
if (PhotonManager.Instance.IsConnected)
{
Dictionary<byte, object> parameter = new Dictionary<byte, object>();
parameter.Add((byte)OperationCode.GetHeroInfo, null);
//向服务端发起请求
PhotonManager.Instance.Peer.OpCustom((byte)OperationCode.GetHeroInfo, parameter, true);
}
}
}
PhotonManager
增加服务器响应时间,获取HeroList,并将其缓存
public void OnOperationResponse(OperationResponse operationResponse)
{
switch ((OperationCode)operationResponse.OperationCode)
{
case OperationCode.Login:
HandleLoginResponse(operationResponse);
break;
case OperationCode.Register:
HandleRegisterResponse(operationResponse);
break;
case OperationCode.GetHeroInfo:
HandleHeroInfoResponse(operationResponse);
break;
}
}
private void HandleHeroInfoResponse(OperationResponse operationResponse)
{
switch ((ReturnCode)operationResponse.ReturnCode)
{
case ReturnCode.Sucess:
object json;
operationResponse.Parameters.TryGetValue((byte)ReturnCode.Sucess, out json);
if (json != null)
{
JsonData data = JsonMapper.ToObject(json.ToString());
AddHeroDataInCache(data);
}
break;
}
}
//反序列化Json对象,并加入缓存
private void AddHeroDataInCache(JsonData data)
{
for (int i = 0; i < data.Count; i++)
{
HeroEntity entiy = new HeroEntity();
entiy.ID = (int)data[i]["ID"];
entiy.Desc = data[i]["Desc"].ToString();
PhotonDataCache.AddOrUpdateDataCache(PhotonCacheType.HeroList, entiy);
}
}
PhotonDataCache
增加缓存类
public enum PhotonCacheType
{
HeroList
}
public static class PhotonDataCache
{
private static readonly Dictionary<PhotonCacheType, Dictionary<int, IEntity>> DataCache = new Dictionary<PhotonCacheType, Dictionary<int, IEntity>>();
public static void AddOrUpdateDataCache(PhotonCacheType cacheType, int key, IEntity value)
{
Dictionary<int, IEntity> dict;
if (!DataCache.ContainsKey(cacheType))
{
dict = new Dictionary<int, IEntity>();
DataCache.Add(cacheType, dict);
}
dict = DataCache.First(x => x.Key == cacheType).Value;
if (!dict.ContainsKey(key))
{
dict.Add(key, value);
}
else
{
dict[key] = value;
}
}
public static void AddOrUpdateDataCache(PhotonCacheType cacheType, IEntityIntKey entity)
{
AddOrUpdateDataCache(cacheType, entity.ID, entity);
}
public static IEntity GetValue(PhotonCacheType cacheType, int key)
{
if (DataCache.ContainsKey(cacheType))
{
Dictionary<int, IEntity> data = DataCache.First(x => x.Key == cacheType).Value;
if(data !=null)
{
return data.First(x => x.Key == key).Value;
}
}
return null;
}
public static T GetValue<T>(PhotonCacheType cacheType, int key) where T : IEntity
{
IEntity entity = GetValue(cacheType, key);
if (entity != null)
return (T)entity;
return default(T);
}
}
以上数据已经被放入进缓存,只需要在界面上进行绑定
UISelectHero
初始化,并监听英雄选择按钮点击事件
public class UISelectHero : UIScene {
private UIHeroInfo m_HeroInfo;
protected override void Start()
{
base.Start();
InitWidget();
}
private void InitWidget()
{
m_HeroInfo = UIManager.Instance.GetUI<UIHeroInfo>(UIName.UIHeroInfo);
for (int i = 0; i < this.GetWidgetCount(); i++)
{
UISceneWidget m_TogButton = GetWidget("togHero" + (i + 1));
if(m_TogButton != null)
{
m_TogButton.PointerClick += TogButtonOnPointerClick;
}
}
}
private void TogButtonOnPointerClick(UnityEngine.EventSystems.PointerEventData obj)
{
string heroID = obj.selectedObject.name;
heroID = heroID.Substring(heroID.Length - 1);
m_HeroInfo.SetHeroInfo(heroID);
}
}
UIHeroInfo
更新介绍信息
public void SetHeroInfo(string heroId)
{
int id;
if(Int32.TryParse(heroId, out id))
{
HeroEntity heroInfo = PhotonDataCache.GetValue<HeroEntity>(PhotonCacheType.HeroList, id);
m_LblDesc.text = heroInfo.Desc;
}
}
搞定