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:

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

public class SkillAnimation

{

 public SkillAnimation()

 {

  m_vCallback = new Dictionary< UInt32, List<framecallback>>();

 }

  public delegate void FrameCallback(UInt32 iFrame);

  //帧回调函数容器< 帧数,<回调函数list>>

  private Dictionary< UInt32, List<framecallback>> m_vCallback;  

  //注册帧回调函数

  public void RegisterFrameCallback(UInt32 iFrame, FrameCallback callback)

  {

   if (!m_vCallback.ContainsKey(iFrame))

   {

    List<framecallback> vCallback = new List<framecallback>();

    m_vCallback.Add(iFrame, vCallback);

   }

   m_vCallback[iFrame].Add(callback);

  }

  //清空注册的帧回调函数

  public void Clear()

  {

   foreach (KeyValuePair< UInt32, List<framecallback>> pair in m_vCallback)

   {

    pair.Value.Clear();

   }

   m_vCallback.Clear();

  }

  //遍历注册的帧回调函数,根据播放的帧数触发相应的函数

  public void Tick(UInt32 iCurrentFrame)

  {

   List<uint32> vPlayCompleted = new List<uint32>();

   //遍历注册的回调函数,并触发相应的函数

   foreach (KeyValuePair< UInt32, List<framecallback>> pair in m_vCallback)

   {

    if (pair.Key <= iCurrentFrame)

    {

     foreach (FrameCallback callback in pair.Value)

     {

      callback(pair.Key);

     }

      vPlayCompleted.Add(pair.Key);

    }

   }

   //删除已触发的回调函数

   foreach (UInt32 iCompleted in vPlayCompleted)

   {

    m_vCallback[iCompleted].Clear();

    m_vCallback.Remove(iCompleted);

   }

  }

}

public class SkillAnimationMgr

{

 private SkillAnimationMgr()

 {

  m_vSkillAnimation = new Dictionary< string, SkillAnimation>();

 }

 private static SkillAnimationMgr s_Instance;

 private Dictionary< string, SkillAnimation> m_vSkillAnimation;

 public static SkillAnimationMgr Instance

 {

 get

 {

  if (null == s_Instance)

  {

   s_Instance = new SkillAnimationMgr();

  }

  return s_Instance;

 }

}

public void Init() { }

//添加动画帧回调组件功能

public void AddSkillAnimation(string sAnimationName, SkillAnimation skillAnimation)

{

 if (!m_vSkillAnimation.ContainsKey(sAnimationName))

 {

  m_vSkillAnimation.Add(sAnimationName, skillAnimation);

 }

}

//删除动画帧回调组件功能

public void RemoveSkillAnimation(string sAnimationName)

{

 if (m_vSkillAnimation.ContainsKey(sAnimationName))

 {

  m_vSkillAnimation[sAnimationName].Clear();

  m_vSkillAnimation.Remove(sAnimationName);

 }

}

//Tick管理器中注册的全部帧回调组件

public void Tick(float fElaspeTime)

{

 //未移除当前Tick时不在播放状态的动画SkillAnimation

 foreach (KeyValuePair < string, SkillAnimation > item in m_vSkillAnimation)

 {

  if (ViewMgr.Instance.CurPlayerView.IsSkillAnimationPlaying(item.Key))

  {

   UInt32 iFrame = (UInt32)ViewMgr.Instance.CurPlayerView.GetPlayingAnimationFrame();

   item.Value.Tick(iFrame);

  }

 }

}</framecallback></uint32></uint32></framecallback></framecallback></framecallback></framecallback></framecallback>
步骤5:
对输入过程筛选,输入成功的放入缓存器中,即完成了程序对技能输入的检测,如下所示。 public void Attack_N(Code code)//筛选过程,最后将筛选后的输入,放入缓存器中。 {  //技能输入筛选条件  if (LogicMgr.Instance.CurPlayer.CheckIdleState() || (LogicMgr.Instance.CurPlayer.CheckJumpState() && !LogicMgr.Instance.CurPlayer.CheckAttackIdleState()))  {   LogicMgr.Instance.AddInputKeyboard(code);   LogicMgr.Instance.CurPlayer.Attack_N();  }   else if (LogicMgr.Instance.CurPlayer.CheckAttackState())  {   if (LogicMgr.Instance.CurPlayer.CheckRight(PlayerRight.ReceiveKeyboard))   {    LogicMgr.Instance.AddInputKeyboard(code);   }  } }

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

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

官方千人大群:59113309   135439306

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

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

 

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

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. 关于vs2013 mysql Ef框架中提示版本不兼容问题的解决办法

    <runtime>     <assemblyBinding>       <dependentAssembly>         <assemblyIden ...

  2. Ubuntu 下部署asp.net运行环境

    在Ubuntu下部署asp.net运行环境,网上教程很多,基本都是编译Mono源码,然后安装jexus.但是可能是我最近RP不太好,编译Mono源码一直都是失败,无奈之下只好找另外的方法安装了. 网上 ...

  3. Python之创建单元素tuple

    tuple和list一样,可以包含 0 个.1个和任意多个元素. 包含多个元素的 tuple,前面我们已经创建过了. 包含 0 个元素的 tuple,也就是空tuple,直接用 ()表示: >& ...

  4. secondarynamenode异常

    secondarynamenode异常 -- ::, ERROR org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode: Exception ...

  5. Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解

    转自Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解 终端:输入和输出设备(键盘 + 显示器). 串行终端:与机器的串口对应,每一个串口对应一个串行终端,串口对应的是物理终端. 虚拟 ...

  6. django的url的name参数的意义(转发)

    http://bio.rusaer.com/archives/288   Django一个比较隐含的函数url 阅读量(5010)  |  发表 于 2010-03-09 14:26:18 Djang ...

  7. SDUT 2622 最短路径(Dijkstra)

    点我看题目 题意 :中文不详述. 思路 :因为这个题加了一个要求就是路径数目得是x的倍数.所以在原来算法的一维dis数组增加到二维,用来存走的路径数%x.也可以用spfa做. #include < ...

  8. java Date和String转换总结

    java.util.Date和String类型的转换是非常常用的,现在总结一下: 1. Date转换为String //Date --->String DateFormat dft = new ...

  9. <算法竞赛入门经典> 第8章 贪心+递归+分治总结

    虽然都是算法基础,不过做了之后还是感觉有长进的,前期基础不打好后面学得很艰难的,现在才慢慢明白这个道理. 闲话少说,上VOJ上的专题训练吧:http://acm.hust.edu.cn/vjudge/ ...

  10. Java多态的体现之继承

    /** * * 功能:演示多态 */ package com.litao; public class Demo5 { public static void main(String[] args) { ...