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

扫一扫,访问微社区

蛮牛译馆

关注:553

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

查看: 630|回复: 17

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

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

213

主题

250

帖子

1362

积分

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

UID
159865
好友
9
蛮牛币
3259
威望
0
注册时间
2016-8-1
在线时间
597 小时
最后登录
2017-8-17

蛮牛译员

发表于 7 天前 | 显示全部楼层 |阅读模式

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

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

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日久生情
1553/5000
排名
2035
昨日变化
6

26

主题

520

帖子

1553

积分

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

UID
69941
好友
1
蛮牛币
5333
威望
0
注册时间
2015-1-20
在线时间
483 小时
最后登录
2017-8-17
发表于 7 天前 | 显示全部楼层
很厉害的样子,马克一下。。。。。。。。。

回复 支持 反对

使用道具 举报

4四处流浪
390/500
排名
6802
昨日变化
64

3

主题

176

帖子

390

积分

Rank: 4

UID
176358
好友
0
蛮牛币
39
威望
0
注册时间
2016-11-4
在线时间
75 小时
最后登录
2017-8-17
发表于 7 天前 | 显示全部楼层
{:106:}{:106:}

回复

使用道具 举报

7日久生情
1904/5000
排名
1012
昨日变化
3

3

主题

394

帖子

1904

积分

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

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

回复 支持 反对

使用道具 举报

排名
13864
昨日变化
370

0

主题

10

帖子

71

积分

Rank: 2Rank: 2

UID
159593
好友
0
蛮牛币
171
威望
0
注册时间
2016-7-30
在线时间
25 小时
最后登录
2017-8-17
发表于 7 天前 | 显示全部楼层
那么腻害

回复

使用道具 举报

3偶尔光临
212/300
排名
10758
昨日变化
6

0

主题

108

帖子

212

积分

Rank: 3Rank: 3Rank: 3

UID
190613
好友
0
蛮牛币
99
威望
0
注册时间
2016-12-8
在线时间
42 小时
最后登录
2017-8-17
发表于 7 天前 | 显示全部楼层
很厉害的样子,马克一下。。。。。

回复 支持 反对

使用道具 举报

7日久生情
1934/5000
排名
643
昨日变化

1

主题

241

帖子

1934

积分

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

UID
2219
好友
1
蛮牛币
4853
威望
0
注册时间
2013-8-19
在线时间
632 小时
最后登录
2017-8-16
发表于 7 天前 | 显示全部楼层
很厉害的样子

回复

使用道具 举报

3偶尔光临
274/300
排名
9378
昨日变化
121

3

主题

150

帖子

274

积分

Rank: 3Rank: 3Rank: 3

UID
85086
好友
2
蛮牛币
270
威望
0
注册时间
2015-3-26
在线时间
41 小时
最后登录
2017-8-17
发表于 7 天前 | 显示全部楼层
啊啊啊啊啊阿啊啊啊啊啊啊啊啊啊啊啊

回复 支持 反对

使用道具 举报

排名
10940
昨日变化
160

0

主题

3

帖子

89

积分

Rank: 2Rank: 2

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

回复

使用道具 举报

6蛮牛粉丝
1207/1500
排名
2943
昨日变化
15

15

主题

456

帖子

1207

积分

Rank: 6Rank: 6Rank: 6

UID
182832
好友
6
蛮牛币
5185
威望
0
注册时间
2016-11-11
在线时间
410 小时
最后登录
2017-8-17
发表于 6 天前 | 显示全部楼层
感谢分享

回复

使用道具 举报

3偶尔光临
198/300
排名
15494
昨日变化
505

1

主题

145

帖子

198

积分

Rank: 3Rank: 3Rank: 3

UID
233607
好友
0
蛮牛币
40
威望
0
注册时间
2017-7-22
在线时间
24 小时
最后登录
2017-8-17

一贫如洗

发表于 6 天前 | 显示全部楼层
大神的诞生,小白表示很崇拜
[发帖际遇]: 一个袋子砸在了 2695648715 头上,2695648715 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

5熟悉之中
572/1000
排名
3377
昨日变化
1

4

主题

72

帖子

572

积分

Rank: 5Rank: 5

UID
127539
好友
0
蛮牛币
2867
威望
0
注册时间
2015-11-1
在线时间
172 小时
最后登录
2017-8-16
QQ
发表于 6 天前 | 显示全部楼层
mark,666666666666666

回复 支持 反对

使用道具 举报

排名
24190
昨日变化
2631

0

主题

18

帖子

44

积分

Rank: 1

UID
223971
好友
0
蛮牛币
21
威望
0
注册时间
2017-5-27
在线时间
16 小时
最后登录
2017-8-17
发表于 4 天前 | 显示全部楼层
animation?

回复

使用道具 举报

5熟悉之中
876/1000
排名
9505
昨日变化
121

4

主题

694

帖子

876

积分

Rank: 5Rank: 5

UID
209186
好友
0
蛮牛币
1458
威望
0
注册时间
2017-3-1
在线时间
100 小时
最后登录
2017-8-17
发表于 4 天前 | 显示全部楼层
这自己做的动画不必特效差啊

回复 支持 反对

使用道具 举报

排名
30594
昨日变化
62

2

主题

40

帖子

69

积分

Rank: 2Rank: 2

UID
165351
好友
0
蛮牛币
81
威望
0
注册时间
2016-9-1
在线时间
21 小时
最后登录
2017-8-16
发表于 4 天前 | 显示全部楼层
顶一个。。。。。。。。。。。。。。。。。。。

回复

使用道具 举报

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

本版积分规则

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