Unity3D拥有很强大的动画系统,不仅可以制作简单动画还能管理动画。
制作简单动画可以借助Animation。
为了管理动画,Unity3D配置了Animator Controller文件类型,它包含以下功能。
- 可以对多个动画进行整合;
- 使用状态机来实现动画的播放和切换;
- 可以实现动画融合和分层播放;
- 可以通过脚本来对动画播放进行深度控制
如果我们想管理GameObject的组合的动画这时Animator组件就派上用场了。部分参数含义如下:
- Controller:使用的Animator Controller文件。
- Avatar:使用的骨骼文件。
- Apply Root Motion:绑定该组件的GameObject的位置是否可以由动画进行改变(如果存在改变位移的动画)。
- Update Mode:更新模式:Normal表示使用Update进行更新,Animate Physics表示使用FixUpdate进行更新(一般用在和物体有交互的情况下),Unscale Time表示无视timeScale进行更新(一般用在UI动画中)。
- Culling Mode:剔除模式:Always Animate表示即使摄像机看不见也要进行动画播放的更新,Cull Update Transform表示摄像机看不见时停止动画播放但是位置会继续更新,Cull Completely表示摄像机看不见时停止动画的所有更新。
Animator Controller通过状态机控制动画。新建界面如下:
我们可以通过自己制作的animation 或者是直接拖动模型的动画进来,设置执行条件等。下面以鹰动画为例说明:
我设置两个参数bool类型的live和int类型的fly_attack_trigger,设置相关条件如下
首先我们遇到一个问题如何在攻击结束后返回飞行状态呢?或许你会说在update里将fly_attack_trigger设置为0就行但是你怎么知道攻击动作执行完呢?万一一帧没执行完攻击你就调回飞行呢。所以我选择在动画结束时调用事件函数StopAttack,方法找到动画的inspector面板,在里面有个Events下拉条,下拉后在想要的帧的位置添加事件函数,函数名字记得在使用这个动画的物体的脚本里面写好,否则会报错
然后写脚本控制鹰的上下左右移动和前进和攻击。上下左右与攻击直接使用键盘的输入解决,至于前进需要利用下几何知识将欧拉角的y向量投影到x轴和z轴。还有如果鹰只会前进不会转弯就太傻了,利用Rotate旋转即可,脚本如下
public class CrowController : MonoBehaviour {
public float speed = 4.0f;
private Animator ani;
private Rigidbody rig;
// Use this for initialization
void Start () {
ani = GetComponent<Animator>();
rig = GetComponent<Rigidbody>();
}
void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
this.transform.Rotate(new Vector3(0, 45, 0));
rig.velocity = Vector3.zero;
Debug.Log(transform.eulerAngles);
}
else if (Input.GetKeyDown(KeyCode.D))
{
this.transform.Rotate(new Vector3(0, -45, 0));
rig.velocity = Vector3.zero;
Debug.Log(transform.eulerAngles);
}
}
// Update is called once per frame
void FixedUpdate () {
rig.AddForce(new Vector3(Mathf.Sin(transform.eulerAngles.y * Mathf.PI / 180), 0, Mathf.Cos(transform.eulerAngles.y * Mathf.PI / 180)), ForceMode.Force);
float high = Input.GetAxis("Vertical") * speed;
rig.AddForce(Vector3.up * (high + 9), ForceMode.Force);
float right = Input.GetAxis("Horizontal") * speed;
rig.AddForce(Vector3.right * right, ForceMode.Force);
if(Input.GetButtonDown("Fire1"))
{
ani.SetInteger("fly_attack_trigger", 1);
}
if (Input.GetButtonDown("Fire2"))
{
ani.SetInteger("fly_attack_trigger", 2);
}
}
void StopAttack()
{
ani.SetInteger("fly_attack_trigger", 0);
Debug.Log("0");
}
void OnCollisionEnter(Collision other)
{
Debug.Log(other.gameObject.name);
ani.SetBool("live", false);
}
}
同样的我引入了鸡和它的动画但是我觉得如果鸡能动起来那就更真实了,我需要画一些点和路径,这时itween插件就派上用场了,下载可到 官网 ,建议下载itween Path和 itween path editor(可视化路径编辑工具)。iTween 是一个动画库, 它的目的就是最小的投入实现最大的产出. 让你做开发更轻松, 用它可以轻松实现各种动画, 晃动, 旋转, 移动, 褪色, 上色, 控制音频等等。
导入方法:在项目中建立Plugins 目录, 然后将下载的 iTween.cs 放到 Plugins 目录即可 . 如果需要编辑路径 , 使用 import package->custom package 菜单功能加入 iTweenPath.unitypackage
使用方法如下图:将I Tween Path的脚本加到你需要编辑的角色,设置节点数及位置我们可以直观的在场景中看到
然后写个脚本进行控制,本来itween里面有一个参数orienttopath设置true就可以让角色沿着路线转弯朝着节点走,但是运行后鸡是用尾巴朝着Node走。仔细研究后才知道它是调用lookat,而lookat就是将物体z轴正向朝着目标,因为鸡的尾巴恰好是z轴正向,所以解决办法你可以用3DMax建模软件改变正向反向,但是有一个问题,鸡的模型在bird.unitypakage,需要先解压再拿到模型改完再压缩回去,而单单解压unitypakage本身就及其麻烦,所以我放弃了,第二个办法改itween path的源码,将lookat方法后再旋转180度,但是作者代码好多啊,最后发现一个简单的办法直接弃用itween的方法,自己lookat然后旋转就行。
ChickenController.cs如下:
public class ChickenController : MonoBehaviour
{
//路径寻路中的所有点
public Transform[] paths;
public Transform Crow;
private Animator ani;
int n = 0;
void Start()
{
ani = GetComponent<Animator>();
Hashtable args = new Hashtable();
//设置路径的点
args.Add("path", paths);
//设置类型为线性,线性效果会好一些。
args.Add("easeType", iTween.EaseType.linear);
//设置寻路的速度
args.Add("speed", 10f);
//是否先从原始位置走到路径中第一个点的位置
args.Add("movetopath", true);
//循环
args.Add("loopType", "loop");
//是否让模型始终面朝当面目标的方向,拐弯的地方会自动旋转模型
//如果你发现你的模型在寻路的时候始终都是一个方向那么一定要打开这个
args.Add("orienttopath", false);
//让模型开始寻路
iTween.MoveTo(gameObject, args);
}
void OnDrawGizmos()
{
//在scene视图中绘制出路径与线
iTween.DrawLine(paths, Color.yellow);
iTween.DrawPath(paths, Color.red);
}
void Update()
{
float safeDis = Vector3.Distance(this.transform.position, Crow.position);
if (safeDis < 10)
{
ani.SetInteger("state", 1);//当鹰和鸡距离小于10f,鸡转成跑的动画
}
else
{
ani.SetInteger("state", 0);//否则鸡采取走的动画
}
float dis = Vector3.Distance(this.transform.position, paths[n].position);
if(dis < 0.10f)
{
n++;
if (n == 6)
{
n = 0;
}
this.transform.LookAt(paths[n]);
this.transform.Rotate(new Vector3(0, 180, 0));
}
}
}
之所以你写的脚本可以起作用是因为作者已经帮你写了itween.cs,截个图略表敬意,源码请自己研究
晒出效果图:
然后我又导进去两种鸭子和公鸡,下面晒出效果图
当然了itweenPath简单易用,但是凡事都有两面性,一旦你需要很多个角色都使用itweenPath游戏会卡。所以还是自己代码实现吧。
最后我把自己用地形编辑器编辑的地形截几张美图和大家分享