之前写过一个系列《HTML5 2D平台游戏开发》,在此过程中发现有很多知识点没有掌握,而且用纯JavaScript来开发一个游戏效率极低,因为调试与地图编辑都没有可视化的工具,开发起来费时费力,加上业余时间有限,我决定暂且中止开发。为了弥补缺少的知识点,我打算先学习和借鉴一下Unity的开发思路,于是把原先的游戏素材移植了过来。首先还是先从人物的动作开始,Unity的动画与之前开发时的思路有很大不同,Unity没有“帧”这一概念,也就是说没有办法获取到当前动画播放到第几帧,只能通过normalizedTime来获取动画播放的百分比进度,一下子让适应这种模式有些困难。先不考虑代码实现细节,整理一下思路,人物实现三连击的状态机大致如下:

  1. Idle ⇢ attack_a ⇢ Idle
  2. Idle ⇢ attack_a ⇢ attack_b ⇢ Idle
  3. Idle ⇢ attack_a ⇢ attack_b ⇢ attack_c ⇢ Idle

在Idle状态下按下攻击键,过渡到attack_a,如果没有下一步操作,attack_a动画播放完毕后还原到Idle状态。如果在attack_a状态下再次按下攻击键,则过渡到attack_b,如果在attack_b状态下无操作,动画播放完毕后还原到Idle,依此类推,多段连击也是一样的。为了表示攻击的状态,需要为Animator添加一个attack参数:

attack等于0表示处于非攻击状态,attack等于1表示处于attack_a,2和3分别表示处于attack_b、attack_c。

接下来一步一步分析各个状态间的过渡。

Idle ⇢ attack_a

  Idle状态可以随时通过按下攻击键打断并过渡到attack_a,故没有 Has Exit Time ,其它项也都置为0。

attack_a ⇢ Idle

  最初我是这样考虑的,给这个过渡设置 Has Exit Time ,如果没有任何操作,让其还原到Idle,于是有了

 

但最终运行时攻击总是会卡在最后一帧一段时间,只有把Exit Time设置为0.1才流畅。也许是动画播放速度设置太快的缘故,但我总觉得通过Exit Time的方式来实现不太好。在查阅一番资料后,我觉得给动作添加Behaviour是比较好的方式。选中attack_a,为其添加一个名为SetNormalizeTime的Behaviour:

public class SetNormalizedTime : StateMachineBehaviour {
private string targetParameter = "Normalized Time"; // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.SetFloat(targetParameter, );
} // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.SetFloat(targetParameter, stateInfo.normalizedTime);
} // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.SetFloat(targetParameter, );
}
}

每次进入该状态,先将Normalized Time重置为0,表示动画从头开始,然后在OnStateUpdate中更新它,最后退出时再置为0。同时也别忘了在Animator中添加一个名为Normalized Time的参数(float类型):

现在可以把attack_a ⇢ Idle的 Has Exit Time 去掉了,同时添加一个 Conditions

表示当动画播放完毕时(NormalizeTime > 1.0f) 过渡到 Idle。同样的,也给attack_b ⇢ Idle 和 attack_c ⇢ Idle 附加上这个 Behaviour。

代码实现

  常规操作:

private Animator anim;
private Rigidbody2D myRigidbody;
private AnimatorStateInfo stateInfo; public int hitCount = ; //0:表示idle状态。 1:表示当前正在进行attack_a。 2:attack_b。 3:attack_c。 void Start ()
{
anim = GetComponent<Animator>(); //获取动画组件
myRigidbody = GetComponent<Rigidbody2D>(); //获取刚体组件
} void Update()
{
stateInfo = anim.GetCurrentAnimatorStateInfo();
HandleInput();
}

下面实现HandleInput方法:

void HandleInput()
{
//若动画为三种状态之一并且已经播放完毕
if ((stateInfo.IsName("attack_a") || stateInfo.IsName("attack_b") || stateInfo.IsName("attack_c")) && stateInfo.normalizedTime > 1.0f)
{
hitCount = ; //将hitCount重置为0,即Idle状态
anim.SetInteger("attack", hitCount);
attack = false;
} //按下键盘J键攻击
if (Input.GetKeyDown(KeyCode.J))
{
HandleAttack();
} }

(这里踩了一个坑,实现这部分逻辑时我是远程操作完成的,发送的指令实际上有一定的延迟,这样就导致按住键盘J键不放可以连续触发攻击,也就是连发。让我误以为GetKeyDown是连续触发的,实际上GetKeyDown只触发一次。)

HandleAttack的实现:

void HandleAttack()
{
//若处于Idle状态,则直接打断并过渡到attack_a(攻击阶段一)
if (stateInfo.IsName("Idle") && hitCount == )
{
hitCount = ;
anim.SetInteger("attack", hitCount);
}
//如果当前动画处于attack_a(攻击阶段一)并且该动画播放进度小于80%,此时按下攻击键可过渡到攻击阶段二
else if(stateInfo.IsName("attack_a") && hitCount == && stateInfo.normalizedTime < 0.8f)
{
hitCount = ;
}
//同上
else if(stateInfo.IsName("attack_b") && hitCount == && stateInfo.normalizedTime < 0.8f)
{
hitCount = ;
}
}

