zoukankan      html  css  js  c++  java
  • 客户端ARPG角色行为模型

    [概述]

      对于玩家自身而言, 场景中的角色分两种:自己,别的生物(包括别的玩家,monster, npc等)。而生物本身是一个集合{属性数据(状态), 行为(动作表现)}。

      站在玩家自身的角度来看, 对于别的生物, 他们的所有数据和行为都是来自服务器, 客户端要做的相当于播放录像的功能, 根据服务器送过来的指令对他们进行控制和表现。

      而玩家自身, 其行为来自两个地方:1、操作模块(比如说客户端的io操作, 程序发出的操作指令等, 操作模块内部封装了所有的操作指令, 对玩家对象进行控制), 2、服务器指令。操作模块的指令会向两个路径分发:1、向服务器发送请求,2、向玩家自身发送指令.
     

    [角色行为]

    和角色行为相关的变量:

    1、  完成条件(即条件满足前不能进行其他行为)。

    2、  位置(产生行为的角色位置)。

    3、  方向。

    4、  状态(此行为对应的角色状态)。

    5、  动作表现。

    [行为分类]

    1、walk.  终点位置, 速度

    2、run. 终点位置, 速度

    3、攻击(施法). 位置,方向

    4、受伤(被攻击).

    5、死亡. 位置

    6、冲撞、被冲撞、死亡击飞等运动轨迹相关. 终点位置       

    [玩家自身]

    [一] 连续移动

    1、客户端角色Me每预先跑一步A-->B, 都要等待服务器的返回(失败或者成功)。在服务器返回响应之前(Me有可能在移动过程中, 也有可能已经到达B点等候),客户端有可能存在以下操作:

             a、移动操作, 即点击场景其他地方C(即玩家想下一步移动到C),此时应该把C立即加入到移动队列中。

                       如果服务器返回成功, 则继续处理移动队列;如果服务器返回失败, 则将Me拉回到A点, 并清空移动队列。

             b、其他操作(如攻击)

                       如果服务器返回成功, 则清空移动队列, 并处理操作队列;如果服务器返回失败, 则将Me拉回到A点, 并清空移动队列, 操作队列。

            

    [二] 攻击

    客户端角色Me的位置CP, 服务器位置SP

    1、CP与SP位置一致, 则立即发送attack指令到服务器, 并立即切换到attack状态,表现攻击动作。

    2、CP与SP位置不一致(有可能正在移动过程中, 即已经发送move指令到服务器), 则立即发送attack指令到服务器(预先攻击)

             a、如果attack指令返回成功, 则等待CP与SP相同时则前端进行攻击行为流程。

             b、如果attack指令返回失败, 则清除标志, 并等待下一步操作。

    3、尝试释放技能的时机

      a、任务开始时在当前位置判断能否释放。

      (有可能攻击失败, 因为玩家位置已变, 延时通知)

      b、开始一次新的移动,先向服务请求移动,前端预移动,并且判断能否释放, 如果可以则预释放。服务器返回移动请求和释放请求成功后,等到达目的点之后表现攻击动作和特效,否则清除预攻击状态。

      (有可能攻击失败, 因为玩家位置已变, 延时通知。这时候是否需要根据当前玩家移动的时间做一个判断策略?一次移动的时间间隔是560ms, 正常的网络传输延时极限(玩家移动广播到达之前+自己发送攻击请求到服务器延时)3个传输延时和2个服务器处理延时)。

      c、收到攻击对象位置变化广播时,判断能否释放,如果可以, 则根据自己当前的状态进行释放或者预释放。

      (这个时候成功率最高, 因为玩家位置延时最短。)

      以上三个时机形成了开始一个攻击任务整个阶段的闭环。

    [其它场景对象]

    这里的处理模型, 主要用于处理行为队列中存在多个行为的情况(大部分原因是网络延迟引起的)

    [一] 移动

    1、  行为队列全部是移动行为, 两种处理方式:

    a、  依次处理每个移动行为。

    b、  根据队列长度,直接处理队尾的移动行为,并清空行为队列。

    2、  行为队列最后一个行为是攻击行为, 同样是两种处理方式:

    a、  依次处理每个移动行为。

    b、根据队列长度,直接处理队尾的攻击行为,并清空行为队列。

    [二] 攻击

    处理模型同上。

    [三] 服务器强制同步行为

    服务器有时候会强制同步行为, 如瞬移等。 则立即清空行为队列, 并执行强制同步行为。

     [操作模块]

    操作模块是针对玩家自身的操作(io操作、自动挂机产生的操作等),将其转换为控制玩家对象的一个逻辑控制任务, 这里用operation表示,比如移动、释放技能、访问npc等都可称之为operation。

    1、创建一个operation之前, 要先判断能否创建这个operation,不能则不响应玩家操作;若能, 则创建一个operation,并且插入到operation队列中。

      例如玩家当前处于摆摊或则死亡等不能移动的状态, 如果这时候玩家操作想移动, 则直接返回不响应。

      例如技能cd没到或魔法值不够等处于不能释放技能的状态, 如果这时候玩家操作想释放技能, 则直接返回不响应。

    2、若当前正在执行的operation失败, 则要判断失败原因, 判断是否要重新尝试。

      例如移动任务,在移动过程中遇到阻挡点或则服务器返回移动失败, 则重新寻路。寻路成功,则继续执行;失败,则放弃任务。

      例如释放技能(有可能会创建一个移动的子任务),在执行过程中发现魔法值不足等问题, 则直接放弃任务。若是移动失败,则尝试重新寻路。

      

    [行为队列模式(FIFO)]

    无论是某个具体的动作行为,还是某个改变状态的操作, 都可以抽象为一个action cmd。

    每个entity持有一个ActionModel, 每个ActionModel维护一个action list。

    [一]实现细节

    1、因为要频繁产生action cmd, 如何防止碎片化问题, 在解决这个问题的时候, 不能影响可维护性和扩展性, 尤其是扩展性。

    2、action list: a1 a2 a3, 在表现上, 由于a2是一个持续性过程, a3有可能会影响a2的表现, 也就是a3可以在a2的执行过程中直接处理, 从而达到并发性表现(并发性的cmd可以使得表现更为丰富)。据此可以抽象, action cmd可以分为:互斥性action和并发性action。

    action list的处理流程:

             if(curAction.isEnd)
             {
                 curAction = list.empty ? action_idle : list.pop_front;
             }
    
             while(!list.front.isMutex(curAction))
             {
                 Process(list.pop_front);
             }
    
             curAction.update;

    [事件与状态]

    1、移动

    {run, walk} --> {move}

    failed:

    拉回原地

    2、攻击

    {物理攻击} --> {物理攻击状态}

    {魔法攻击} --> {魔法攻击状态}

    failed:

    只播放攻击动作, 不播放后续的特效

    3、冲撞

    {rush} --> {冲撞状态}

    {rushed} --> {被冲撞状态}

     4、受伤

    {beHit} --> {hurt}

    5、死亡

    {die} --> {死亡状态}

    6、采集

    {gatherItem} --> {采集状态}

    实时战斗系统问题锦集

    1、人物动作处理策略
        由于某个原因(网络延迟等), 当前正在处理的动作尚未结束(比如移动尚未到达目的地), 此时又收到另外一个要处理的动作协议,这时候的处理策略。
        a、直接将人物状态设置到当前动作的目标状态, 然后开始新的动作。
        b、按正常流程处理当前动作, 并且把要处理的动作入队, 待当前动作完成, 再依次处理动作队列里的内容。
        
        问题衍生:如果把问题放大化, 即当前动作尚未结束, 后面收到一串待处理的动作, 此时的处理策略。

        有可能出现的情况:
        a、正在移动, 网络送来攻击行为        -->位置不一致
        b、正在攻击, 网络送来移动行为        -->位置不一致
        c、正在攻击, 网络送来新的攻击行为    -->表现不一致
        
        处理原则:优先保证位置一致,其次保证表现上的一致性。
        
        处理策略(实际上这里的动作处理, 仅仅是影响人物的表现, 还有坐标位置):
        动作按处理的紧急:
        <1>可以延迟处理的,放入队列缓存
        <2>需要立即处理的(如冲撞, 不立即处理的话,冲撞和被冲撞的表现不一致了。如怪物正在攻击(表现攻击动作))
        
    2、技能释放的处理策略
    技能分类:
        按技能的释放方式:主动、被动
        按攻击目标的数量:群攻、单体
        按是否需要目标:需要、不需要
        按是否魔法锁定:锁定、不锁定
        按施法距离:近身、远程
        按作用目标:只能对自己、只能对队友、只能对敌人
        
    技能释放的前提条件:
        cd、距离、魔法量、目标

    技能释放的要素:
        释放人、目标、方向、 目标点
        <1>从当前位置释放,作用于目标(或目标点)(要判断施法距离)
        <2>在当前位置朝当前方向释放技能(战士技能)
        <3>在当前位置朝鼠标方向释放技能(shift+左键攻击或者两个比较特殊的技能(地狱冰封,极光电影))
        <4>施加于自身(可以合并到<1>, 只是不用判断施法距离)
        
        特殊案例:
        群体治疗术、群体隐身术(作用于当前鼠标位置)
        单体治疗术、单体隐身术(作用于当前鼠标所在的目标, 如果没有目标,作用于自身)
        
    3、打击感的体现

    4、鼠标和键盘按着不放进行操作的延时机制
    如果按着鼠标或者键盘不放,一秒钟可以触发次数:
    鼠标:由程序主线程控制, window系统不会主动触发
    键盘:34次/s

    如果窗口样式指定了CS_DBLCLKS, 则双击鼠标产生的事件:

    down->up->double click->up
    否则:

    down->up->down->up,此时需要使用者根据一定的规则自己检测并生成双击事件。

  • 相关阅读:
    【MFC】对话框自带滚动条的使用
    【MFC】MFC DLEdit 设计属于自己的编辑框_鼠标悬停
    【MFC】MoveWindow();函数使用详解
    【MFC】SetWindowPos函数使用详解
    模板 key+1
    lazyload 分页加载
    缓慢显示隐藏
    js计算日期的前几天的日期
    判断子元素(or属性)是否存在
    动态加载的数据,hover效果
  • 原文地址:https://www.cnblogs.com/zilongblog/p/4184793.html
Copyright © 2011-2022 走看看