开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

蛮牛译馆

关注:609

当前位置:游戏蛮牛 技术专区 蛮牛译馆

查看: 1578|回复: 21

[Unity教程] 如何在Unity中优化敌军死亡动画

[复制链接]  [移动端链接]
排名
8489
昨日变化

263

主题

301

帖子

1538

积分

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

UID
159865
好友
9
蛮牛币
3979
威望
0
注册时间
2016-8-1
在线时间
626 小时
最后登录
2017-11-19

蛮牛译员

发表于 2017-8-11 12:14:12 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 manew_JR 于 2017-8-11 12:15 编辑

如何在Unity中优化敌军死亡动画
002.png 001.png
你好,我们是一个小型的独立游戏工作室,被称为“醉酒星期一”。
我们最近在上做了一个游戏,你在一个竞技场里跑来跑去,用巨大的斧头绕着你自己旋转,并试图攻击其他玩家。Good smash - good kill.
我们使用基于物理的ragdoll动画来让死亡看起来更逼真。开始的时候一切都很好。

然而,当人物和计算的数量开始增长时,游戏开始缓慢而落后于旧手机。禁用所有物理计算给了我们50 - 60个fps和绝对平滑度,但我们不想放弃角色的酷炫死亡画面。

其中一个解决方案是强迫animator制作一组死亡动画。但是我们有一个好主意,把一些布娃娃的死亡直接记录在Unity中,然后显示出想要的动画?死亡将会变得多样化,不需要占据animator,最重要的是——一切都会很快,美丽和现实。

我们最终的效果

003.gif


实现

Unity中的动画剪辑由Clip类提供,该类包含一个AnimationCurve数组。AnimationCurve为特定对象的某一特定属性的更改定义了曲线,例如,localPosition.x。时间轴上的值变化由一些关键帧结构描述。
004.png

这个想法很简单:对于每个字符对象的每个属性,我们创建一个AnimationCurve并将该属性的值存储在每个框架的曲线上。生成的AnimationClip通过AssetDatabase导出。最后生成CreateAsset。

让我们创建类AnimationRecorderItem来跟踪每个字符对象。监视对象的所有属性都将通过字典来描述,其中键是属性的名称,值是动画曲线。


