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

  

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

  

  相关主要代码:  

    //根据一条线的上一个节点,确定这个节点如何定位
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 * );
var hitDown = false;
//如果前面没有挡住,检查垂直位置
if (!hitForward)
{
//height用来控制垂直扩展的高度
var upPos = pos + * forward * radius + up * height * ;
//Debug.DrawRay(upPos, -up, Color.green, 100);
hitDown = Physics.Raycast(upPos, -up, out hit, height * );
}
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表示扩展多少层,层数越多,我们每条线的相隔的角度也应该越小,如下效果。

  

  相关代码:  

    //分成多条线向外扩散
public void extend()
{
//分成多条线
count = (int)( * level * Mathf.PI);
//每条偏移角度
angle = 360.0f / count;
var up = transform.rotation * Vector3.up;
for (int i = ; 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 = ; 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, );
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

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

  

  相关代码:  

    //确定当前层上的某个位置是否需要生成
bool bCreate(int level, int place)
{
//当前需要显示的个数
var levelCount = (int)( * level * Mathf.PI);
var levelLength = Mathf.RoundToInt((float)count / levelCount);
//每层起点偏移一点位置
var offset = place + level;
return offset % levelLength == ;
}

bCreate

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

  

  如下是完整代码:  

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 = ;
[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)( * level * Mathf.PI);
//每条偏移角度
angle = 360.0f / count;
var up = transform.rotation * Vector3.up;
for (int i = ; 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 = ; 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, );
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)( * level * Mathf.PI);
var levelLength = Mathf.RoundToInt((float)count / levelCount);
//每层起点偏移一点位置
var offset = place + level;
return offset % levelLength == ;
}
public GameObject getPrefab(int curLevel)
{
var prfabCount = particlePrefabs.Length;
//var t = Mathf.RoundToInt(prfabCount * (curLevel - 1) / level);
var index = Random.Range(, 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 - * 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 * );
var hitDown = false;
//如果前面没有挡住,检查垂直位置
if (!hitForward)
{
//height用来控制垂直扩展的高度
var upPos = pos + * forward * radius + up * height * ;
//Debug.DrawRay(upPos, -up, Color.green, 100);
hitDown = Physics.Raycast(upPos, -up, out hit, height * );
}
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里的火焰效果的更多相关文章

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

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  2. js模仿jquery里的几个方法parent, parentUntil, children

    有时工作需要, 也是接着上一章的方法, 用js模仿jquery里的几个方法parent, parentUntil, children. function parent(node){ return no ...

  3. unity, 在OnDisable里一定要将Cloth禁掉

    如果在OnDisable中不将Cloth组件禁掉,则当物体再次激活时布料将变形.

  4. js模仿jquery里的几个方法next, pre, nextAll, preAll

    /*siblings函数, 选取node的所有兄弟节点*/ function siblings(node){ if(node.nodeType === 1){ node.flag = true; // ...

  5. 模仿jq里的选择器和color样式

    (function(){ HTMLElement.prototype.css = function () { var option; if (arguments.length > 0) { op ...

  6. Unity 5 中的全局光照技术详解

    貌似是某位好人翻译的 https://unity3d.com/cn/learn/tutorials/topics/graphics/unity-5-lighting-and-rendering#rd? ...

  7. Unity 5 中的全局光照技术详解(建议收藏)

    本文整理自Unity全球官方网站,原文:UNITY 5 - LIGHTING AND RENDERING (文章较长,请耐心阅读)简介全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法, ...

  8. Unity 5--全局光照技术

    本文整理自Unity全球官方网站,原文:UNITY 5 - LIGHTING AND RENDERING 简介全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法,要精确的仿真全局光照非常 ...

  9. 04、Unity 5--全局光照技术

    本文整理自Unity全球官方网站,原文:UNITY 5 - LIGHTING AND RENDERING 简介全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法,要精确的仿真全局光照非常 ...

随机推荐

  1. Google的Bigtable学习笔记(不保证正确性)

    跪求各路大侠指正:1.首先是一个列式存储的简单数据模型的数据库,它比键值对模型/文档模型NoSQL数据库复杂点(也就更强一点).2.它的分布式存储性能依靠于GFS也就对单机房网络有硬性指标.3.它同时 ...

  2. 微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题

    微信多图片上传必须挨个上传,也就是不能并行,得串行: 那么我们可以定义一个如下所示的上传函数: var serverIds = []; function uploadImages(localImage ...

  3. 20 个免费的 Bootstrap 的后台管理模板

    之前 OSC 曾经发过多个后台管理界面模板的推荐,例如: 50 个漂亮的后台管理界面模板 25 个精美的后台管理界面模板和布局 分享 6 套超酷的后台管理员界面网站模板 30个优秀的后台管理界面设计案 ...

  4. 使用Immutable优化复制

    Orleans有一个降低请求消息序列化开销的功能,这里将首先介绍序列化的工作方式,并解释如何使用这个降低开销的功能 Orleans中的Serialization 当在Orleans中发起一个对grai ...

  5. 39行代码实现JS HTML模板(轻量+高效+易用)

    otmpl 是一个轻量级前端模版(仅有39行无压缩代码,支持缓存),所用指令仅需[#...#]和{#...#},前者包含需要输出html语句,后者包含js变量. 支持javascript完整语法,你可 ...

  6. 初学者利用git 上传代码到Coding的简单操作步骤

    1.首先登陆coding网站注册账号https://coding.net/ (注册完后需登陆邮箱激活邮件) 2.登陆刚注册的coding账号 ,添加项目 添加项目—〉输入项目名称—〉输入对项目的简单描 ...

  7. [MFC] MFC音乐播放器 傻瓜级教程 网络 搜索歌曲 下载

    >目录< >——————————————————————< 1.建立工程  1.建立一个MFC工程,命名为Tao_Music 2.选择为基本对话框 3.包含Windows So ...

  8. jQuery document window load ready 区别详解

    用过JavaScript的童鞋,应该知道window对象和document对象,也应该听说过load事件和ready事件,小菜当然也知道,而且自认为很了解,直到最近出了问题,才知道事情并不是那么简单. ...

  9. Beta分布和Dirichlet分布

    在<Gamma函数是如何被发现的?>里证明了\begin{align*} B(m, n) = \int_0^1 x^{m-1} (1-x)^{n-1} \text{d} x = \frac ...

  10. paip..禁用mmseg 的默认词库. . 仅仅使用自定义词库from数据库.

    paip..禁用mmseg 的默认词库. . 仅仅使用自定义词库from数据库. mmseg默认词库只能是文件格式...不好维护..要是不个词库放的个数据库里面走好维护兰.. 要实现2个目标..: 1 ...