这里要注意,比如在触发第二段攻击时需要满足条件 normalizedTime < 0.8f ,但此时按下攻击键是不会马上播放第二段攻击动画的,如果马上播放就显得动作非常不协调了,应该等到第一阶段的攻击动画播放到一定阶段才播放第二段攻击动画。所以需要给关键帧添加一个方法,告诉动画系统在这一帧要执行某个指令。

void GoToNextAttackAction()
{
anim.SetInteger("attack", hitCount);
}

给第7帧添加一个事件,指向 GoToNextAttackAction 这个方法,动画将在第7帧的时候被打断并进入下一个攻击动画。如果hitCount没有改变,SetInteger("attack",hitCount) 不会影响当前正在播放的动画,动画会持续播放完毕(至第9帧)。

P.S. 虽然费了一些周折,但还是把效果实现出来了,Unity的开发效率比JS高出太多,大概100倍左右吧,这是在开发过程中的感觉。不知道离游戏成品还有多遥远,但我还是会继续学习。

Unity2D实现人物三连击的更多相关文章

  1. Unity - HasExitTime用法

    本文详细分析了AnimatorController中动画切换过渡问题,即Translation过渡及hasExitTime的问题.方法为对实际项目中的所有情况进行分类,规划逻辑图,可视化分析解决这些问 ...

  2. [开发ing] Unity项目 - Hero英雄

    目录 游戏原型 项目演示 绘图资源 代码实现 技术探讨 参考来源 游戏原型 游戏介绍:这是一款横版类魂游戏,玩家将操控Hero,在诸神黄昏的墓地中,挑战源源不断的敌人,以及近乎无敌的强大boss 灵感 ...

  3. 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  4. Unity2D 人物移动切换人物图片

      勾选Constraints_freeze Rotation_z轴锁定,防止碰撞偏移.        public float moveSpeed = 3f;//定义移动速度        priv ...

  5. 时光煮雨 Unity3D实现2D人物移动-总结篇

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  6. 时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  7. 角色移动优化【Unity2D自学之路】

    自学unity2D独立游戏开发,第一篇自学笔记.在场景中添加角色,并给角色添加Rigidbody2D刚体组件.collection2D碰撞体组件,c#脚本组件控制人物移动和跳跃.c#脚本组件内容如下, ...

  8. 计算机人物系列-Mauchly,Eckert,Goldstine

    关键词:莫尔学院(Moore School),阿伯丁试验场(Aberdeen Proving Ground), 雷明顿兰德公司(Remington Rand Corporation), IBM院士(I ...

  9. Python学习笔记(2) Python提取《釜山行》人物关系

    参考:http://www.jianshu.com/p/3bd06f8816d7 项目原理:   实验基于简单共现关系,编写 Python 代码从纯文本中提取出人物关系网络,并用Gephi 将生成的网 ...

随机推荐

  1. HDU 1847 【巴什博弈】

    Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...

  2. #424 Div2 C

    #424 Div2 C 题意 给出 k 个分数,初始分数未知,按顺序把这 k 个分数加到初始分数上,已知 n 个加入分数后的结果(无序),问初始分数有多少种可能. 分析 也就是说这 n 个结果,它们之 ...

  3. POJ 1741 Tree 树的分治

    原题链接:http://poj.org/problem?id=1741 题意: 给你棵树,询问有多少点对,使得这条路径上的权值和小于K 题解: 就..大约就是树的分治 代码: #include< ...

  4. Oracle PL/SQL DBA 编程实践基础

    [附:一文一图]

  5. iOS禁止多点操作(按钮和Table项)

    1)避免同时点击多个按钮: [btn setExclusiveTouch:YES]; 设置确保当btn点击时,其他按钮不响应: (2)避免同时点击UITableView中多个row -(NSIndex ...

  6. xcode里面使用Memory Leaks和Instruments检测内存泄漏

    教程截图: 作为一名无证程序员,无论你多么精通Objective-C的内存管理,随着时间的推移,你也不可避免的犯内存相关的错误.但通常因为代码量太大,以至于你不可能一行一行的去排除(等你解决完,你设计 ...

  7. What is a fully qualified domain name (FQDN)?

    fully qualified domain name (FQDN) is the complete domain name for a specific computer, or host, on ...

  8. wp8使用mvvm模式简单例子

    mvvm是silverlight/wpf下的mvc升华 通过一个简单的加法计算器例子来说明mvvm是什么 在设计界面完成设计之后,显示简单的布局,如下图: 然后来比较,传统的直接方式,mvc和mvvm ...

  9. zabbix通过percona插件监控mysql

    percona zabbix mysql-plugin是percona发布的一个使用zabbix监控mysql数据库的工具,这款工具比zabbix自带的监控模板要强大的多,毕竟percona是Mysq ...

  10. bitcoin-qt忘记密码

    客户端有钱包加密功能,输入密码可以增强安全性. 但是,如果你把钱包文件弄丢了,那即使设了密码,币也会丢. 关闭bitcoin-qt,把钱包文件wallet.dat 剪到其他地方(但不要删除),然后重新 ...