用Unity模仿CSGO里的火焰效果

摘要:
CSGO中的火灾效应与真实情况相似。它可以沿着掩体移动。以下是模仿效果。如下图所示codes://According到线路的前一节点,确定如何定位节点:boolforward{varforward=quat*Vector3.forward;varup=quat*Vector3.up;varnextPos=pos+forward*radius;RaycastHitit;//前端是否被阻止//Debug.DrawRay;varhitForward=Physical.Raycast;varhitDown=false;//如果前端未被阻止,请检查垂直位置,如果(!HitForward){//height用于控制垂直扩展的高度varupPos=pos+2*前*半径+up*height*2;//Debug.DrawRay;hitDown=Physics.Raycast;}如果{//新位置pos=hit.point+hit.normal*preabHeight;//Debug.DrawRay;quat=Quaternation.FromToRotation*quat;returntrue;}returnfalse;}转发上面代码的每个句子都有注释。我们添加一个半径参数来指示每个前进的步长。半径越小,密度越大。然后我们添加一个高度参数来指示垂直提升能力,如下图所示。

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

  用Unity模仿CSGO里的火焰效果第1张

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

  用Unity模仿CSGO里的火焰效果第2张

  相关主要代码:  

用Unity模仿CSGO里的火焰效果第3张用Unity模仿CSGO里的火焰效果第4张
    //根据一条线的上一个节点,确定这个节点如何定位
    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;
    }
forward

  如上代码每句都加上了注释,我们添加了一个radius参数,用来表示每次前进的步子大小,radius越小,则越密集,然后添加一个height参数用来表示垂直方向升降能力,可以看下图。

  确定一条线上显示后,我们只要考虑沿着周围全部扩展就行,在这我们用level表示扩展多少层,层数越多,我们每条线的相隔的角度也应该越小,如下效果。

  用Unity模仿CSGO里的火焰效果第5张

  相关代码:  

用Unity模仿CSGO里的火焰效果第3张用Unity模仿CSGO里的火焰效果第7张
    //分成多条线向外扩散
    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;
        }
    }
extend

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

  用Unity模仿CSGO里的火焰效果第8张

  相关代码:  

用Unity模仿CSGO里的火焰效果第3张用Unity模仿CSGO里的火焰效果第10张
    //确定当前层上的某个位置是否需要生成
    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;
    }
bCreate

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

   用Unity模仿CSGO里的火焰效果第11张

  如下是完整代码:  

用Unity模仿CSGO里的火焰效果第3张用Unity模仿CSGO里的火焰效果第13张
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;
    }
}
FireMove

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

免责声明:文章转载自《用Unity模仿CSGO里的火焰效果》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇HTML5 Blob与ArrayBuffer、TypeArray和字符串String之间转换向github项目push代码后,Jenkins实现其自动构建下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[Unity基础]移动平台下的文件读写

From:http://blog.csdn.net/lyh916/article/details/52161633 参考链接: http://www.cnblogs.com/murongxiaopifu/p/4199541.html?utm_source=tuicool#autoid-3-2-0 http://zhaolongchn.blog.163...

Unity之Bmob云存储一

无论我们做软件还是做游戏,少不了的就是和数据打交道,对于要保存到本地的数据,我们可以采用的载体太多了。例如:txt,Xml,Sqlite,SqlServer,Mysql等等,具体使用什么那就视情况而定了。但是假如我们要在游戏中要做一个在线排行榜,我们会怎么解决呢?有些人立刻会想到把数据放到服务器上不就OK了!对的,我也是这么想的!实践才是检验真理的唯一标准...

如何修改iframe内的页面的元素的样式。。。。

方法一: 直接通过设置backgroundColor的颜色即可:<!DOCTYPE html><html><head><script>function changeStyle(){var x=document.getElementById("myframe");var y=(x.contentWindow |...

Unity3D ZFBrowser (EmbeddedBrowser) 插件嵌入网页无法输入中文问题

  网页嵌入插件最好的应该就是ZFBrowser了, 可是使用起来也是问题多多, 现在最要命的是网页输入不能打中文, 作者也没打算接入IME, 只能自己想办法了...   搞了半天只想到一个办法, 就是通过Unity的IME去触发中文输入, 然后传入网页, 也就是说做一个透明的 InputField 盖住网页的输入文本框, 然后在 Update 或是 on...

动画开发之PIXI开发

简单的移动小游戏只要引入pixi.min.js就可以, 如果要用spine动画(龙骨也支持导出spine格式的)就要引入pixi-spine.js 如果还有声音的支持引入pixi-sound.js 学习网址:   - 官网http://www.pixijs.com   - API http://pixijs.download/release/docs/...

unity材质球贴图滚动

using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { //滚动速度 public float HorSpeed = 1.0f;...