[C#] 纯文本查看 复制代码
Properties = new Dictionary<string, AnimationCurve> ();
 
Properties.Add ( "localPosition.x", new AnimationCurve () );
Properties.Add ( "localPosition.y", new AnimationCurve () );
Properties.Add ( "localPosition.z", new AnimationCurve () );
 
Properties.Add ( "localRotation.x", new AnimationCurve () );
Properties.Add ( "localRotation.y", new AnimationCurve () );
Properties.Add ( "localRotation.z", new AnimationCurve () );
Properties.Add ( "localRotation.w", new AnimationCurve () );
 
Properties.Add ( "localScale.x", new AnimationCurve () );
Properties.Add ( "localScale.y", new AnimationCurve () );
Properties.Add ( "localScale.z", new AnimationCurve () );


对于每个框架中的所有对象属性,都将设置它们的当前值:


[C#] 纯文本查看 复制代码
Properties["localPosition.x"].AddKey (new Keyframe (time, _animObj.localPosition.x, 0.0f, 0.0f));
Properties["localPosition.y"].AddKey (new Keyframe (time, _animObj.localPosition.y, 0.0f, 0.0f));
Properties["localPosition.z"].AddKey (new Keyframe (time, _animObj.localPosition.z, 0.0f, 0.0f));

Properties["localRotation.x"].AddKey (new Keyframe (time, _animObj.localRotation.x, 0.0f, 0.0f));
Properties["localRotation.y"].AddKey (new Keyframe (time, _animObj.localRotation.y, 0.0f, 0.0f));
Properties["localRotation.z"].AddKey (new Keyframe (time, _animObj.localRotation.z, 0.0f, 0.0f));
Properties["localRotation.w"].AddKey (new Keyframe (time, _animObj.localRotation.w, 0.0f, 0.0f));

Properties["localScale.x"].AddKey (new Keyframe (time, _animObj.localScale.x, 0.0f, 0.0f));
Properties["localScale.y"].AddKey (new Keyframe (time, _animObj.localScale.y, 0.0f, 0.0f));
Properties["localScale.z"].AddKey (new Keyframe (time, _animObj.localScale.z, 0.0f, 0.0f));



但是,如果您为每个对象的每个属性记录每个帧的所有值,那么动画的输出文件将会变得太大。让我们介绍一下限制最小变化的条件与前面的框架相比。如果对象移动了,增加和转动了一点,我们将不会记录这些变化。


另外,我们还需要创建一个manager类 —AnimationRecorder.。

这个脚本应该通过动画对象的所有子元素执行,并为每个对象创建一个animation记录器的实例。
同时,它还会立即生成并记住它将被保存在AnimationClip中的相对路径。


根据文档,相对路径生成如下:

Quote
这条曲线适用于游戏对象的路径。相对路径的格式类似于pathname。e.g. "root/spine/leftArm". 如果相对路径为空,则表示动画剪辑所附的游戏对象。


代码将会是:

[C#] 纯文本查看 复制代码
private List<AnimationRecorderItem> _recorders;
 
void Start ()
{
    Configurate ();
}
 
void Configurate ()
{
    _recorders = new List<AnimationRecorderItem> ();
 
    var allTransforms = gameObject.GetComponentsInChildren< Transform > ();
    for ( int i = 0; i < allTransforms.Length; ++i )
    {
        string path = CreateRelativePathForObject ( transform, allTransforms [ i ] );
        _recorders.Add( new AnimationRecorderItem ( path, allTransforms [ i ] ) );
    }
}
 
private string CreateRelativePathForObject ( Transform root, Transform target )
{
    if ( target == root )
    {
        return string.Empty;
    }
 
    string name = target.name;
    Transform bufferTransform = target;
 
    while ( bufferTransform.parent != root )
    {
        name = string.Format ( "{0}/{1}", bufferTransform.parent.name, name );
        bufferTransform = bufferTransform.parent;
    }
    return name;
}
 



计算当前动画时间并记录每个帧的属性值:

[C#] 纯文本查看 复制代码
private float _recordingTimer;
private bool _recording = false;
 
void Update ()
{
 
    if ( _recording )
    {
        for ( int i = 0; i < _recorders.Count; ++i )
        {
            _recorders [ i ].AddFrame ( _recordingTimer );
        }
        _recordingTimer += Time.deltaTime;
    }
}


但是更新函数经常被调用,并且记录动画的每一个帧都是冗余的,所以我们限制了记录。每个人都应该有30个fps。


我们将通过在空格键上敲打来开始记录。

[C#] 纯文本查看 复制代码
private const float CAPTURING_INTERVAL = 1.0f / 30.0f;
 
private float _lastCapturedTime;
private float _recordingTimer;
private bool _recording = false;
 
void Update ()
{
    if ( Input.GetKeyDown ( KeyCode.Space ) && !_recording )
    {
        StartRecording ();
        return;
    }
 
    if ( _recording )
    {
        if (_recordingTimer==0.0f||_recordingTimer-_lastCapturedTime>=CAPTURING_INTERVAL)
        {
            for ( int i = 0; i < _recorders.Count; ++i )
            {
                _recorders [ i ].AddFrame ( _recordingTimer );
            }
            _lastCapturedTime = _recordingTimer;
        }
        _recordingTimer += Time.deltaTime;
    }
}
 
public void StartRecording ()
{
    Debug.Log ( "AnimationRecorder recording started" );
    _recording = true;
}



让我们实现一个动画导出。我们将创建AnimationClip实例并将其填充为所收集的值。

[C#] 纯文本查看 复制代码
private void ExportAnimationClip ()
{
    AnimationClip clip = new AnimationClip ();
    for ( int i = 0; i < _recorders.Count; ++i )
    {
        Dictionary<string,AnimationCurve> propertiles = _recorders [ i ].Properties;
        for ( int j = 0; j < propertiles.Count; ++j )
        {
            string name = _recorders [ i ].PropertyName;
            string propery = propertiles.ElementAt ( j ).Key;
            var curve = propertiles.ElementAt ( j ).Value;
            clip.SetCurve ( name, typeof(Transform), propery, curve );
        }
    }
    clip.EnsureQuaternionContinuity ();
 
    string path = "Assets/" + gameObject.name + ".anim";
    AssetDatabase.CreateAsset ( clip, path );
    Debug.Log ( "AnimationRecorder saved to = " + path );
}




最后,我们将创建AnimationRecorderRagdollHelper助手类,该函数将停止动画的动画对象,打开所有的碰撞,给物体加速度,开始记录我们的动画。动画录制的结束将由我们自己完成。

为了避免场景加载和各种对象的初始化,脚本将开始处理指定的延迟。


这就是所有的教程,我们添加AnimationRecorderRagdollHelper性格,冲击力,然后开始现场,观察人物高高兴兴地飞来飞去。

当冰冷的尸体在地面上结冰时,按下空格键。
008.gif


脚本将我们的动画输出到项目的根。

009.png
010.gif




我们以这种方式为每个角色录制4 - 5个动画,并在角色死亡时随机选择。





原文标题:How We Optimized Ragdoll Death Animation in Unity









评分

参与人数 1鲜花 +2 收起 理由
634948676 + 2 赞一个!

查看全部评分

本帖被以下淘专辑推荐:


回复

使用道具 举报

7日久生情
2054/5000
排名
1399
昨日变化
11

36

主题

624

帖子

2054

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
69941
好友
1
蛮牛币
6463
威望
0
注册时间
2015-1-20
在线时间
632 小时
最后登录
2018-2-20
发表于 2017-8-11 12:31:52 | 显示全部楼层
很厉害的样子,马克一下。。。。。。。。。

回复 支持 反对

使用道具 举报

5熟悉之中
618/1000
排名
4953
昨日变化

6

主题

243

帖子

618

积分

Rank: 5Rank: 5

UID
176358
好友
0
蛮牛币
271
威望
0
注册时间
2016-11-4
在线时间
131 小时
最后登录
2018-2-2
发表于 2017-8-11 13:40:53 | 显示全部楼层
{:106:}{:106:}

回复

使用道具 举报

7日久生情
2226/5000
排名
862
昨日变化

5

主题

437

帖子

2226

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
46577
好友
1
蛮牛币
2655
威望
0
注册时间
2014-9-24
在线时间
780 小时
最后登录
2018-2-9
发表于 2017-8-11 14:10:09 | 显示全部楼层
厉害,这个很实用,这让我想到了骑砍里的布娃娃选项里就有限定数量和无限数量
[发帖际遇]: llupll 捡了钱没交公 蛮牛币 降了 2 . 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

5熟悉之中
502/1000
排名
4147
昨日变化
1

0

主题

58

帖子

502

积分

Rank: 5Rank: 5

UID
159593
好友
0
蛮牛币
1070
威望
0
注册时间
2016-7-30
在线时间
152 小时
最后登录
2018-2-11
发表于 2017-8-11 14:42:21 | 显示全部楼层
那么腻害

回复

使用道具 举报

3偶尔光临
295/300
排名
9216
昨日变化

0

主题

124

帖子

295

积分

Rank: 3Rank: 3Rank: 3

UID
190613
好友
0
蛮牛币
11
威望
0
注册时间
2016-12-8
在线时间
72 小时
最后登录
2017-9-28
发表于 2017-8-11 15:36:52 | 显示全部楼层
很厉害的样子,马克一下。。。。。

回复 支持 反对

使用道具 举报

7日久生情
2428/5000
排名
468
昨日变化
2

1

主题

321

帖子

2428

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
2219
好友
1
蛮牛币
6067
威望
0
注册时间
2013-8-19
在线时间
768 小时
最后登录
2018-2-19
发表于 2017-8-11 19:34:50 | 显示全部楼层
很厉害的样子

回复

使用道具 举报

4四处流浪
340/500
排名
7455
昨日变化
1

2

主题

138

帖子

340

积分

Rank: 4

UID
85086
好友
2
蛮牛币
345
威望
0
注册时间
2015-3-26
在线时间
71 小时
最后登录
2018-2-1
发表于 2017-8-11 21:49:23 | 显示全部楼层
啊啊啊啊啊阿啊啊啊啊啊啊啊啊啊啊啊

回复 支持 反对

使用道具 举报

4四处流浪
314/500
排名
5344
昨日变化

0

主题

12

帖子

314

积分

Rank: 4

UID
231194
好友
0
蛮牛币
1018
威望
0
注册时间
2017-7-10
在线时间
86 小时
最后登录
2018-2-8
发表于 2017-8-12 08:26:15 | 显示全部楼层
[发帖际遇]: 简简单单happy 在论坛发帖时没有注意,被小偷偷去了 2 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

7日久生情
1674/5000
排名
1850
昨日变化

16

主题

491

帖子

1674

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
182832
好友
7
蛮牛币
7251
威望
0
注册时间
2016-11-11
在线时间
609 小时
最后登录
2018-2-9
发表于 2017-8-12 09:22:40 | 显示全部楼层
感谢分享

回复

使用道具 举报

5熟悉之中
559/1000
排名
4412
昨日变化
36

1

主题

194

帖子

559

积分

Rank: 5Rank: 5

UID
233607
好友
1
蛮牛币
927
威望
0
注册时间
2017-7-22
在线时间
94 小时
最后登录
2018-2-19
发表于 2017-8-12 10:15:17 | 显示全部楼层
大神的诞生,小白表示很崇拜
[发帖际遇]: 一个袋子砸在了 2695648715 头上,2695648715 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

5熟悉之中
749/1000
排名
2715
昨日变化
1

4

主题

77

帖子

749

积分

Rank: 5Rank: 5

UID
127539
好友
0
蛮牛币
3477
威望
0
注册时间
2015-11-1
在线时间
222 小时
最后登录
2017-11-8
QQ
发表于 2017-8-12 14:34:09 | 显示全部楼层
mark,666666666666666

回复 支持 反对

使用道具 举报

排名
17967
昨日变化

0

主题

34

帖子

83

积分

Rank: 2Rank: 2

UID
223971
好友
1
蛮牛币
78
威望
0
注册时间
2017-5-27
在线时间
25 小时
最后登录
2017-11-8
发表于 2017-8-14 08:53:29 | 显示全部楼层
animation?

回复

使用道具 举报

7日久生情
3790/5000
排名
4176
昨日变化

5

主题

3129

帖子

3790

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
209186
好友
5
蛮牛币
4574
威望
0
注册时间
2017-3-1
在线时间
366 小时
最后登录
2018-1-26
发表于 2017-8-14 09:29:31 | 显示全部楼层
这自己做的动画不必特效差啊

回复 支持 反对

使用道具 举报

排名
30354
昨日变化
3

1

主题

37

帖子

69

积分

Rank: 2Rank: 2

UID
165351
好友
0
蛮牛币
92
威望
0
注册时间
2016-9-1
在线时间
23 小时
最后登录
2017-12-22
发表于 2017-8-14 09:43:00 | 显示全部楼层
顶一个。。。。。。。。。。。。。。。。。。。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

关闭

站长推荐 上一条 /1 下一条

快速回复 返回顶部 返回列表