利用结构体存储实体状态——2024TapTap聚光灯GameJam(二)
简介
策划要求实现游戏中角色可以扔出手中提灯,并保持扔出前的光线角度、颜色。(可惜最后功能完美实现,但是这个玩法被取消了,没有实际使用到)
下面记录我实现这个玩法所使用的解决办法。
逻辑
使用结构体保存角度、颜色、灯光类型的数据,再使用单例模式,将脚本挂载在场景中的游戏对象上,这样就可以保证只有一个保存实例,并且便于调用。
对于扔出的灯,我的想法是在原地创建一个预制体,然后读取保存的状态,重新设置灯光。
实现
定义
首先新建脚本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实现视觉效果,源码可能与上文略有差别)