• 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程04:技能的输入与检测》


    4.技能的输入与检测

    概述:

    技能系统的用户体验,制约着玩家对整个游戏的体验。游戏角色的技能华丽度,连招的顺利过渡,以及逼真的打击感,都作为一款游戏的卖点吸引着玩家的注意。开发者在开发游戏初期,会根据玩家对此类游戏的惯性操作,设定技能控制按键。同时Genesis引擎为开发者提供的众多API接口,包含了按键过程、按键按下和抬起的识别功能。当玩家根据游戏设定的按键操作,输入后。系统会记录按键操作的命令,然后程序通过对玩家当前输入状态,以及输入的过程检测,判定技能输入是否为有效输入。

    技能系统的用户体验,制约着玩家对整个游戏的体验。游戏角色的技能华丽度,连招的顺利过渡,以及逼真的打击感,都作为一款游戏的卖点吸引着玩家的注意。开发者在开发游戏初期,会根据玩家对此类游戏的惯性操作,设定技能控制按键。同时Genesis-3D引擎为开发者提供的众多API接口,包含了按键过程、按键按下和抬起的识别功能。当玩家根据游戏设定的按键操作,输入后。系统会记录按键操作的命令,然后程序通过对玩家当前输入状态,以及输入的过程检测,判定技能输入是否为有效输入。 

    原理:

    按键定义->输入->检测输入状态->检测输入过程。


    图4-1

    技能输入检测的实现:

    步骤1:

    引擎提供了相应的API接口,供开发者使用,其中就包括三个与按键相关的接口,一个是按键过程中、按键按下、按键抬起。在ScriptRuntime命名里,有个Input类下,为情提供了相应接口。开发者可以直接定义按下当前操控间,所作的操作。以攻击为例,如下所示。

    1 if (Input.KeyDown(Code.J))
    2 {
    3  Attack_N(Code.J);
    4 }

    步骤2:

    检测输入条件,即玩家当前状态的输入权限。

    玩家根据开发者对游戏的设定,进行相关按键操作。当玩家按下按键之后,程序记录按键事件。之后按照开发者定义的检测规则,判定玩家输入是否有效。由于按键所属的功能不同,相应筛选机制也是不同的。技能的输入条件检测,可以通过动画区间帧来控制。玩家权限的判定,是否键输有效。攻击键J举例,原理图,如图4-1-1所示。


    图4-2-1

    横向为动画帧,上面的A、B、C、D、E等代表所在时间轴上响应的帧数。判定玩家连招输入权限,程序逐帧检测当前帧玩家所属状态。在A点输入J攻击键后,程序遍历每帧玩家状态。在A-B动画区间帧内玩家为无权限输入,玩家即使有键入指令,程序也不认为输入状态有效,进而不做后面的检测。只有在B-C动画区间内时,程序判定玩家有输入权限,玩家在该动画区间内获得键入权限。如在该区间内有攻击键J的输入,程序即遍历后面的动画帧,若无有限键入,即停止此次连招技能的输入状态的检测。

    步骤3:

    private PlayerRight m_eRight = PlayerRight.ReceiveKeyboard; //玩家权限,包含:接收按键操作、对怪物的有效碰撞伤害

    步骤4:

    动画区间检测输入状态,代码如下所示。

    001
    public class SkillAnimation
    002
    {
    003
     public SkillAnimation()
    004
     {
    005
      m_vCallback = new Dictionary< UInt32, List<framecallback>>();
    006
     }
    007
      public delegate void FrameCallback(UInt32 iFrame);
    008
      //帧回调函数容器< 帧数,<回调函数list>>
    009
      private Dictionary< UInt32, List<framecallback>> m_vCallback;  
    010
      //注册帧回调函数
    011
      public void RegisterFrameCallback(UInt32 iFrame, FrameCallback callback)
    012
      {
    013
       if (!m_vCallback.ContainsKey(iFrame))
    014
       {
    015
        List<framecallback> vCallback = new List<framecallback>();
    016
        m_vCallback.Add(iFrame, vCallback);
    017
       }
    018
       m_vCallback[iFrame].Add(callback);
    019
      }
    020
      //清空注册的帧回调函数
    021
      public void Clear()
    022
      {
    023
       foreach (KeyValuePair< UInt32, List<framecallback>> pair in m_vCallback)
    024
       {
    025
        pair.Value.Clear();
    026
       }
    027
       m_vCallback.Clear();
    028
      }
    029
      //遍历注册的帧回调函数,根据播放的帧数触发相应的函数
    030
      public void Tick(UInt32 iCurrentFrame)
    031
      {
    032
       List<uint32> vPlayCompleted = new List<uint32>();
    033
       //遍历注册的回调函数,并触发相应的函数
    034
       foreach (KeyValuePair< UInt32, List<framecallback>> pair in m_vCallback)
    035
       {
    036
        if (pair.Key <= iCurrentFrame)
    037
        {
    038
         foreach (FrameCallback callback in pair.Value)
    039
         {
    040
          callback(pair.Key);
    041
         }
    042
          vPlayCompleted.Add(pair.Key);
    043
        }
    044
       }
    045
       //删除已触发的回调函数
    046
       foreach (UInt32 iCompleted in vPlayCompleted)
    047
       {
    048
        m_vCallback[iCompleted].Clear();
    049
        m_vCallback.Remove(iCompleted);
    050
       }
    051
      }
    052
    }
    053
    public class SkillAnimationMgr
    054
    {
    055
     private SkillAnimationMgr()
    056
     {
    057
      m_vSkillAnimation = new Dictionary< string, SkillAnimation>();
    058
     }
    059
     private static SkillAnimationMgr s_Instance;
    060
     private Dictionary< string, SkillAnimation> m_vSkillAnimation;
    061
     public static SkillAnimationMgr Instance
    062
     {
    063
     get
    064
     {
    065
      if (null == s_Instance)
    066
      {
    067
       s_Instance = new SkillAnimationMgr();
    068
      }
    069
      return s_Instance;
    070
     }
    071
    }
    072
    public void Init() { }
    073
    //添加动画帧回调组件功能
    074
    public void AddSkillAnimation(string sAnimationName, SkillAnimation skillAnimation)
    075
    {
    076
     if (!m_vSkillAnimation.ContainsKey(sAnimationName))
    077
     {
    078
      m_vSkillAnimation.Add(sAnimationName, skillAnimation);
    079
     }
    080
    }
    081
    //删除动画帧回调组件功能
    082
    public void RemoveSkillAnimation(string sAnimationName)
    083
    {
    084
     if (m_vSkillAnimation.ContainsKey(sAnimationName))
    085
     {
    086
      m_vSkillAnimation[sAnimationName].Clear();
    087
      m_vSkillAnimation.Remove(sAnimationName);
    088
     }
    089
    }
    090
    //Tick管理器中注册的全部帧回调组件
    091
    public void Tick(float fElaspeTime)
    092
    {
    093
     //未移除当前Tick时不在播放状态的动画SkillAnimation
    094
     foreach (KeyValuePair < string, SkillAnimation > item in m_vSkillAnimation)
    095
     {
    096
      if (ViewMgr.Instance.CurPlayerView.IsSkillAnimationPlaying(item.Key))
    097
      {
    098
       UInt32 iFrame = (UInt32)ViewMgr.Instance.CurPlayerView.GetPlayingAnimationFrame();
    099
       item.Value.Tick(iFrame);
    100
      }
    101
     }
    102
    }</framecallback></uint32></uint32></framecallback></framecallback></framecallback></framecallback></framecallback>
    步骤5:
    对输入过程筛选,输入成功的放入缓存器中,即完成了程序对技能输入的检测,如下所示。
    01
    public void Attack_N(Code code)//筛选过程,最后将筛选后的输入,放入缓存器中。
    02
    {
    03
     //技能输入筛选条件
    04
     if (LogicMgr.Instance.CurPlayer.CheckIdleState()
    05
                  || (LogicMgr.Instance.CurPlayer.CheckJumpState() && !LogicMgr.Instance.CurPlayer.CheckAttackIdleState()))
    06
     {
    07
      LogicMgr.Instance.AddInputKeyboard(code);
    08
      LogicMgr.Instance.CurPlayer.Attack_N();
    09
     }
    10
      else if (LogicMgr.Instance.CurPlayer.CheckAttackState())
    11
     {
    12
      if (LogicMgr.Instance.CurPlayer.CheckRight(PlayerRight.ReceiveKeyboard))
    13
      {
    14
       LogicMgr.Instance.AddInputKeyboard(code);
    15
      }
    16
     }
    17
    }

    引擎官方网站:http://www.genesis-3d.com.cn/

    官方论坛:http://bbs.9tech.cn/genesis-3d/

    官方千人大群:59113309   135439306

    YY频道-游戏开发大讲堂(完全免费,定期开课):51735288 

    Genesis-3D开源游戏引擎:游戏起源,皆因有我!!!

     
  • 相关阅读:
    详解git pull和git fetch的区别
    什么是移臂调度,什么是旋转调度?
    常用的资源分配策略有哪两种?在每一种策略中,资源请求队列的排序原则是什么?
    什么是虚拟资源,对主存储器而言,用户使用的虚拟资源是什么?
    进程调度的任务是什么,线程调度的任务是什么?
    用于进程控制的原语主要由哪几个,每个原语的执行将使进程的状态发生什么变化?
    试说明进程创建的主要功能是什么?
    什么是线程,线程与进程有什么区别?
    什么是进程互斥,什么是进程同步,同步和互斥这两个概念有什么联系和区别?
    n个并发进程共用一个公共变量Q,写出用信号灯实现n个进程互斥的程序描述,给出信号灯值得取值范围,并说明每个取值范围的物理意义。
  • 原文地址:https://www.cnblogs.com/G-3D/p/3500792.html
Copyright © 2020-2023  润新知