MMO进入主城--角色信息显示

 更正!这里插入:前面的创建角色之后,点击开启冒险按钮返回角色选择面板,角色选择列表不显示的问题

原因:服务器创建角色后,没有把角色列表返回给客户端

>>首先我们点击开启冒险按钮创建角色:

 此时:按钮挂了UICharacterSelect脚本中的OnClickCreate()方法

OnClickCreate
public void OnClickCreate()
{
    if(string.IsNullOrEmpty(this.charName.text))
    {
        MessageBox.Show("请输入角色名称");
        return;
        //不能把空消息发给服务器
    }
    //启用协议创建角色
    UserService.Instance.SendCharacterCreate(this.charName.text, this.charClass);   
}
 SendCharacterCreate

调用UserService中的SendCharacterCreate;把创建角色请求消息发送给服务端

OnCreateCharacter

服务端中对客服端的请求做出响应的方法是:OnCreateCharacter//在Game Server:UserService的构造方法中已经订阅

服务器打包信息发给客户端时,缺少了打包已有的角色:

//前面创建新角色,放进DBService;

类似于OnLogin方法,把DBService.Instance.Entities.Characters中的对象都遍历一次;

Characters即为所有角色;他是NCharacterInfo类型的;

我们只需要把它遍历一次,赋值并加进message中即可

//add部分是新加的

void OnCreateCharacter(NetConnection<NetSession> sender,UserCreateCharacterRequest request)
{
    Log.InfoFormat("UserCreateCharacterRequest: Name:{0}  Class:{1}", request.Name, request.Class);

    
    //TCharacter是提前建好的一个类,里面有关于Character的所有字段的访问器
    TCharacter character = new TCharacter()
    {//创建新角色要把客户端传进来的信息填充
        Name = request.Name,
        Class = (int)request.Class,//这里加一个强制转换;数据库不允许枚举值
        TID=(int)request.Class,
        //mapID:第一次出现的时候要出现在那张地图;哪个位置
        MapID=1,//主城;某次登录需要用到上一次的位置
        MapPosX=5000,
        MapPosY=4000,
        MapPosZ=820,//这是地图的中心位置;单位是cm

    };
 //这里添加了character=:因为可能对象会发生变化;因此把返回值往里面Add
    character=DBService.Instance.Entities.Characters.Add(character);
    sender.Session.User.Player.Characters.Add(character);
    //对数据库做的任何增删改查的操作之后都要保存
    DBService.Instance.Entities.SaveChanges();

    
    //准备要发送客户端的信息
    NetMessage message = new NetMessage();
    message.Response = new NetMessageResponse();
    message.Response.createChar = new UserCreateCharacterResponse();

    //add
    //得到角色列表
    
    foreach (var c in sender.Session.User.Player.Characters)
    {//从该用户的已经创建的角色中找
        NCharacterInfo info = new NCharacterInfo();
        info.Id = c.ID;
        info.Name = c.Name;
        info.Class = (CharacterClass)c.Class;
        info.Tid = c.TID;
        info.mapId = c.MapID;
        //把数据库当前已经有的填充到协议中发给客户端
        //message.Response.userLogin.Userinfo.Player.Characters.Add(info);//添加角色到响应
        message.Response.createChar.Characters.Add(info);
    }

    //回发消息吧结果告诉用户;创建是否成功
    message.Response.createChar.Result = Result.Success;
    message.Response.createChar.Errormsg = "None";

    //创建一个包换角色列表的数组
    byte[] data = PackageHandler.PackMessage(message);
    sender.SendData(data, 0, data.Length);
}

回到客户端的UserService的OnUserCreateCharacter中的OnCharacterCreate方法

回到UICharacterSelect中的OnCharacterCreate方法

如果角色创建成功,调用InitCharacterSelect(true):创建列表等等。。

