unity3d 摄像机跟随角色时被物体遮挡解决方案

在看此文章时请先看上面的参考文章。更多精彩请关注【狗刨学习网】

     看完以上文章后,你也许会想人家都已经给出所有代码了,你还写个毛啊
     别急,现在进入主题

     在我的项目中,我采用的是物体遮挡作半透明处理,如果按照上述文章中的思路来写代码的话,那么结果就是当多个物体遮挡角色时,只有第一个物体会半透明,如图:


      角色被墙和屋顶遮挡住了,但是可以清楚的看见左下角的墙呈半透明状态,而屋顶依旧不透明

      为了解决这个问题,我们不采用上述文章中的 physics.Linecast,在这里我们需要用到 Physics.RaycastAll;使用方法详见圣典

      ok,现在我们开始敲代码

      首先 ,我们引入命名空间 System.Collections.Generic,然后在声明三个需要用到的变量
  1. <font face="新宋体" size="2">using System.Collections.Generic;//引入命名空间

  2. public class MyCamera1 : MonoBehaviour
  3. {
  4.     //观察目标
  5.     public Transform Target;

  6.     //上次碰撞到的物体
  7.     private List<GameObject> lastColliderObject;

  8.     //本次碰撞到的物体
  9.     private List<GameObject> colliderObject;
  10. }</font>
复制代码

       我们需要发射一条射线,这条射线从角色当前位置发射置摄像机的方向

  1. <font face="新宋体" size="2"> /*射线可以从头部起始*/

  2. 3         //这里是计算射线的方向,从主角发射方向是射线机方向
  3. 4         Vector3 aim = Target.position;
  4. 5         //得到方向
  5. 6         Vector3 ve = (Target.position - transform.position).normalized;
  6. 7         float an = transform.eulerAngles.y;
  7. 8         aim -= an * ve;

  8. 10         //在场景视图中可以看到这条射线
  9. 11         //Debug.DrawLine(target.position, aim, Color.red);
  10. 12 
  11. 13         RaycastHit[] hit;
  12. 14         hit = Physics.RaycastAll(Target.position, aim, 100f);//起始位置、方向、距离</font>
复制代码

     射线发送完毕后,我们获取发送射线时碰撞到的所有物体,并且添加进本次碰撞到的物体(colliderObject)变量中

     因为我的地图、护栏碰撞(不可见)、地面碰撞(不可见)是三个模型,也就是说地图本身是没有任何碰撞的

     所以当碰撞到的物体名为护栏或地面时,就不修改其透明度,因为他本身就不可见

     这里我偷懒了,直接判断物体名称,可自行改为判断物体 tag

     当视角旋转的时候,射线有时候会碰撞到角色,所以,我们获取 tag 判断是否碰撞的物体为角色

  1. <font face="新宋体" size="2"> 1         //将 colliderObject 中所有的值添加进 lastColliderObject
  2. 2         for (int i = 0; i < colliderObject.Count; i++)
  3. 3             lastColliderObject.Add(colliderObject[i]);

  4. 5         colliderObject.Clear();//清空本次碰撞到的所有物体
  5. 6         for (int i = 0; i < hit.Length; i++)//获取碰撞到的所有物体
  6. 7         {
  7. 8             if (hit[i].collider.gameObject.name != "Editable Poly 1"//护栏
  8. 9                 && hit[i].collider.gameObject.name != "Editable Poly"//地面
  9. 10                 && hit[i].collider.gameObject.tag != "Player")//角色
  10. 11             {
  11. 12                 //Debug.Log(hit[i].collider.gameObject.name);
  12. 13                 colliderObject.Add(hit[i].collider.gameObject);
  13. 14                 SetMaterialsColor(hit[i].collider.gameObject.renderer, 0.4f);//置当前物体材质透明度
  14. 15             }
  15. 16         }</font>
复制代码

      当获取到所碰撞到的所有物体后,我们要修改他的材质透明度,有些物体有很多材质,不知道怎么解决的请看我下面这个方法:

  1. <font face="新宋体" size="2"> 1     /// 置物体所有材质球颜色 <summary>
  2. 2     /// 置物体所有材质球颜色
  3. 3     /// </summary>
  4. 4     /// <param name="_renderer">材质</param>
  5. 5     /// <param name="Transpa">透明度</param>
  6. 6     private void SetMaterialsColor(Renderer _renderer, float Transpa)
  7. 7     {
  8. 8         //获取当前物体材质球数量
  9. 9         int materialsNumber = _renderer.sharedMaterials.Length;
  10. 10         for (int i = 0; i < materialsNumber; i++)
  11. 11         {
  12. 12             //获取当前材质球颜色
  13. 13             Color color = _renderer.materials[i].color;
  14. 14 
  15. 15             //设置透明度  取值范围:0~1;  0 = 完全透明
  16. 16             color.a = Transpa;
  17. 17 
  18. 18             //置当前材质球颜色
  19. 19             _renderer.materials[i].SetColor("_Color", color);
  20. 20         }
  21. 21     }</font>
复制代码

       如果本次碰撞到的物体存在于上个物体,那么则说明当前物体还处于遮挡角色状态,所以我们赋值为null

  1. <font face="新宋体" size="2"> 1         //上次与本次对比,本次还存在的物体则赋值为null
  2. 2         for (int i = 0; i < lastColliderObject.Count; i++)
  3. 3         {
  4. 4             for (int ii = 0; ii < colliderObject.Count; ii++)
  5. 5             {
  6. 6                 if (colliderObject[ii] != null)
  7. 7                 {
  8. 8                     if (lastColliderObject[i] == colliderObject[ii])
  9. 9                     {
  10. 10                         lastColliderObject[i] = null;
  11. 11                         break;
  12. 12                     }
  13. 13                 }
  14. 14             }
  15. 15         }</font>
复制代码

       还处于遮挡状态的物体已被赋值为null,那么剩下的物体就是没有处于遮挡状态的,所以我们要重置该物体材质为不透明

  1. <font face="新宋体" size="2">1 //当值为null时则可判断当前物体还处于遮挡状态
  2. 2         //值不为null时则可恢复默认状态(不透明)
  3. 3         for (int i = 0; i < lastColliderObject.Count; i++)
  4. 4         {
  5. 5             if (lastColliderObject[i] != null)
  6. 6                 SetMaterialsColor(lastColliderObject[i].renderer, 1f);//恢复上次物体材质透明度
  7. 7         }</font>
复制代码

      好了,所有代码已完成,我们看一下运行结果

      未遮挡时:

         

遮挡时:

         

211731341872056.jpg (91.76 KB, 下载次数: 0)

下载附件  保存到相册

6 小时前 上传


        怎么样,有木有感觉很酷炫呢,哈哈哈
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值