[业务系统]人物坐骑系统介绍I

image.png

1.问题描述

旧版本的坐骑系统依赖于人物装备了【法宝】(一种装备类型),装备了法宝的人物变拥有了【幻化】坐骑的能力,即在人物装备栏中的【外观】中会有已经幻化和未幻化(解锁)的坐骑。
如果玩家至少幻化一种坐骑(动物外观),那么玩家在使用坐骑按钮后变成【骑乘】形态,如果没有解锁任何一种坐骑。外观默认使用【法宝】骑乘的状态。
后续,玩家可以在坐骑选择界面手动选择使用【法宝】还是已经解锁的动物作为坐骑外观。
image.pngimage.png
两种坐骑外观

【骑乘状态】可以转化为【飞行状态】,处在飞行状态时,向上滑动左侧摇杆会使玩家向上飞行。
【飞行状态】向下滑动转化为【骑乘状态】,【骑乘状态】再次点击按钮为坐骑。

新版本的需求变化为坐骑的【幻化】不依赖于装备【法宝】了,未装备法宝,无法飞行。

2.问题分析

客户端发起

先从上坐骑的事情回调部分开始调试。行为是通过客户端发起,对于【申请】性质的行为一般是服务器做校验,更新服务器共享内存组,判断是否需要持久化(如果需要,在GameServer进程的DBRoutine线程中在定期心跳包中与DBAgent进程通信,持久化存储主线程接收到的新数据字段。这部分是游戏的数据管理进程做的,不是本文重点)
image.png
现在出现了一个问题:
游戏的自动寻路系统在导航阶段,会根据当前位置与目标点的距离和高度差 ,通过状态机选择是否需要骑乘坐骑再寻路。也就是除了按钮回调事件,在update中可能也会调用到UseSkillMount的逻辑,
而原先在客户端本地UseSkillMount条件筛选中,玩家必须装备法宝才有后面的步骤。现在新需求,上坐骑与法宝取消了绑定关系。那么如果玩家此时没有幻化坐骑,那么一旦开启任务自动寻路,会一直弹“未幻化坐骑,不可骑乘”的提示字。
所以需要设置一个flag做区分,在发包的时候告诉服务器。这一帧是玩家点击按钮使用坐骑,而不是导航系统自动上马使用坐骑,把逻辑分开就不会一直走错误判断了

public string UseSkillMount_WithError(bool isPlayerClick = false)
{
    //-----错误条件筛选--
    
    //code zone
     CG_MOUNT_MOUNT_PAK pak = new CG_MOUNT_MOUNT_PAK();
            pak.data.MountID = isPlayerClick ? -1 : 0; // 传0有特殊含义,意思就是让服务器决定自动坐骑
    //-1表示由玩家发起(非导航系统)
            if (GlobeVar._AutoGameConfig.IsOpenGetInfo)
            {
                pak.data.MountEffect = PlatformHelper.ReqSource();
                pak.data.MountMCount = PlatformHelper.ReqCount();
                pak.data.MountHColor = PlatformHelper.ReqOption();
                pak.data.MountBColor = PlatformHelper.ReqContent();
                pak.data.MountFColor = PlatformHelper.ReqSubType();
                int data = 0;
//--机器适配的宏-省略
#if UNITY_IPHONE && !UNITY_EDITOR
            pak.data.MountVersion = data;
#else
                pak.data.MountData = data;
#endif
            }
            pak.SendPacket();
}

服务器校验和计算

接下来在服务器工程的 HandlePacket重载函数,参数列表是CG_MOUNT_MOUNT 中找到解析包的部分大概是下面这样

int32_t nMountID =  rPacket.mountID();
if(nMountID < -1)
{
    return PACKET_EXE_CONTINUE;
}
int32_t real_nMountID =  AutoMountID(nMountID);

看看服务器是怎么判断当前选取哪个坐骑的

int32_t Obj_Player::AutoMountID(int32_t nMountID)
{
    //1.参数有效直接使用这个参数,查表上指定坐骑
    //2.如果有幻化坐骑,并且在包裹里,那么直接使用幻化的坐骑

    //差异性判断:
    /*
    如果是自动任务:那么先检查当前默认坐骑ID是否为空(保存的是上一次幻化坐骑,或者使用法宝的ID)
    如果为空,先遍历坐骑缓存池的全部ID,如果有不为空则使用
    若缓存池为空,那么只剩下一种情况就是购买了法宝但从未使用,即没有幻化。保险起见,直接返回法宝ID
    如果是-1那么不可上坐骑(实际是不可能的,因为要保证导航系统的稳定可靠)

    如果是玩家发起的行为
    那么只需要检测坐骑背包是否有坐骑,没有就返回当前装备栏的法宝ID,如果是-1.
    那么不可上坐骑
    */
    
}

接下来如果没有return,说明服务器拿到了合法的ID。

private bool  Mount_Mount(int mountID)
{
    //1.判断坐骑是在包里还是当前装备的法宝
    //2.有效性检测
    //3.如果是绑定系统主人,则解除所有人的绑定关系
    //4.重置状态(解除隐身 -- 解除对话状态 -- 打断采集 -- 打断技能行为)
    //5.判断有无效果追加(如果在空中换坐骑,则附加一次空中加速)

    SendMountData();
    BroadCast_MountData();
}

接下来服务器回包给客户端,主要是表明接受到的ID是合法且有效的。回传当前玩家绑定的服务器ID 和合法坐骑ID号

void Obj_Player::SendMountData()
{
    __SOL_TRACE;
    if(IsSceneVaild() == false)
    {
        return;
    }
    Packets::GC_MOUNT_DATA_PAK pak;
    pak.m_PacketData.set_objserverid(GetID());
    pak.m_PacketData.set_mountid(m_CurMountID());
    SendPacket(pak);
    SOL_TRACE__;
}

客户端变更表现

接下来在客户端DataHandler类中找到Receive的方法

public static void ReceivePacket(GC_MOUNT_DATA packet)
    {
        int nObjServerID = packet.ObjServerID;
        int nMountID = packet.MountID;

        int EnterSceneServerID = GameManager.PlayerDataPool.CreateMainPlayerCache.m_ServerID;
        // 切场景缓存
        if ( EnterSceneServerID == nObjServerID )
        {
            GameManager.PlayerDataPool.CreateMainPlayerCache.m_MountID = nMountID;
        }
        else
        {
            Obj_Char obj = ObjManager.FindObjCharInScene(nObjServerID);
            if ( obj )
            {
                if ( obj.IsPlayer())
                {
                    Obj_Player Player = obj as Obj_Player;
                    if (Player != null)
                    {
                        if(Player.IsInJump())
                        {
                            Player.ResetJumpState();
                            Player.RideOrUnMount(nMountID,false);
                        }
                        else
                        {
                            Player.RideOrUnMount(nMountID);
                        }
                    }
                }
            }
        }
    }

我们发现如果接受到的ServerID 绑定了有效的玩家后,就开始判断玩家是否可以上坐骑(跳跃过程中显然是不可以上坐骑的,得等动画播放结束后。但游戏为了玩家体验,直接选择重置状态然后立即上坐骑)
这里还发现,上下马的客户端收包位置是一样的。可以确定服务器只是做了数据方面的校验和计算。那么唯一ID怎么标识,玩家是上马还是下马呢。
合法的mountID一定大于0,等于0是客户端发起计算请求,如果上马合法,服务器一单会回传一个大于0的MountID。
所以,客户端只需要判断如果mountID <0,那么说明是下马的行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值