Organizations

8 results for QFramework
  • QFramework集成网络序打包 Unity 网络编程和其他网络服务端编程交互其实还有很大区别, 包含以下问题: 网络传输默认采用 字节序(小端序) 传输, 并不是服务端常用的 网络序(大端序) 默认字符串采用 Unicode 而非常规用的 UTF-8 字符串 对于网络序转化需要 bytes 反转下处理: // 依靠 Array.Reverse 讲字节序转网络序 Int32 value = 120; var buffer = BitConverter.GetBytes(value); Array.Reverse(buffer); // 翻转序列 对于字符串处理就需要编码处理下: // Unicode 转 UTF8 字节流 var value = "hello.world"; var buffer = Encoding.UTF8.GetBytes(value); var lengthBuffer = BitConverter.GetBytes(buffer.Length); Array.Reverse(lengthBuffer); // UTF8字节流 转 Unicode var buffer = new byte[length]; // 假设客户端返回二进制流 Encoding.UTF8.GetString(buffer, 0, length); // 转化 Unicode 这里主要用到 Encoding 和 BitConverter 方法来处理转化, 没什么需要说的.
    QFramework Created Sun, 17 Nov 2024 22:42:28 +0800
  • 有限状态机作用 按照游戏玩家对象设计基本上有以下状态: Idle(bool): 待机 Move(bool): 移动 Run(bool): 冲刺 Attack(bool): 攻击 Jump(bool): 跳跃 按照简单代码处理, 如果玩家先 移动 再按下 冲刺 的情况, 这时候玩家应该需要做到的是 冲刺 覆盖掉 移动 状态, 而不是 移动 和 冲刺 同时 bool=true. 可以自己编写代码测试或者自己脑子模拟下以下情景: 假设玩家初期带有 移动 状态, 那么玩家移动状态追加 isMove 即可 但是后来玩家又多出个 冲刺 状态, 因为行为是和 移动 互斥必须编写代码判断处于状态中 再后来玩家有多个 飞行(fly) 状态, 又要覆盖编写 if|switch 状态判断切换逻辑 这里如果按照比较初级的游戏逻辑来处理判断代码: // 判断玩家是否可以移动, 不允许玩家处于奔跑和飞行状态 if (!isRun && !isFly) { // 允许移动并切换, 其他UI逻辑代码略 isMove = true; } // 判断玩家是否可以奔跑, 不允许玩家处于飞行状态 if (!isFly) { // 允许奔跑 isRun = true; } // 其他诸如追加传送和闪现的追加行为状态判断 可以看到这里面的状态复杂度及其可怕, 特别判断自身状态情况完全耦合在一起纠缠不清; 而如果要定义这种抢占状态(唯一状态)并发的情况, 衍生出利用 有限状态机(FSM) 处理并发行为状态.
    QFramework Created Sun, 10 Nov 2024 20:16:38 +0800
  • Command 和 Query Command 负责 增|删|改, Query 负责 查, 但是 Query 并不是必选的; 有的时候计算量不是那么重的时候可以直接通过 Model 直接查询数据, 但是复杂跨 Model 数据就依赖 Query. 比如当前有 玩家模型(PlayerModel) 和 敌人模型(EnemyModel), 你需要战斗计算敌人的真实攻击数值; 这个真实攻击数值等于 敌人攻击力减去玩家防御值 的情况, 这时候就需要跨模型查询出 玩家防御值 - 敌人攻击值 抵消的伤害: /// <summary> /// 计算敌人真实伤害 /// </summary> public class EnemyAttackValueQuery : AbstractQuery<int> { protected override int OnDo() { // 获取敌人攻击 - 玩家防御之后真实数值 var v = this.GetModel<EnemyModel>().Atk - this.GetModel<PlayerModel>().Def; return v > 0 ? v : 1; // 最小攻击伤害 1 } } 这种复杂查询的情况就适合 Query 进行发挥; 对于网络游戏来说, 如果需要从服务器同步数据则通过 Query 内部拉取, 而增删改同步到服务器则需要在 Command 做处理
    QFramework Created Sat, 09 Nov 2024 21:35:56 +0800
  • UniTask 说明 虽然 Unity 提供自带协程方案, 但是本身开销庞大且要求 UnityEngine API 必须从主线程调用才能被执行, 也就没有比较好的办法在其他线程调用 UnityEngine API 相关调度方式( 无法脱离 MonoBehaviour 去进行调用任务 ). 所以社区提出了 UniTask 方案, 在保证Unity线程安全的前提下还支持 C# 的异步编程模型,而且不需要依赖 MonoBehaviour 便可以运行. 对于需要用到 Action 回调处理地方, 用 UniTask 处理更加方便 配置安装 这里采用官方的 Git 导出方案, 直接在 Package Manager 点击 add package from git URL 输入以下地址自动安装: https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask 这样默认就在项目组件当中追加好 UniTask 第三方依赖了. 常规使用 UniTask 性能极佳且对第三方插件没有兼容性问题( 如 DoTween ), 这里提供常用到的使用说明: // 使用UniTask所需的命名空间 using Cysharp.Threading.Tasks; // 你可以返回一个形如 UniTask<T>(或 UniTask) 的类型,这种类型事为Unity定制的,作为替代原生Task<T>的轻量级方案 // 为Unity集成的 0GC,快速调用,0消耗的 async/await 方案 async UniTask<string> DemoAsync() { // 你可以等待一个Unity异步对象 var asset = await Resources.
    QFramework Created Sat, 09 Nov 2024 15:36:50 +0800
  • 场景管理 在 Untiy 当中也是需要管理好自身场景, 很多人以为场景切换就是单纯场景资源编号之后调用 Unity 自身的 SceneManager 就行; 实际上场景并非这么简单直接切换, 因为场景还有不少问题需要处理: 是否为独占场景: 需要关闭其他UI独占场面 是否同个分组场景: 有的场景是多个子场景拼接 是否为界面首页: 默认进入游戏的主界面 首页是切换Loading还是Home: 确定启动游戏之后先运行 Loading 还是 Home 其他还有做 ab 包动态下载场景资源的情况 另外需要说明下 Unity 的场景概念很多人混合在一起, 他和 Godot 节点式常见不一样, 需要在菜单栏 File(文件) - BuildSetting(构建设置) 当中去手动或者代码引入对应 Scene 对象场景; 但是有人也喜欢在单一 Scene 之中引入外部预制件并设置 Active 状态让其可用或者不可用唤起, 这种方法好处就是直接单次加载所有预制件直接 Active 切换场景即可, 但是坏处就是某个场景资源十分庞大直接卡死所有其他简单场景. 所以在 Unity 场景分为以下几种意思: Scene: 也就是 BuildSetting 设置的场景, 包括且不限制 登录Scene | 首页Scene | 游戏Scene 等等之类单一场景 Page: 子场景也就是场景内显示的预制体层, 比如触发点击战场情况时候看起来转场到战场地图的 新场景, 同时还有打开背包进入背包菜单界面的情况 注意: 这里后续会大量依赖 QFramework|UniTask|FSM 这些组件, 所以最好对其有基本认识.
    QFramework Created Sat, 09 Nov 2024 14:50:08 +0800
  • DoTween动画 众所周知 Unity 本身具有动画系统, 但是因为其不成熟的体现后续都采用第三方库来处理, 其中最知名的就是 DoTween 插件. DoTween官方网站 DoTween 极可能把功能封装完成简单函数调用, 提供了包含且不限于 线性插值、贝塞尔曲线插值、弹簧插值 等动画插值处理方法. 官方提供的样例也简单, 直接 下载插件 解压放入项目即可进行商业化使用. 插件移动过去之后一键点击配置, 最多需要点击设置 ASMDEF 处理下, 之后就可以开始直接代码配置. 这里集合之前 QFramework 追加事件即可: using System.Collections.Generic; using QFramework; using UnityEngine; using DG.Tweening; // 引入动画系统 // 项目文件: QGame/ViewController/RevolveController.cs namespace QGame.ViewController { /// <summary> /// 旋转事件 /// </summary> public struct RevolveEvent { public bool Stop; public GameObject[] Objects; public float Duration; } /// <summary> /// 旋转控制器 /// </summary> public class RevolveController : MonoBehaviour, IController,IOnEvent<RevolveEvent> { /// <summary> /// 返回引用句柄 /// </summary> /// <returns>IArchitecture</returns> public IArchitecture GetArchitecture() { return QGameApp.
    QFramework Created Thu, 07 Nov 2024 11:54:06 +0800
  • QFramework架构 QFramework 官方样例推荐的架构推荐以 MVC 架构方式构建项目目录, 这里以 Scripts 目录为主要代码基准目录: 以此 Scripts 目录下为主, 同级推荐生成以下目录: ViewController: IController 接口,负责接收输入和状态变化时的表现,一般情况下,MonoBehaviour 均为表现层 System: ISystem 接口,帮助IController承担一部分逻辑,在多个表现层共享的逻辑,比如计时系统、商城系统、成就系统等 Model: IModel 接口,负责数据的定义数据的增删查改方法 Utility: IUtility 接口,负责提供基础设施,比如存储方法、序列化方法、网络连接方法、蓝牙方法、SDK、框架继承等或者第三方库集成 Command: ICommand 接口,核心业务区用于获取对象做游戏逻辑计算, 包括且不限于游戏初始化|关卡进入等 Event: IEvent 接口,统一的全局事件目录, 定义游戏所需的所有调配事件 各层级调用规则: IController 更改 ISystem|IModel 的状态必须用 Command 来处理 ISystem|IModel 状态发生变更后通知 IController 必须用 Event|BindableProperty IController 可以获取 ISystem|IModel 对象来进行数据查询 ICommand 不能有状态和内部属性相关 上层可以直接获取下层, 下层不能获取上层对象, 下层如果想要向上层通信必须用 Event 上层向下层通信用方法调用(只是做查询,状态变更用Command),IController的交互逻辑为特别情况,只能用Command 这里简单以玩家对战的战斗场景来说明: 玩家进入战斗场景, 这时候其实是处理表现层 IController 这时候玩家确认攻击指令, 其实就是调用 ICommand 指令功能 ICommand 接受指令直接先查询玩家 IModel 信息确认玩家攻击力造成的伤害 ICommand 查询到伤害推送给 ISystem 战斗系统确认是否已经打败 ISystem 确认伤害打败怪物采用 IEvent 通知 ICommand 开始进行胜利结算 ICommand 接收到结算的时候, IUtility 负责保存胜利奖励信息和状态信息 上面就是各层级所需的逻辑流程, 后续就是规划具体游戏业务功能.
    QFramework Created Sun, 03 Nov 2024 13:06:06 +0800
  • QFramework初探 在 Unity 当中其实可以从0开始编写内部游戏框架, 但是出于项目加快上线计划从而会采用开源框架, 而这里采用开源社区的 QFramework 来引入. 内部只有 QFramework.cs 单个文件, 直接创建文件夹之后复制黏贴到项目就能直接开始项目搭建. 这里先编写个官方测试样例, 代码之中会具体说明相关的功能作用: using System.Collections.Generic; using QFramework; using UnityEngine; using Random = UnityEngine.Random; // 自定义项目的命名空间, 防止命名空间污染 namespace Examples { /// <summary> /// 挂载的控制器名称, 需要实现 IController 接口 /// </summary> public class QueryModelController : MonoBehaviour, IController { #region 数据模型 /// <summary> /// 生成随机数模型 /// </summary> public class RandomValueModel : AbstractModel { /// <summary> /// 模型初始化, 可以通过本地配置|网络获取到数据 /// </summary> protected override void OnInit() { } /// <summary> /// 模拟服务器|数据库查询获得信息 /// </summary> /// <returns></returns> public int Execute() { return Random.
    QFramework Created Sat, 02 Nov 2024 14:41:21 +0800