[业务系统]人物坐骑系统介绍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,那么说明是下马的行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/425427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【笔试强训错题选择题】Day5.习题(错题)解析

文章目录 前言 错题题目 错题解析 总结 前言 错题题目 1. ​ ​ 2. 3. ​ 4. ​ 5. ​ 错题解析 1. 移位运算符的使用 2. 3. 4. 5. 总结

股票技术指标(包含贪婪指数)

股票技术指标是用于分析股票价格和成交量数据&#xff0c;以便预测未来市场走势的工具。技术分析师使用这些指标来识别市场趋势、价格模式、交易信号和投资机会。技术指标通常基于数学公式&#xff0c;并通常在股票价格图表上以图形形式表示。 技术指标主要分为以下几类&#x…

过于老旧的pytorch_ssim包 请从github下载源码

有些冷门算法真的不要随便pip&#xff0c;有可能下载到史前版本…最好还是找源代码 汗 今天要用到SSIM损失函数&#xff0c;从网上简单看了一下原理就想测试一下&#xff0c;偷了一下懒就直接在命令行输入pip install pytorch_ssim了&#xff0c;结果报了一堆错误&#xff08;汗…

冒泡排序(C语言详解)

原理&#xff1a;从左到右一次比较&#xff0c;如果左侧数字比右侧数字大&#xff08;小&#xff09;&#xff0c;则两数交换&#xff0c;否则比较下一 组数字&#xff0c;每一次大循环比较可以将乱序的最右侧数字改为最大&#xff08;最小&#xff09;&#xff0c…

在springboot项目中调用通义千问api多轮对话并实现流式输出

官网文档 阿里灵积提供了详细的官方文档 如何实现多轮对话 官方文档中提到只需要把每轮对话中返回结果添加到消息管理器中&#xff0c;就可以实现多轮对话。本质上就是将历史对话再次发送给接口。 如何实现流式输出 官方文档中提出使用streamCall()方法就可以实现流式输出&…

本届挑战赛亚军方案:基于大模型和多AGENT协同的运维

“轻舟已过万重山团队”荣获本届挑战赛亚军&#xff0c;该团队来自华为集团IT-UniAI 产品和openEuler系统智能团队。 方案介绍 自ChatGPT问世以来&#xff0c;AI迎来了奇点iPhone时刻&#xff0c;这一年来大模型深入影响企业办公&#xff0c;金融&#xff0c;广告&#xff0c;…

上位机图像处理和嵌入式模块部署(上、下位机通信的三个注意点)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 如果最终部署在客户现场的是一个嵌入式设备&#xff0c;那么上位机在做好了算法编辑和算法部署之后&#xff0c;很重要的一步就是处理上位机和下位…

Mybatis 主从表有名字相同,只能查询出一条数据

Mybatis 主从表有名字相同&#xff0c;只能查询出一条数据 重新命名后&#xff0c;可以正常查询

【HarmonyOS】鸿蒙开发之Stage模型-UIAbility的启动模式——第4.4章

UIAbi lity的启动模式简介 一共有四种:singleton,standard,specified,multion。在项目目录的:src/main/module.json5。默认开启模式为singleton(单例模式)。如下图 singleton&#xff08;单实例模式&#xff09;启动模式 每个UIAbility只存在唯一实例。任务列表中只会存在一…

多个地区地图可视化

1. 配置Json文件 1.1 获得每个省份的json数据 打开 阿里云数据可视化平台 主页。 在搜索框中输入所需省份。 将json文件下载到本地。 1.2 将各省份的json数据进行融合 打开 geojson.io 主页 点击 open&#xff0c;上传刚刚下载的 json 文件&#xff0c;对多个省份不断…

SpringCloud负载均衡源码解析 | 带你从表层一步步剖析Ribbon组件如何实现负载均衡功能

目录 1、负载均衡原理 2、源码分析 2.1、LoadBalanced 2.2、LoadBalancerClient 2.3、RibbonAutoConfiguration 2.4、LoadBalancerAutoConfiguration 2.5、LoadBalancerIntercepor⭐ 2.6、再回LoadBalancerClient 2.7、RibbonLoadBalancerClient 2.7.1、DynamicServe…

JavaScript进阶-高阶技巧

文章目录 高阶技巧深浅拷贝浅拷贝深拷贝 异常处理throw抛异常try/caych捕获异常debugger 处理thisthis指向改变this 性能优化防抖节流 高阶技巧 深浅拷贝 只针对引用类型 浅拷贝 拷贝对象后&#xff0c;里面的属性值是简单数据类型直接拷贝值&#xff0c;如果属性值是引用数…

matlab 写入格式化文本文件

目录 一、save函数 二、fprintf函数 matlab 写入文本文件可以使用save和fprintf函数 save输出结果: fprintf输出结果: 1.23, 2.34, 3.45 4.56, 5.67, 6.78 7.89, 8.90, 9.01 可以看出fprintf输出结果更加人性化,符合要求,下面分别介绍。 一、save函数 …

【前端寻宝之路】学习如何使用HTML实现简历展示和填写

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-iJ3Ou0qMGFVaqVQq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

哈希表是什么?

一、哈希表是什么&#xff1f; 哈希表&#xff0c;也称为散列表&#xff0c;是一种根据关键码值&#xff08;Key value&#xff09;直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录&#xff0c;从而加快查找速度。这个映射函数叫做散列函数&#xff08…

【字符串相加】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 字符串相加 方法一&#xff1a; 方法二&#xff1a; 总结 前言 世上有两种耀眼的光芒&#xff0c;一种是正在升起的太阳&#xff0c;一种是正在努力学习编程的…

给你N个整数,要求删除最大和最小的数之后按原顺序输出。

给你N个整数&#xff0c;要求删除最大和最小的数之后按原顺序输出。 输入输出格式 输入描述: 第一行输入一个整数N&#xff0c;N<100。 第二个输入N个整数。 输出描述: 按题意输出。#include <iostream> using namespace std; int main() {int n;cin >> n;int…

Vue2->3

Vue2->3 认识Vue31. Vue2 选项式 API vs Vue3 组合式API2. Vue3的优势 使用create-vue搭建Vue3项目1. 认识create-vue2. 使用create-vue创建项目 熟悉项目和关键文件组合式API - setup选项1. setup选项的写法和执行时机2. setup中写代码的特点3. <script setup>语法糖…

Scratch 第十六课-弹珠台游戏

第十六课-弹珠台游戏 大家好&#xff0c;今天我们一起做一款弹珠台scratch游戏&#xff0c;我们也可以叫它弹球游戏&#xff01;这款游戏在刚出来的时候非常火爆。小朋友们要认真学习下&#xff01; 这节课的学习目标 物体碰撞如何处理转向问题。复习键盘对角色的控制方式。…

ubuntu环境下docker容器详细安装使用

文章目录 一、简介二、ubuntu安装docker1.删除旧版本2.安装方法一3. 安装方法二&#xff08;推荐使用&#xff09;4.运行Docker容器5. 配置docker加速器 三、Docker镜像操作1. 拉取镜像2. 查看本地镜像3. 删除镜像4. 镜像打标签5. Dockerfile生成镜像 四、Docker容器操作1. 获取…
最新文章