文章目录

  • 前言
  • 一、准备
  • 二、使用
    • 1、第一步:创建Model数据
    • 2、创建接触命令TriggerCommand
    • 3、创建Player玩家脚本
    • 4、创建UI,联动数据
    • 5、初始化游戏
    • 6、额外系统添加(成就系统)
  • 总结

前言

QF架构是在该框架不断迭代中出现的,不同与其他的架构,她的优点是将各个模块分层管理并且提供封装好的工具方便实现以前写起来很麻烦的功能,写起来层次分明。官方讲的也很好,想要李姐原理可以去看教程+源码。
本篇是我李姐的使用方式,不涉及讲解。


一、准备

文件夹管理如下图:(如果游戏当中有功能独立于该游戏的小游戏【如2077当中加入了街机小游戏】,建议再建立一个类似的文件夹)

附:Model-数据,Command-命令,System-系统,Storage-存储,Game-游戏逻辑,GameArchitecture架构【注册模块】,GameMgr-游戏管理【主要用于初始化】

Architecture代码

//游戏架构:用来注册模块namespace QFramework.Game{public class Game : Architecture<Game>{protected override void Init(){//注册各个模块//储存this.RegisterUtility<IStorage>(new Storage());}}}

储存(简单用LitJson写了一个,想要更全面更系统化可以参考另一篇文章unity强力配置插件)

using UnityEngine;using System.IO;using LitJson;//存储类namespace QFramework.Game{public interface IStorage : IUtility{void Save<T>(string file,T data);T Load<T>(string fileName);}public class Storage : IStorage{public void Save<T>(string name, T data){string filePath = Application.streamingAssetsPath + "/" + name +".json";//利用JsonMapper将save对象转换为Json格式的字符串string saveJsonStr = JsonMapper.ToJson(data);//将这个字符串写入到文件中//创建一个StreamWriter,并将字符串写入文件中StreamWriter sw = new StreamWriter(filePath);sw.Write(saveJsonStr);//关闭StreamWritersw.Close();}public T Load<T>(string name){T t = default;string filePath = Application.streamingAssetsPath + "/" + name + ".json";if (File.Exists(filePath)){//创建一个StreamReader,用来读取流StreamReader sr = new StreamReader(filePath);//将读取到的流赋值给jsonStrstring jsonStr = sr.ReadToEnd();//关闭sr.Close();//将字符串jsonStr转换为Save对象t = JsonMapper.ToObject<T>(jsonStr);}else{Debug.LogWarning("存档文件不存在");}return t;}}}

GameMgr代码

//初始化游戏namespace QFramework.Game{public class GameMgr : MonoBehaviour{void Start(){ResKit.Init();// UIKit 的分辨率设置//UIKit.Root.SetResolution(1920, 1080, 1);}}}

二、使用

我们假设需要快速实现一个Demo给老板看,效果是玩家在场景里来回走,地上随机生成奖励,碰到一个奖励就加分;加分需要保存下来,并且到一定分数触发成就系统,弹出来成就完成。

1、第一步:创建Model数据

玩家的数据那就起名PlayerModel,具体属性是分数Score

