利用射線檢測實現光束照射啟用功能——2024TapTap聚光燈GameJam(一)

CloverJoyi發表於2024-11-05

利用射線檢測實現光束照射啟用功能——2024TapTap聚光燈GameJam


記錄日期 2024-11-05                          記錄時間 13:35
專案完成 2024-10-28                         歷經時長 21 天

簡介

專案主題:Light

專案名稱:《OneLastLight》(2D平臺跳躍解密)

我的職責:gamepaly程式,負責實現遊戲玩法功能

簡述:

策劃的設計為角色控制燈光,燈光照射到平臺,可以使平臺顯現實體,玩家可以藉助平臺解密。

燈光可以被不是平臺的實體阻擋,而且燈光不能被平臺阻擋,可以穿透平臺。

角色有兩種形態的燈光,光圈會以玩家為中心形成圓形照亮區域,光束會從玩家開始射出一個扇形區域跟隨滑鼠探測。

光束有紅、藍、白三種顏色,光圈有紅、藍兩種顏色。白色可以使所有平臺顯現實體,紅、藍光只能令相反顏色的平臺顯現實體,可以使相同顏色的平臺隱藏。

這裡記錄我實現這個玩法所使用的解決辦法。

正文

構想

採用射線檢測方法,從角色的位置開始,每次讓射線移動一個角度,設定角度限制,使射線檢測形成扇形區域,而光圈模式只要將角度限制改為360度

普通的 Physics2D.Raycast只能檢測射線碰到的第一個實體,不可穿透,所以這次選擇Physics2D.RaycastAll方法,此方法可以返回一個射線上的所有實體從近到遠的陣列.(Physics2D-RaycastAll - Unity 指令碼 API

實現

  1. 建立角色Player,建立兩個空物體LightBeam、LightCircle作為Player的子物體image.png
  2. 新建兩個指令碼:LightBeamController、LightCircleController,分別掛載在:LightBeam、和LightCircle上,指令碼內容為構想中RayCastAll方法的實現使用,先獲取射線上的所有物體,然後遍歷,呼叫物體上指令碼中的啟用程式碼
    LightBeamController(LightCircleControl相似):
//此方法用於實現光線啟用平臺、阻擋、穿透  
void DrawFieldOfView(){  
    // 計算最左側方向的向量
    // -transform.up看情況設定,最好與LightBeam的旋轉一致
    Vector3 forward_down = Quaternion.Euler(0, 0, -(viewAngle / 2f)) * -transform.up * viewRadius;  

	//在限制角度內建立viewAngleStep條射線,每條射線偏移一定的角度
    for (int i = 0; i <= viewAngleStep; i++){  
        Vector3 v = Quaternion.Euler(0, 0, (viewAngle / viewAngleStep) * i + 180f) * forward_down; // 根據當前角度計算方向向量  
        Vector3 pos = transform.position + v; // 計算射線終點  
  
        // 在Scene中繪製線條(僅在Scene中可見,方便檢視)  
        Debug.DrawLine(transform.position, pos, Color.red);  
  
        // 設定射線檢測射線 
        Ray2D ray = new Ray2D(transform.position, v);  

		//射線檢測
        RaycastHit2D[] hits =  
            Physics2D.RaycastAll(ray.origin, v, viewRadius, LayerMask.GetMask("Trigger")); //這裡設定只檢測Trigger層級 

		//遍歷檢測到的物體
        for (int j = 0; j < hits.Length; j++){  
            RaycastHit2D hitInfo = hits[j];  
            if (hitInfo.collider != null){  
                if (hitInfo.collider.CompareTag("BluePlatform") || hitInfo.collider.CompareTag("RedPlatform")){  
                    //檢測到為BluePlatform或者RedPlatform執行平臺上的顯現操作
                    }                               
                }                
            }        
        }    
    }
}
  1. 射線穿透做完了,現在射線可以穿透所有的物體,為其新增阻擋功能,非常簡單。已知Physice2D.RayCastAll方法是將射線碰撞到的所有物體按從近到遠的順序排列在陣列中。那麼在遍歷時遇到不是啟用平臺的物體直接跳出此次遍歷即可,即在判斷平臺的條件句後加上break即可
