Unity发射光线,光线反射详细实现

Unity发射激光,光线被镜子折射详细实现

在这里插入图片描述
最终效果如图所示
在这里插入图片描述

一总体思路

理一下思路,首先关键是用LineRenderer渲染光线,但是LineRenderer需要线的每个点坐标
已知条件:
发射点坐标,发射方向
需要求出:
途中经过的所有点坐标
最终:
将所有点通过代码实时用LineRenderer渲染出来
有了这些其他都是小问题,光线的形状LineRenderer可以设置,发射器的形状自己定义,被反射墙加碰撞体,然后算碰了墙后走的方向,这些都是有函数的,所以现在,开始

二发射器实现

1生成空物体存放发射器和光线

生成空物体,命名LineAndLight(后文统一叫做LineAndLight)下面放发射器和光线,后面算位置就属于同一个坐标系下,空物体位置设置成(0,0,0)以防光线渲染出问题。
在这里插入图片描述
在这里插入图片描述

2 生成2d精灵Sprite

spriteRenderer拖进去发射器图片
在这里插入图片描述

3给发射器挂C#脚本

给发射器挂载脚本,命名Light,具体解释在后面的关键代码解释中
脚本内容如下,这里只说明下 [SerializeField] private GameObject position;这行,需要一个物体代表发射的点,给后面的算法提供发射点的位置,我们在发射器下添加空物体,这里点击这里让空物体显示出来
在这里插入图片描述
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class lightddd: MonoBehaviour
{
    public LineRenderer laser;
    public List<Vector3> laserPoint = new List<Vector3>();
    public LayerMask marrow;
    public   bool hitdoor = false;
    public GameObject shaining;
    [SerializeField] private int reflectNum;
    [SerializeField] private GameObject position;
    
  public enum LightDiraction
    {
        down,
        up,
        right,
        left
    }
    public LightDiraction lightDiraction;
        // Start is called before the first frame update
    void Start()
  {
        laser.gameObject.SetActive(true);
        GameManager.RegistLight(this);
    }

    // Update is called once per frame
    void Update()
    {
      

        CastLaser();
        laser.positionCount = laserPoint.Count;
        laser.SetPositions(laserPoint.ToArray());
    }
    
    void CastLaser()
    {
        laserPoint.Clear();
        //开始的点
        var startPoint = position.transform.position;
      
        //两个关卡不同时,灯泡初始方向不同,所以选择判断改变初始点
        
        //发射方向
        var diraction = new Vector2(0, -1);
switch (lightDiraction)
        {
            case LightDiraction.up:
                {
                     diraction = new Vector2(0, 1);
                    
                    break;
                }
            case LightDiraction.down:
                {
                     diraction = new Vector2(0, -1);
                    
                    break;

                }
            case LightDiraction.right:
            {
           diraction = new Vector2(1, 0);
                   
                    break;
        }
            case LightDiraction.left:
                {
                     diraction = new Vector2(-1, 0);
                    break;
                }

        }
       
       
        //第一个出发点
        laserPoint.Add(startPoint);

        int i = 0;
        do
        {
            RaycastHit2D hit = Physics2D.Raycast(startPoint, diraction,1000f,marrow);
            //添加击中点到路径中,raycast返回值  RaycastHit2D,  RaycastHit2D.point返回接触到碰撞体的表面
            if (hit)
                laserPoint.Add(hit.point);

            //如果击中门,门特效开,hitdoor变量变换,用于胜负判断,击中门的时候跳出while很重要
            if (hit.transform.tag == "door")
            {
                shaining.SetActive(true);
                hitdoor = true;
                break;
            }
            else
            {
                shaining.SetActive(false);

                hitdoor = false;
            }
            //发射方向,RaycastHit2D.normal返回被射线击中的曲面的法向量
            // if(hit.transform.rotation.z==90)
            //    diration = Vector2.Reflect(hit.point - (Vector2)startPoint, -hit.normal);
            // else if(hit.transform.rotation.z == 0)
            
            diraction = Vector2.Reflect(hit.point -(Vector2)startPoint,hit.normal);
           // if (hit.transform.rotation.z == 90)
               // diration = new Vector2(-diration.x, -diration.y);
                startPoint = hit.point+diraction*0.01f;
            i++;
        } while (i < reflectNum)
        ;
            


    }
}

4给发射器加2D碰撞体

在这里插入图片描述
在这里插入图片描述

三光线LineRenderer实现

1新建空物体

在前面的空物体LineAndLight下新建空物体,命名Line
在这里插入图片描述

2添加LineRenderer组件

给Line添加组件LineRenderer
颜色宽度凭自己爱好自己设置
在这里插入图片描述

四折射光线的墙壁实现

你想让什么折射光线就建什么物体,可以加到镜子上,墙壁上,但是最重要的是图层一定要设置,图层设置后在光线的代码里才能检测是否遇到了墙壁
这里建一个四面的墙

1建立空物体命名Wall

在这里插入图片描述

2添加墙壁

墙壁设置图层,加碰撞体
在这里插入图片描述

五关键算法解释

1声明变量解释

   public LineRenderer laser;
    public List<Vector3> laserPoint = new List<Vector3>();
    public LayerMask marrow;
    public   bool hitdoor = false;
    public GameObject shaining;
    [SerializeField] private int reflectNum;
    [SerializeField] private GameObject position;

