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)
        ;           
    }
}

七效果

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章