利用结构体存储实体状态——2024TapTap聚光灯GameJam(二)

利用结构体存储实体状态——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实现视觉效果,源码可能与上文略有差别)

posted @ 2024-11-29 23:35  CloverJoyi  阅读(3)  评论(0编辑  收藏  举报