这些声明的东西都是干嘛的这里讲一下
1 public LineRenderer laser;
这就是绑定刚才的线那个物体
2 public List laserPoint = new List();
这个装坐标的动态数组装所有经过的重要点(折射点,能渲染Line的点)
3 public LayerMask marrow;
绑定图层,用这个图层判断光线是不是碰到墙壁了
4 public bool hitdoor = false;
这是我用来判断是否碰到接收器了,这里对大家没用,如果大家想要加接收器,喜欢我的文章,我后期更新加接收器的
5 public GameObject shaining;
这是我用来让接收器发光的
6 [SerializeField] private int reflectNum;
决定光线折射几次后停止继续被折射
7 [SerializeField] private GameObject position;
绑定初始点,获取位置

2计算点的算法 Physics2D.Raycast,Vector2.Reflect

laserPoint.Clear();

刚开始清空光线走过的点的数组

  var startPoint = position.transform.position;

取到初始点,加入走过的点的数组

        var diraction = new Vector2(0, -1);
switch (lightDiraction)
        {
            case LightDiraction.up:
                {
                     diraction = new Vector2(0, 1);
                    
                    break;
                }
            case LightDiraction.down:
                {
                     diraction = new Vector2(0, -1);
                    
                    break;

                }
            case LightDiraction.right:
            {
           diraction = new Vector2(1, 0);
                   
                    break;
        }
            case LightDiraction.left:
                {
                     diraction = new Vector2(-1, 0);
                    break;
                }

        }

由他的方向得到需要发射的光线方向

 
      
            RaycastHit2D hit = Physics2D.Raycast(startPoint, diraction,1000f,marrow);
            //添加击中点到路径中,raycast返回值  RaycastHit2D,  RaycastHit2D.point返回接触到碰撞体的表面
            if (hit)
                laserPoint.Add(hit.point);

            //如果击中门,门特效开,hitdoor变量变换,用于胜负判断,击中门的时候跳出while很重要
           
            

从初始点出发向指定方向发射,如果击中marrow图层的,返回RaycastHit2D对象hit,这个hit可以取到点,法向量

 diraction = Vector2.Reflect(hit.point -(Vector2)startPoint,hit.normal);

得到发射后的方向 ,RaycastHit2D.normal返回被射线击中的曲面的法向量,Reflect通过传入两个向量,入射向量,法向量,得到出射向量,出射向量作为新方向,击中点作为新的初始点,再循环就行了,前面的reflectNum控制循环几次。

六总代码解释

光线,也就是前面的Line在游戏中要关闭,在代码中打开
重写了下注释

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class lightddd: MonoBehaviour
{
    public LineRenderer laser;
    public List<Vector3> laserPoint = new List<Vector3>();
    public LayerMask marrow;
    public   bool hitdoor = false;
    public GameObject shaining;
    [SerializeField] private int reflectNum;
    [SerializeField] private GameObject position;
       //创建枚举状态控制发射方向
  public enum LightDiraction
    {
        down,
        up,
        right,
        left
    }
    //生成枚举类型对象
    public LightDiraction lightDiraction;
    //设置光线为打开状态
           void Start()
    {
        laser.gameObject.SetActive(true);
        GameManager.RegistLight(this);
    }
    void Update()
    {
      CastLaser();
//设置LineRenderer的关键点为我们算出来的点
        laser.positionCount = laserPoint.Count;
        laser.SetPositions(laserPoint.ToArray());
    }
    
    void CastLaser()
    {
        laserPoint.Clear();
        //开始的点
        var startPoint = position.transform.position;
      
        //两个关卡不同时,灯泡初始方向不同,所以选择判断改变初始点
        
        //发射方向
        var diraction = new Vector2(0, -1);
switch (lightDiraction)
        {
            case LightDiraction.up:
                {
                 diraction = new Vector2(0, 1);                  
                 break;
                }
            case LightDiraction.down:
                {
                 diraction = new Vector2(0, -1);                   
                 break;
                }
            case LightDiraction.right:
                {
                diraction = new Vector2(1, 0);
                break;
                 }
            case LightDiraction.left:
                {
                 diraction = new Vector2(-1, 0);
                 break;
                }
        }      
        //第一个出发点
        laserPoint.Add(startPoint);
        int i = 0;
        do
        {
            RaycastHit2D hit = Physics2D.Raycast(startPoint, diraction,1000f,marrow);
            //添加击中点到路径中,raycast返回值  RaycastHit2D,  RaycastHit2D.point返回接触到碰撞体的表面
            if (hit)
            laserPoint.Add(hit.point);
            //如果击中门,门特效开,hitdoor变量变换,用于胜负判断,击中门的时候跳出while很重要
            if (hit.transform.tag == "door")
            {
             shaining.SetActive(true);
             hitdoor = true;
             break;
            }
            else
            {
            shaining.SetActive(false);
            hitdoor = false;
            }
            //发射方向,RaycastHit2D.normal返回被射线击中的曲面的法向量
            // if(hit.transform.rotation.z==90)
            //    diration = Vector2.Reflect(hit.point - (Vector2)startPoint, -hit.normal);
            // else if(hit.transform.rotation.z == 0)
             diraction = Vector2.Reflect(hit.point -(Vector2)startPoint,hit.normal);
           // if (hit.transform.rotation.z == 90)
               // diration = new Vector2(-diration.x, -diration.y);
                startPoint = hit.point+diraction*0.01f;
            i++;
        } while (i < reflectNum)
        ;           
    }
}

七效果

在这里插入图片描述
在这里插入图片描述

原创文章 66 获赞 39 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44739495/article/details/106147513