namespace QFramework.Game{public interface IPlayerModel : IModel{public BindableProperty<int> Score { get; }}public class PlayerModel : AbstractModel, IPlayerModel{public BindableProperty<int> Score { get; } = new BindableProperty<int>();protected override void OnInit(){var storage = this.GetUtility<IStorage>();// 设置初始值(不触发事件)Score.SetValueWithoutEvent(storage.Load(nameof(Score)));// 当数据变更时 存储数据Score.Register(newCount =>{storage.Save(nameof(Score), newCount);});}}}

写完后在架构注册模块

//游戏架构:用来注册模块namespace QFramework.Game{public class Game : Architecture<Game>{protected override void Init(){//注册各个模块this.RegisterModel<IPlayerModel>(new PlayerModel());//储存this.RegisterUtility<IStorage>(new Storage());}}}

2、创建接触命令TriggerCommand

接触后分数增加

namespace QFramework.Game{public class TriggerCommand : AbstractCommand{protected override void OnExecute(){var model = this.GetModel<IPlayerModel>();model.Score.Value++;}}}

3、创建Player玩家脚本

创建一个3d模型球体(命名为Player),添加刚体并设置Is Kinematic为true,选择球体Alt+V创建脚本;再建几个相同的球(命名为Ball)放到周围加上黄色材质。

namespace QFramework.Game{public partial class Player : ViewController{private Rigidbody rigidbody;void Start(){rigidbody = GetComponent<Rigidbody>();}private void Update(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");}private void OnTriggerEnter(Collider other){if (other.name.StartsWith("Ball")) {Game.Interface.SendCommand<TriggerCommand>();other.Hide();}}}}

核心代码:发送触碰命令Game.Interface.SendCommand();

4、创建UI,联动数据

创建QF的GamePanel的UI,其中脚本继承IController用以获得model,将数据和界面绑定。

namespace QFramework.Game{public class GamePanelData : UIPanelData{}public partial class GamePanel : UIPanel, IController{private IPlayerModel model;protected override void OnInit(IUIData uiData = null){mData = uiData as GamePanelData " />? new GamePanelData();model = this.GetModel<IPlayerModel>();model.Score.RegisterWithInitValue((value) => ScoreText.text = "分数:" + value).UnRegisterWhenGameObjectDestroyed(gameObject);}protected override void OnOpen(IUIData uiData = null){}protected override void OnShow(){}protected override void OnHide(){}protected override void OnClose(){}public IArchitecture GetArchitecture(){return Game.Interface;}}}

5、初始化游戏

默认初始打开GamePanel的UI

//初始化游戏namespace QFramework.Game{public class GameMgr : MonoBehaviour{void Start(){ResKit.Init();// UIKit 的分辨率设置//UIKit.Root.SetResolution(1920, 1080, 1);UIKit.OpenPanel<GamePanel>();}}}

6、额外系统添加(成就系统)

成就系统初步完成,到10就会触发debug。

//成就系统//成就系统namespace QFramework.Game{public interface IAchievementSystem : ISystem{}public class AchievementSystem : AbstractSystem, IAchievementSystem{protected override void OnInit(){var model = this.GetModel<IPlayerModel>();model.Score.Register(value => {if (value == 10){Debug.Log("针不戳");}else if (value == 2000000) {Debug.Log("还行吧");}});}}}

注册模块

//游戏架构:用来注册模块namespace QFramework.Game{public class Game : Architecture<Game>{protected override void Init(){//注册各个模块this.RegisterModel<IPlayerModel>(new PlayerModel());this.RegisterUtility<IStorage>(new Storage());this.RegisterSystem<IAchievementSystem>(new AchievementSystem());}}}

但我们发现逻辑上只要到10就会触发,考虑到以后加个红色的球碰到减生命值可能就会来回触发;简单改下,如果成就达成我们就把成就存下来,然后判断一下成就是否是返回默认值0。

//成就系统namespace QFramework.Game{public interface IAchievementSystem : ISystem{}public class AchievementSystem : AbstractSystem, IAchievementSystem{protected override void OnInit(){var storage = this.GetUtility<IStorage>();var model = this.GetModel<IPlayerModel>();model.Score.Register(value => {if (value == 10 && storage.Load("针不戳") == 0){storage.Save("针不戳", 1);Debug.Log("针不戳");}else if (value == 2000000 && storage.Load("还行吧") == 0) {storage.Save("还行吧", 1);Debug.Log("还行吧");}});}}}

如果项目有要求,这里还是在Storage那里进行封装成就相关的函数,如下进行删除等操作的扩展。

public void Clear() {PlayerPrefs.DeleteAll();}pubic bool xxx(){//判断xx}

总结

QF架构的基本使用,这是我李姐的使用步骤,具体有什么问题请留言。