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. 如何实现一个malloc函数

    一.概述 1.malloc简介 函数所在头文件:<stdlib.h> 函数原型是:void *malloc (size_t n) 函数功能:在内存的动态存储区中分配一个长度为size的连续 ...

  2. Python之添加新元素

    现在,班里有3名同学: >>> L = ['Adam', 'Lisa', 'Bart'] 今天,班里转来一名新同学 Paul,如何把新同学添加到现有的 list 中呢? 第一个办法是 ...

  3. VC项目配置基础以及快捷键(收藏)

    来自http://blog.csdn.net/phunxm/article/details/5082488 一.IDE基础配置 1.字体 VC6中“Tools→Options→Format→Font” ...

  4. ext combobox getValue

    使用combobox时,它有一个hiddenName的属性,专门用于提交combobox中value的值. 现假设某combobox的Id为comboId,hiddenName属性的值为hiddenV ...

  5. Android编程中常用的PopupWindow和Dialog对话框

    注意:PopupWindow组件的使用问题,PopupWindow是一个阻塞对话框,如果你直接在Activity创建的方法中显示它,则会报错:android.view.WindowManager$Ba ...

  6. jquery mobile event

    jquery.js $(document).on("mobileinit", function() { // }); jquery.mobile.js $(document).re ...

  7. android对大图片的缓存处理

    废话不多说,直接上代码 package com.huge.emj.common.util; import java.io.File; import java.io.FileInputStream; i ...

  8. JavaScript 按回车键提交搜索表单 easyui ajax方式

    <!-- 搜索框 --> <form id="bUserSearchForm" style="padding:8px;" onkeydown= ...

  9. D-Bus,kdbus和Binder

    http://blog.sina.com.cn/s/blog_4af327e10101irie.html 材料来自:The unveiling of kdbus 和 Kdbus Details .后一 ...

  10. CAN

    CAN Introduction Features Network Topology(CANbus網路架構) MESSAGE TRANSFER(CAN通訊的資料格式) 1.DATA FRAME(資料通 ...