利用結構體儲存實體狀態——2024TapTap聚光燈GameJam(二)

CloverJoyi發表於2024-11-29

利用結構體儲存實體狀態——2024TapTap聚光燈GameJam(二)


記錄日期 2024-11-29           專案時間 2024-10-8           歷經時長 21 天

簡介

策劃要求實現遊戲中角色可以扔出手中提燈,並保持扔出前的光線角度、顏色。(可惜最後功能完美實現,但是這個玩法被取消了,沒有實際使用到)

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

邏輯

使用結構體儲存角度、顏色、燈光型別的資料,再使用單例模式,將指令碼掛載在場景中的遊戲物件上,這樣就可以保證只有一個儲存例項,並且便於呼叫。

對於扔出的燈,我的想法是在原地建立一個預製體,然後讀取儲存的狀態,重新設定燈光。

實現

定義

首先新建指令碼SaveData,定義結構體StateSave,這裡lightColor是一個顏色的列舉,angle為角度,lightMode是燈光模式:true為光束模式,false為光圈模式,isLight表示燈的開關。

public enum LightColor {  
    white = 0,  
    Red = 1,  
    Blue = 2,  
}
public struct StateSave{  
    public LightColor _color;  
    public float _angle;  
    public bool lightMode; //true:Beam false:circle  
    public bool isLight;  
}

在指令碼中宣告結構體,並將此指令碼設定為單例模式,然後在場景中新增一個空的遊戲物件,最後把SaveData指令碼掛載在這個遊戲物件上。

如此一來當場景執行時就會例項化SaveData,由於在SaveData中宣告瞭結構體,在例項化的時候也會新建一個StateSave物件,且保證了只能有一個SaveData例項。

(由於專案需要,後面我又在這個指令碼中加入了一些別的內容,導致上圖多出了一些東西,但是實現流程是一樣的)

對於扔出的提燈,我首先製作一個提燈的預製體,並將其放在Resources資料夾中便於載入。

然後設定狀態機當按下扔出鍵時進入無燈狀態,儲存當前燈光資料,關閉自身所有的燈並在原地建立一個提燈,根據讀取的燈光資料設定提燈的燈光。

public void ThrowLantern(Transform m_playerBody) {  
     var _lantern =(GameObject)Instantiate(Resources.Load("Lantern(External)"),m_playerBody.transform.position,m_playerBody.transform.rotation);  
     OutPutState(_lantern);  
 }
 private void M_ThrowLantern(Transform m_playerBody) {  
     m_playerController.ThrowLantern(m_playerBody);  
 }
//根據儲存的狀態設定提燈的狀態  
 private void Init() {  
     if (L_stateSave.lightMode) {  
         _lightBeam.gameObject.SetActive(true);  
         _lightCircle.gameObject.SetActive(false);  
         _lightBeam.GetComponent<BeamController>().GetState(L_stateSave);  
     }     else {  
         _lightBeam.gameObject.SetActive(false);  
         _lightCircle.gameObject.SetActive(true);  
         _lightCircle.GetComponent<CircleController>().GetState(L_stateSave);  
     } }

呼叫

在SaveData中分別定義讀取狀態和儲存狀態的方法

public StateSave GetState(StateSave state) {  
    state._angle = m_stateSave._angle;  
    state._color = m_stateSave._color;
    state.lightMode = m_stateSave.lightMode;  
}

public void SaveState(LightColor color, float angle, bool lightMode) {  
    m_stateSave._color = color;  
    m_stateSave._angle = angle;  
    m_stateSave.lightMode = lightMode;  
}

由於使用單例模式,呼叫時只需

SaveData.Instance.GetState(state);

SaveData.Instance.SaveState();

讀取到儲存的狀態後,再在程式中初始化燈的狀態即可,由於我使用的是一個簡易的狀態機來控制人物有燈和無燈的狀態,所以我只需在狀態進入和狀態退出時分別呼叫GetState()和SaveState()方法,並在狀態進入時初始化燈的狀態就可以。

總結

功能雖然完美實現了,但是最後這個機制並沒有應用在遊戲中(應該是沒有合理的方案使角色在扔出提燈解密後將提燈收回)。而且時隔一個月再次審視我的程式碼,感覺程式碼的結構還是比較混亂的,最佳化的空間很大,也算是我經驗不足的體現。

對於這個解決方案,我覺得一定有比我這個方案更合理的方法,但是這個方案是我自己構思出來的,因此我感到很有成就感,所以記錄下來作為紀念。

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

相關文章