• GJM : 用Unity模仿CSGO里的火焰效果 [转载]


    • 感谢您的阅读。喜欢的、有用的就请大哥大嫂们高抬贵手“推荐一下”吧!你的精神支持是博主强大的写作动力以及转载收藏动力。欢迎转载!
    • 版权声明:本文原创发表于 【请点击连接前往】 ,未经作者同意必须保留此段声明!如有问题请联系我,侵立删,谢谢!
    • 我的博客:http://www.cnblogs.com/GJM6/  -  传送门:【点击前往

    本文章由天天不在编写,转载请注明出处。 所有权利保留。 
    文章链接:http://www.cnblogs.com/zhouxin/p/5910257.html
    作者:天天不在


      CSGO里的火焰效果和真实的情况比较像,能沿着遮挡物前进,如下是模仿效果。

     


      思路比较简单,开始想的是一圈一圈发出去,但是前圈与后圈的联系不好做,换种思路,每个方向发射一条线,这样根据上一个位置的方位先向前进,如果前面有遮挡,则计算好新的位置与方向,反之前面没有遮挡,选择合适的位置,并从这个方向的上面向下检测,检测这个方向的垂直位置有没遮挡,如果有遮挡,计算新的方向与位置,没有,则表明延展不下去。如下图所示.


      相关主要代码:  

    [AppleScript] 纯文本查看 复制代码
     
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    //根据一条线的上一个节点,确定这个节点如何定位
        bool forward(ref Vector3 pos, ref Quaternion quat)
        {
            var forward = quat * Vector3.forward;
            var up = quat * Vector3.up;
     
            var nextPos = pos + forward * radius;
            RaycastHit hit;
            //前面有没挡住
            //Debug.DrawRay(nextPos, forward, Color.red, 100);
            var hitForward = Physics.Raycast(nextPos, forward, out hit, radius * 2);
            var hitDown = false;
            //如果前面没有挡住,检查垂直位置
            if (!hitForward)
            {
                //height用来控制垂直扩展的高度
                var upPos = pos + 2 * forward * radius + up * height * 2;
                //Debug.DrawRay(upPos, -up, Color.green, 100);
                hitDown = Physics.Raycast(upPos, -up, out hit, height * 4);
            }
            if (hitForward || hitDown)
            {
                //新的位置
                pos = hit.point + hit.normal * prefabHeight;
                //Debug.DrawRay(pos, hit.normal, Color.blue, 100);
                quat = Quaternion.FromToRotation(up, hit.normal) * quat;
                return true;
            }
            return false;
        }


      如上代码每句都加上了注释,我们添加了一个radius参数,用来表示每次前进的步子大小,radius越小,则越密集,然后添加一个height参数用来表示垂直方向升降能力,可以看下图。
      确定一条线上显示后,我们只要考虑沿着周围全部扩展就行,在这我们用level表示扩展多少层,层数越多,我们每条线的相隔的角度也应该越小,如下效果。


     


      相关代码:  

    [AppleScript] 纯文本查看 复制代码
     
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    //分成多条线向外扩散
        public void extend()
        {
            //分成多条线
            count = (int)(2 * level * Mathf.PI);
            //每条偏移角度
            angle = 360.0f / count;
            var up = transform.rotation * Vector3.up;
            for (int i = 0; i < count; i++)
            {
                var curAngle = angle * i;
                var curQuat = Quaternion.AngleAxis(curAngle, up);
                var quat = curQuat * transform.rotation;
                //forward(transform.position, quat, level, i);
                StartCoroutine(forward(transform.position, quat, level, i));
            }
        }
     
        //每条线向前扩展,自动翻越遮挡
        public IEnumerator forward(Vector3 pos, Quaternion quat, int level, int place)
        {
            var npos = pos;
            var nquat = quat;
            int curLevel = 1;
     
            var prePos = npos;
            while (curLevel <= level && forward(ref npos, ref nquat))
            {
                //Debug.DrawLine(prePos, npos, Color.blue, 100f, true);
                if (bCreate(curLevel, place))
                {
                    var offset = offsetPos(nquat, 1);
                    var obj = Instantiate(getPrefab(curLevel), npos + offset, nquat);
                    //Debug.DrawLine(prePos, npos, Color.blue, 100f, true);
                    var duration = getDuration(curLevel);
                    Destroy(obj, duration);
                }
                yield return new WaitForSeconds(deltaTime);
                curLevel++;
                prePos = npos;
            }
        }


      这些蓝线确定了火焰沿线步局,但是现在最中心会比较密集,我们需要有选择的是否生成,如下图:

     


      相关代码:  

    [AppleScript] 纯文本查看 复制代码
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //确定当前层上的某个位置是否需要生成
        bool bCreate(int level, int place)
        {
            //当前需要显示的个数
            var levelCount = (int)(2 * level * Mathf.PI);
            var levelLength = Mathf.RoundToInt((float)count / levelCount);
            //每层起点偏移一点位置
            var offset = place + level;
            return offset % levelLength == 0;
        }


      这样就能简单在每层生成合适的个数,其中最上面有个prefabHeight,用来控制模型中心与下边的高度,用来控制生成的模型贴着遮挡物,如图:


     


      如下是完整代码:  

    [AppleScript] 纯文本查看 复制代码
     
    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    024
    025
    026
    027
    028
    029
    030
    031
    032
    033
    034
    035
    036
    037
    038
    039
    040
    041
    042
    043
    044
    045
    046
    047
    048
    049
    050
    051
    052
    053
    054
    055
    056
    057
    058
    059
    060
    061
    062
    063
    064
    065
    066
    067
    068
    069
    070
    071
    072
    073
    074
    075
    076
    077
    078
    079
    080
    081
    082
    083
    084
    085
    086
    087
    088
    089
    090
    091
    092
    093
    094
    095
    096
    097
    098
    099
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    using UnityEngine;
    using System.Collections;
     
    public class FireMove : MonoBehaviour
    {
        public GameObject[] particlePrefabs;
        [Tooltip("半径越小,模型越密集")]
        public float radius = 0.5f;
        [Tooltip("高度越大,模型能越过更高的遮挡物")]
        public float height = 0.5f;
        [Tooltip("层级越多,向外扩展的导数越多")]
        public int level = 10;
        [Tooltip("每层间隔生成时间")]
        public float deltaTime = 0.1f;
        [Tooltip("控制火焰显示时间")]
        public float duration = 5.0f;
        [Tooltip("水平偏移")]
        public float offsetHeight = 0.1f;
        [Tooltip("高度偏移")]
        public float offsetPanel = 0.2f;
        [Tooltip("模型与地面的距离")]
        public float prefabHeight = 0.01f;
     
        private int count;
        private float angle;
     
    #if UNITY_EDITOR      
        public void Update()
        {
            if (Input.GetKeyDown(KeyCode.K))
            {
                extend();
            }
        }
    #endif
     
        public void attack(int level)
        {
            this.level = level;
            extend();
        }
     
        //分成多条线向外扩散
        public void extend()
        {
            //分成多条线
            count = (int)(2 * level * Mathf.PI);
            //每条偏移角度
            angle = 360.0f / count;
            var up = transform.rotation * Vector3.up;
            for (int i = 0; i < count; i++)
            {
                var curAngle = angle * i;
                var curQuat = Quaternion.AngleAxis(curAngle, up);
                var quat = curQuat * transform.rotation;
                //forward(transform.position, quat, level, i);
                StartCoroutine(forward(transform.position, quat, level, i));
            }
        }
     
        //每条线向前扩展,自动翻越遮挡
        public IEnumerator forward(Vector3 pos, Quaternion quat, int level, int place)
        {
            var npos = pos;
            var nquat = quat;
            int curLevel = 1;
     
            var prePos = npos;
            while (curLevel <= level && forward(ref npos, ref nquat))
            {
                //Debug.DrawLine(prePos, npos, Color.blue, 100f, true);
                if (bCreate(curLevel, place))
                {
                    var offset = offsetPos(nquat, 1);
                    var obj = Instantiate(getPrefab(curLevel), npos + offset, nquat);
                    //Debug.DrawLine(prePos, npos, Color.blue, 100f, true);
                    var duration = getDuration(curLevel);
                    Destroy(obj, duration);
                }
                yield return new WaitForSeconds(deltaTime);
                curLevel++;
                prePos = npos;
            }
        }
     
        //确定当前层上的某个位置是否需要生成
        bool bCreate(int level, int place)
        {
            //当前需要显示的个数
            var levelCount = (int)(2 * level * Mathf.PI);
            var levelLength = Mathf.RoundToInt((float)count / levelCount);
            //每层起点偏移一点位置
            var offset = place + level;
            return offset % levelLength == 0;
        }
        public GameObject getPrefab(int curLevel)
        {
            var prfabCount = particlePrefabs.Length;
            //var t = Mathf.RoundToInt(prfabCount * (curLevel - 1) / level);
            var index = Random.Range(0, prfabCount);
            return particlePrefabs[index];
        }
     
        //加上偏移
        public Vector3 offsetPos(Quaternion quat, int level)
        {
            var xAxis = quat * Vector3.right * Random.Range(-offsetPanel, offsetPanel) * level;
            var zAxis = quat * Vector3.forward * Random.Range(-offsetPanel, offsetPanel) * level;
            var yAxis = quat * Vector3.up * Random.Range(-offsetHeight, offsetHeight) * level;
            return xAxis + zAxis + yAxis;
        }
     
        //每层的生命周期
        float getDuration(int level)
        {
            var levelDuration = duration - 2 * level * deltaTime;
            return levelDuration;
        }
     
        //根据一条线的上一个节点,确定这个节点如何定位
        bool forward(ref Vector3 pos, ref Quaternion quat)
        {
            var forward = quat * Vector3.forward;
            var up = quat * Vector3.up;
     
            var nextPos = pos + forward * radius;
            RaycastHit hit;
            //前面有没挡住
            //Debug.DrawRay(nextPos, forward, Color.red, 100);
            var hitForward = Physics.Raycast(nextPos, forward, out hit, radius * 2);
            var hitDown = false;
            //如果前面没有挡住,检查垂直位置
            if (!hitForward)
            {
                //height用来控制垂直扩展的高度
                var upPos = pos + 2 * forward * radius + up * height * 2;
                //Debug.DrawRay(upPos, -up, Color.green, 100);
                hitDown = Physics.Raycast(upPos, -up, out hit, height * 4);
            }
            if (hitForward || hitDown)
            {
                //新的位置
                pos = hit.point + hit.normal * prefabHeight;
                //Debug.DrawRay(pos, hit.normal, Color.blue, 100);
                quat = Quaternion.FromToRotation(up, hit.normal) * quat;
                return true;
            }
            return false;
        }
    }


      直接放到一个物体上就可以了,其中radius设为相应的火焰半径大小就可,如果要密一些,降低一些就行,相应offset参数用来设定水平与垂直上的偏移,免的给人太规律了,代码上都有详细注释,可以自己改动。

  • 相关阅读:
    window.parent ,window.top,window.self 详解及parent和opener的区别
    jQuery $.extend()用法总结
    JQuery中each()的使用方法说明
    jQuery.isPlainObject()的作用
    change和onchange、click和onclick的区别
    zabbix客户端一键安装脚本(主动模式监控)
    jumpserver在centos 7上的部署
    用阿里云的免费 SSL 证书让网站从 HTTP 换成 HTTPS
    GitLab的安装及使用教程
    一个客户端一键安装环境和服务的shell脚本
  • 原文地址:https://www.cnblogs.com/TDou/p/6098811.html
Copyright © 2020-2023  润新知