(详细请看MMO角色创建与选择:应用通讯协议中的角色列表填充InitCharacterSelect

结果图示:

 主场景的UI制作
角色信息

 修改UIMainCity的分辨率

名字等级信息框

 UIMainCity.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Models;
public class UIMainCity0 : MonoBehaviour
{
    public Text avatarName;
    public Text avatarLevel;
    void Start()
    {//在启动时候刷新
        this.UpdateAvatar();
    }

    void UpdateAvatar()
    {
        //User是单例类,存放用户和角色的各种相关信息//CurrentCharacter存储网络传回来的信息(姓名角色等级..)
        this.avatarName.text = string.Format("{0}[{1}]", User.Instance.CurrentCharacter.Name, User.Instance.CurrentCharacter.Id);
        this.avatarLevel.text = User.Instance.CurrentCharacter.Level.ToString();
    }
   
}

启动后:

角色血条

//创建世界空间的UI

世界空间:在3d场景中是统一的坐标系

建立一个Canvas

与MainPlayerCamera共享同一个Camera

画布缩放器:

用于控制整体缩放和像素密度用户界面画布中的元素。此缩放会影响画布下的所有内容,包括字体大小和图像边框

每单位动态像素数UI 中动态创建的位图(如文本)所使用的每单位像素数量。
每单位参考像素如果精灵具有此“每单位像素数”设置,则精灵中的一个像素将覆盖世界中的一个单位。如果“每单位参考像素数”设置为 1,则精灵中的“每单位像素数”设置将按原样使用。

创建UINameBar

把比例调成UIWorldElementManager1:UINameBar100

UINameBar

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Entities;
public class UINameBar1 : MonoBehaviour
{
    public Text avatarName;

    //信息条要给显示
    public Character character;
    void Start()
    {
        if(character!=null)
        {

        }
    }

    void Update()
    {
        
    }
    void UpdateInfo()
    {//角色的升级,更新
        if(this.character!=null)
        {
            string name = this.character.Name + " Lv." + this.character.Info.Level;
            if(name!=this.avatarName.text)
            {//每一次的赋值会影响性能,回导致UI元素的重绘
                this.avatarName.text = name;
            }
        }

    }
}
UIWorldElement

是UIWorldElementManager世界元素管理器的通用属性

//owner做跟随

//把脚本挂到UINameBar下面

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIWorldElement0 : MonoBehaviour
{
    //用来更新
    public Transform owner;//需要更新的东西属于谁
    //把Owner复制成角色的Transform,让世界元素自动做跟踪
    public float height = 1.5f;
    void Start()
    {
        
    }

    void Update()
    {
        if(owner!=null)
        {
            //UINameBar的位置是角色位置的上方一点
            this.transform.position = owner.position + Vector3.up * height;
        }
    }
}
UIWorldElementManager

维护各种数据,负责数据的增加删除

//把脚本绑到UIWorldMangaer上

单例:频繁用到世界元素动态添加到此管理器中

UIWorldElementManager : MonoSingleton<UIWorldElementManager>

用字典管理所有世界元素信息

隐藏UINameBar

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Entities;
public class UIWorldElementManager : MonoSingleton<UIWorldElementManager>
{
    //取到信息条
    public GameObject nameBarPrefab;
    private Dictionary<Transform, GameObject> elements = new Dictionary<Transform, GameObject>();
    void Start()
    {
        
    }

    void Update()
    {
        
    }
    public void AddCharacterNameBar(Transform owner,Character character)
    {//添加owner
        //实力化nameBarPrefab;管理器下创建的节点的根节点是This.transform
        //当根节点(管理器)被销毁,其所有的子元素都被销毁
        GameObject goNameBar = Instantiate(nameBarPrefab, this.transform);
        //显示在管理器下面的go的名字等信息
        goNameBar.name="NameBar"+character.entityId;
        //取得上面绑定的脚本(血条角色
        goNameBar.GetComponent<UIWorldElement>().owner = owner;
        goNameBar.GetComponent<UINameBar>().character = character;
        goNameBar.SetActive(true);
        //加到管理器;每个人有一个血条,owner是唯一的
        this.elements[owner] = goNameBar;
    }
    public void RemoveCharacterNameBar(Transform owner)
    {//只需要把owner身上的移除掉
        if(this.elements.ContainsKey(owner)) //判断是否已经被删过了
        {
            //销毁游戏对象,包括游戏对象本身,组件,脚本;函数执行是异步的,要在下一帧或指定时间才能销毁
            Destroy(this.elements[owner]);
            //确保当前帧游戏对象不被引用
            this.elements.Remove(owner);
        }
    }
}
角色创建是在GamObjectManager中

 在这里拿到参数:

UIWorldElementManager.Instance.AddCharacterNameBar(go.transform, character);
删除是在EntityController中

所有的角色都挂了此脚本;

void OnDestroy()
{
    if (entity != null)
        Debug.LogFormat("{0} OnDestroy :ID:{1} POS:{2} DIR:{3} SPD:{4} ", this.name, entity.entityId, entity.position, entity.direction, entity.speed);

    //实体移除时把血条也删掉
    if(UIWorldElementManager.Instance!=null)
    {
        UIWorldElementManager.Instance.RemoveCharacterNameBar(this.transform);
    }
}
演示

nameBar方向不对

//关于高度,可以在根据配置表把每个角色血条的高度按照角色高度更新

在UINameBar.cs添加旋转逻辑,名字调用

关于血条对着摄像机

要朝向摄像机的方向;transform.LookAt

//给摄像机设置tag:

UINameBar.cs:Update

 void Update()
    {
        this.UpdateInfo();
        //this.transform.LookAt(Camera.main.transform,Vector3.up);
        //把血条的Scale.x=-1
        this.transform.forward = Camera.main.transform.forward;

    }

 效果图:

//当服务器没有关闭时,多次登录会有多个角色同时出现在场景里;

多个角色共用同一个实例,服务器做了角色进入没有做角色离开;缺少清理工作

总结图:

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值