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开源游戏引擎:游戏起源,皆因有我!!!