if (hitInfo.collider.CompareTag("BluePlatform") || hitInfo.collider.CompareTag("RedPlatform")){  
                    //檢測到為BluePlatform或者RedPlatform執行平臺上的顯現操作
                    }
                    else break;                               
                }
                     
  1. 製作平臺,建立一個空物體叫platform,建立一個矩形叫Entity,給它們掛載碰撞體,將platform的碰撞體設定為trigger,layer層級設定為Trigger(我設定的射線只能檢測Trigger層的物體),tag設定為BluePlatform或RedPlatform,最後將Entity作為platform的子物體
    image.png image.png
  2. 建立指令碼PlatformController,在指令碼中新增BoxAppear()和BoxDisappear()方法,用來控制實體的啟用和失活
public void BoxDisappear()
    {
        _entity.SetActive(false);
    }
public void BoxAppear()
    {
        _entity.SetActive(true);
        timer=0;//將計時器置為0
    }
  1. 在update中新增計時器,在燈光照射時不斷將計時器置為0,燈光不照射時計時器開始累計時間,到達一定時長後將平臺實體自動失活。
private void Update()  
{  
  
    timer += Time.deltaTime;  
    if (timer > canSeeTime)  
    {        
	      BoxDisappear();
    }  
    
  1. 最後在LightBeamController和LightCircleController中加入燈光顏色判斷
if (hitInfo.collider.CompareTag("BluePlatform")||
	hitInfo.collider.CompareTag("RedPlatform")){  
        switch (_colorID){  
            case 0:  
                if (hitInfo.collider.CompareTag("BluePlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxAppear();  
                if (hitInfo.collider.CompareTag("RedPlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxDisAppear();  
                break;  
            case 1:  
                if (hitInfo.collider.CompareTag("BluePlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxDisAppear();  
                if (hitInfo.collider.CompareTag("RedPlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxAppear();  
                break;  
            case 2:  
                if (hitInfo.collider.CompareTag("BluePlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxAppear();  
                if (hitInfo.collider.CompareTag("RedPlatform"))  
                    hitInfo.collider.gameObject.GetComponent<PlatFormController>().BoxAppear();  
                break;   
	    }    
    }       
    else break;  
}

將射線檢測的方法放在UpDate中呼叫,完成!

其它

光束與光圈模式的切換隻需啟用對應物件。

光束跟隨滑鼠,只需要令遊戲物件LightBeam跟隨滑鼠旋轉即可。

專案整體影片演示
專案程式碼GitHub連結(由於專案後面要配合Shader實現視覺效果,原始碼可能與上文略有差別)

總結

這算是我第一次參加GameJam,組隊是從官方組隊群中組的,比賽過程中學到了很多東西,但與他人的團隊協作體驗比較差。

隊伍有9個人,兩程式兩美術5策劃,策劃基本都是完全沒有經驗,每次開會固定5人:兩策劃,兩程式,主美。其它三人完全沒有交流過,也有可能他們與開會來的兩策劃是同一個學校的,他們會線下交流。但是他們交流的內容不會即時的傳遞給我們,有時候就會發現他們又策劃了什麼新功能,但是沒有告訴程式和美術。

策劃是完全沒有經驗的,其中一個策劃要求我等他寫程式需求,然後按照程式需求開發,結果寫了兩天就寫了五條需求,而且很籠統,約等於沒有寫。關卡體量也過於龐大了,美術有很大壓力。然後21天的gamejam唯一一個測試版本是距離ddl還有兩個小時做出來的,導致遊戲有很多影響體驗的小問題。(我一直催促出測試版測試,但策劃貌似更熱衷於新增新功能)

我也有一些不足的地方,我雖然能夠實現遊戲程式邏輯,但我沒有與他人合作的經驗,不擅長留介面給Shader、UI、音樂音效等。

總的來說開發的過程還是很有意思的,從查詢、設計解決問題的方法到實際解決給了我很大成就感。現在的我依然喜歡玩遊戲,比以前更喜歡開發遊戲了。我會繼續學習,持續進步。

相關文章