下载框架作者的示例工程 https://github.com/EllanJiang/StarForce
移动到 unity 空项目中
然后再下载 Gameframework https://github.com/EllanJiang/GameFramework 放到项目的 Asset 对应文件夹中
打开项目,一切顺利


笨木头的教程
https://github.com/mutouzdl/gameframework_demo
烟雨的视频教程
https://www.bilibili.com/video/av71419528


一开始看烟雨的视频教程感觉,啊,讲得好快
有些看懂了有些没看懂,果然还是要自己看

先把烟雨最后的总结截一下:

1.分为编辑器资源模式和非编辑器资源模式
2.流程的生命周期
3.同一时间,只能有一个流程在运行
4.离开流程时要注意取消订阅事件,防止逻辑冲突
5.DF中所有资源加载,都是异步的,不会阻塞主线程,依靠回调函数来判断有没有加载完成
6.GameEntry.Resource.InitResources 是一定要有的,它在非编辑器资源模式下起着至关重要的作用,它初始化了所有资源到一个映射表,但是并没有把所有资源都加载到内存


一开始看的时候还不知道为什么识别不到 namespace

问了别人才知道要设置 adf,说是 Unity 自定程序集 AssemblyDefinitionFile


建好了 adf,我重新构建一遍,结果发现错误更多,然后居然是引擎内部的程序集引用的问题

这就不科学了,LFS 版本的引擎内部应该不会有问题,所以我觉得可能是我项目构建有问题
或许这是因为我需要使用 unity 的 build 来构建

啊……重新构建了一遍还是有这个问题

我这个是把游戏工程文件夹复制粘贴到空项目中,会不会是我这个做法有问题……难受

好吧,这次我是直接用游戏工程文件夹打开,就好了
难受啊,这是哪里的设置有问题


要开始认真看了

我的打算是一遍看一遍复制粘贴项目,照着改,解决改的时候出现的错误,这样的话就能慢慢知道每个东西都是干嘛的了,大概

程序入口为 Hierarchy - Game Framework 的 GameEntry 脚本组件

因此我搞完 Hierarchy - Game Framework 就先复制 GameEntry 脚本过来
然后脚本里面唯二的两个函数被分在 GameEntry.Builtin 脚本和 GameEntry.Custom 脚本中,再复制这两个过来

然后就可以发现 GameEntry.Builtin 是初始化的框架自带的组件,GameEntry.Custom 是初始化自定义的组件,因此直接复制 GameEntry.Custom 过来的话,因为我还没有写自定义组件,所以找不到,会报错。这个时候我还用不到,先删了吧

一开始 Hierarchy - Game Framework - BuiltIn - Procedure 中啥也没有
从头构建游戏流程的话,那就必须要有流程了嘛,所以现在先要复制这个

根据烟雨的分析,我觉得这个流程……好像挺好的呀hhhh
干脆直接拿过来吧
反正之后只需要修改拓展 ProcedureMain 和 ProcedureMenu

Procedure 命名空间都改完了之后出现的错误:

ProcedureMenu 要用到创建好的 UI 类,我暂时没有界面 UI,就把这部分删去了
不过它要求必须重载 UseNativeDialog 是我没想到的

Procedure 中的 GameBaseGameMode 都是基于太空战机这个玩法创建的,那我自然是不能要,之后还是可以借鉴的
比如,他是做了一个游戏模式对应游戏类的字典,啊,这我就不知道为啥了
另外他好像在流程的每一个钩子都要用父类的方法,就比如 OnUpdate 的开头是 base.OnUpdateOnLeave 的结尾是 base.OnLeave
然后有一个转换到 menu 界面的方法

procedureOwner.SetData<VarInt32>("NextSceneId", GameEntry.Config.GetInt("Scene.Menu"));
ChangeState<ProcedureChangeScene>(procedureOwner);

他是要转换到 menu,所以设置这个 menu 的 id,但是实际上状态机里面切换到了 ProcedureChangeScene,那就应该是 ProcedureChangeScene 里面要用到这个 NextSceneId

还有他在 update 中通过计时器来实现延时……哦,这让我知道了原来确实是可以这么做的

ProcedureChangeScene 里面停止声音,恢复正常速度什么的,是把 Main 场景的 OnEnter 的职责分出去了
但是那是因为框架里面已经写好了通用的停止声音,恢复正常速度,就是说,从别的场景里面退出,一样能用,牛啊

然后他根据 id 在 DRScene 中找到对应的场景

怎么判断流程跳转完了呢?他用了一个 m_IsChangeSceneComplete 作为标志
Update 中查看 m_IsChangeSceneComplete 是不是 true,是则 ChangeState
m_IsChangeSceneComplete 在哪里设置为 true 呢,在 OnLoadSceneSuccess,这是一个事件,这个事件在 OnEnter 被订阅,同时 OnEnter 程序块最后执行了 GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName), Constant.AssetPriority.SceneAsset, this); ,也就是说这是一个异步的加载场景,在进入 ProcedureChangeScene 的时候就立即加载 Scene,加载完毕之后立即跳转流程

Main 流程中的 m_Games.Add(GameMode.Survival, new SurvivalGame()); 就是游戏主逻辑了

但是 SurvivalGame 里面只有一个随机生成陨石的脚本……?为啥捏
啊,又要找了,难受

不过还是先看陨石吧
他用 IDataTable<DRAsteroid> dtAsteroid = GameEntry.DataTable.GetDataTable<DRAsteroid>(); 拿到了一个 datatable,但是它只是用来获得一个数量,制作陨石的 typeid,因为后面有 new AsteroidData(GameEntry.Entity.GenerateSerialId(), 60000 + Utility.Random.GetRandom(dtAsteroid.Count) 这个构造函数是 public AsteroidData(int entityId, int typeId)
好奇怪啊,typeid 是在 60000 的基础上加一个随机数
然后这个 Count 应该是场上所有的陨石数量吧,但是我没有在 AsteroidData 的构造函数里面找到修改这个 Count 的内容。

好吧,之后才看到,这个 Count 是数据表的行数
诶呀,那他这个随机就很怪

AircraftData.cs

public AsteroidData(int entityId, int typeId): base(entityId, typeId, CampType.Neutral){IDataTable<DRAsteroid> dtAsteroid = GameEntry.DataTable.GetDataTable<DRAsteroid>();DRAsteroid drAsteroid = dtAsteroid.GetDataRow(TypeId);

他输入的这个随机 typeid 只是用在了 base(entityId, typeId, CampType.Neutral)
我还以为是用来选择陨石的类型的

TargetableObjectData.cs

public TargetableObjectData(int entityId, int typeId, CampType camp): base(entityId, typeId){m_Camp = camp;m_HP = 0;}

EntityData.cs

public EntityData(int entityId, int typeId){m_Id = entityId;m_TypeId = typeId;}

一路下来看到这个随机数最终变成了 m_TypeId 实体类型编号
呃……然后就没有用到了
不懂,跳过

在看 AsteroidData 的时候就可以发现,他这个是实体数据,还有一个实体逻辑,两个都属于实体
或许我现在应该看逻辑,嗯
但是我暂时只接触到了陨石,那就先看陨石的逻辑,然后再找找其他物体是在哪里创建的吧

哦,还要看这个逻辑和 data 是怎么对应的

GameEntry.Entity.ShowAsteroid(new AsteroidData(GameEntry.Entity.GenerateSerialId(), 60000 + Utility.Random.GetRandom(dtAsteroid.Count)){Position = new Vector3(randomPositionX, 0f, randomPositionZ),}) ;

那一看就是因为这个 GameEntry.Entity.ShowAsteroid 了hhh
一看,就跳转到了 EntityExtension.cs
这里面全是类似的函数

EntityExtension.cs

public static void ShowAsteroid(this EntityComponent entityCompoennt, AsteroidData data){entityCompoennt.ShowEntity(typeof(Asteroid), "Asteroid", Constant.AssetPriority.AsteroiAsset, data);}

EntityExtension.cs

private static void ShowEntity(this EntityComponent entityComponent, Type logicType, string entityGroup, int priority, EntityData data){if (data == null){Log.Warning("Data is invalid.");return;}IDataTable<DREntity> dtEntity = GameEntry.DataTable.GetDataTable<DREntity>();DREntity drEntity = dtEntity.GetDataRow(data.TypeId);if (drEntity == null){Log.Warning("Can not load entity id '{0}' from data table.", data.TypeId.ToString());return;}entityComponent.ShowEntity(data.Id, logicType, AssetUtility.GetEntityAsset(drEntity.AssetName), entityGroup, priority, data);}

EntityComponent.cs

        public void ShowEntity(int entityId, Type entityLogicType, string entityAssetName, string entityGroupName, int priority, object userData){if (entityLogicType == null){Log.Error("Entity type is invalid.");return;}m_EntityManager.ShowEntity(entityId, entityAssetName, entityGroupName, priority, ShowEntityInfo.Create(entityLogicType, userData));}

这个 ShowEntity 的函数,一路找下去,最终找到了一个 IEntityManager 类型的 m_EntityManager,这是一个接口
再跳转的话,就直接找到了接口,还是没有实现
所以应该看 m_EntityManager 的赋值,这个赋值语句的右值里面应该是实现过了

EntityComponent.cs

protected override void Awake(){base.Awake();m_EntityManager = GameFrameworkEntry.GetModule<IEntityManager>();

跳转之后看到,GetModule 这个函数也只是使用输入的泛型找 Module,那么 Module 的初始化在

GameFrameworkEntry.cs

private static readonly GameFrameworkLinkedList<GameFrameworkModule> s_GameFrameworkModules = new GameFrameworkLinkedList<GameFrameworkModule>();

呃……不对,这是空的
哦,对,空的的话就创建一个,惰性的

创建函数里面也就只有这句

GameFrameworkEntry.cs

GameFrameworkModule gameFrameworkModule = (GameFrameworkModule)Activator.CreateInstance(moduleType);

然后

Activator.cs

namespace System
{public static class Activator{public static object CreateInstance(Type type);

难受啊,那我怎么知道根据 type 创建出来的是什么
啊啊

哦,好吧,搜了一下,原来这是 C# 的函数,根据一个 type 类型的对象创建类的实例。是我孤陋寡闻了
那就是信息都放在 moduleType 里面了

GameFrameworkEntry.cs

public static T GetModule<T>() where T : class{Type typeFromHandle = typeof(T);if (!typeFromHandle.IsInterface){throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", typeFromHandle.FullName));}if (!typeFromHandle.FullName.StartsWith("GameFramework.", StringComparison.Ordinal)){throw new GameFrameworkException(Utility.Text.Format("You must get a Game Framework module, but '{0}' is not.", typeFromHandle.FullName));}string text = Utility.Text.Format("{0}.{1}", typeFromHandle.Namespace, typeFromHandle.Name.Substring(1));return GetModule(Type.GetType(text) ?? throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", text))) as T;}

moduleType 来自 Type.GetType(text)text 来自 Utility.Text.Format,来自 typeFromHandle.Namespace, typeFromHandle.Name.Substring(1),来自 Type typeFromHandle = typeof(T);
额……难顶,根本不知道这都是个啥
啊……那我就没办法了

我不理解为什么一个接口类的对象没有实现过接口类里面的函数,但是程序还是跑通了,我找不到他到底在哪里实现了
这不科学啊

好吧,还是回来看 ShowAsteroid 吧
组名 优先级 数据
数据是在 SurvivalGame 里面做的
优先级是要在 Scripts\Definition\Constant\Constant.AssetPriority.cs 中定义

好吧,那么这就算看完了
那接下来是该看 SurvivalGame 之外的部分了
他应该是想要通过 Game 类型的不同,控制游戏不同逻辑的部分,但是主角操控等相同的部分他就做成一个,所以没有放在 SurvivalGame 中

后面又看到

ProcedureMain.cs

protected override void OnEnter(ProcedureOwner procedureOwner){base.OnEnter(procedureOwner);m_GotoMenu = false;GameMode gameMode = (GameMode)procedureOwner.GetData<VarByte>("GameMode").Value;m_CurrentGame = m_Games[gameMode];m_CurrentGame.Initialize();}

里面也没有别的
那就只能是 m_CurrentGame.Initialize()
然后初始化里面就是新建 MyAircraft,飞船

那就先把 ProcedureMain 和 ProcedureMenu 里面的内容注释了

然后之后的错误是缺少 AssetUtility
那就复制 Assets\GameMain\Scripts\Utility\AssetUtility.cs 过来
然后应该是缺少一些定义
那就复制 Assets\GameMain\Scripts\Definition 过来
然后缺少 GameBase 和 GameMode
那就复制 Assets\GameMain\Scripts\Game 过来

这也是一些具体的东西了,比如 GameBase 里面 protected ScrollableBackground SceneBackground,多的都删了

然后是 ProcedurePreLoad 缺 DataTable
那就复制 Assets\GameMain\Scripts\DataTable 过来

然后是 ProcedureCheckVersion 里面少了 GameEntry 的 BuiltIn
那就还要在 GameEntry.Custom 里面补回

public static BuiltinDataComponent BuiltinData{get;private set;}private static void InitCustomComponents(){BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();}

然后是 ProcedureLaunch 的 SoundComponent 里面缺 Mute 啥的
那就复制 Assets\GameMain\Scripts\Sound 过来
然后是 Assets\GameMain\Scripts\UI

然后是 MenuForm 需要知道 m_ProcedureMenu 中启动游戏的函数
那就回 ProcedureNenu 补上

public void StartGame(){m_StartGame = true;}

然后是 json 缺 dll
那就复制 Assets\GameMain\Libraries 过去
加了之后本来是 rebuild 不了的
但是我之后又把 AI 那里的碰撞伤害给注释掉了,因为那里也是游戏主逻辑相关的
然后就可以 rebuild 了

然后一直有那个 ‘Entity’ does not contain a definition for ‘Available’ 之类的错误,我还以为是我哪里出错了,然后去复制了好多不相关的东西

后面才看到好像确实是因为框架代码改动了的问题
原来的框架里面的 Entity 是继承了 EntityLogic,所以可以直接通过 Entity 访问到 EntityLogic 里面的 Available 和 CachedTransform
但是新框架里面 Entity 类没有继承 EntityLogic,所以还需要用 Entity.Logic

Assets\GameMain\Scripts\HPBar\HPBarItem.cs
Assets\GameMain\Scripts\Utility\AIUtility.cs
Assets\GameMain\Scripts\Entity\EntityExtension.cs
Assets\GameMain\Scripts\Sound\SoundExtension.cs

然后 EntityExtension 的 ShowEntity 还少一个 EntityData
那就复制 Assets\GameMain\Scripts\Entity\EntityData 中的 EntityData 过去,Logic 就顺便一起复制吧

麻了,复制过来之后就出了问题,说是我不能加 Logic
呃……我知了
他这定义了两个重名的类
然后我是一个文件一个文件从他那复制过来的
一个 Entity 是框架里面的 Entity.cs
一个是游戏工程里的 Entity.cs
我一开始没有复制工程里的文件
然后编辑器就认为我有一个语句中的 Entity 类的对象是框架里面的 Entity.cs 的
我就以为是框架更新了的问题
然后后面我再复制了游戏工程里的 Entity.cs
编辑器又认为这个语句中的 Entity 类的对象是游戏工程里面的 Entity.cs 的

唉,丢人了丢人了

之后为了方便看,把 Assets\GameMain\Scripts\Entity\EntityLogic\Entity.cs 改成了 UEntity.cs
连带着改了很多地方

那么接下来就是没有错误了
估计框架的移植就是这样了?

[Unity] GameFramework 学习记录 1相关推荐

  1. [Unity] GameFramework 学习记录 3

    首先要仿照飞船的创建流程创建一个主角 首先直接导入 Starter Assets - Third Person Character Controller 太爽了 我看看啊 他这个是除了 ThirdPe ...

  2. [Unity] GameFramework 学习记录 2

    嗯--要开始尝试做自己的事了 一开始策划给我列了这些 工程仓库搭建 工程程序框架 第三人称相机实现 主角基础移动实现 主角闪避实现 主角战斗实现 主角能量条实现 近战敌人战斗实现 远程敌人战斗实现 U ...

  3. [Unity] GameFramework 学习记录 5

    jetbrain rider 可以反编译 原来在 visual studio 看不到的,写在 dll 里面的,接口的实现,经过反编译之后就能看到 这样就不用费心思多开一个阅读源码的 IDE 窗口了 牛 ...

  4. [Unity] GameFramework 学习记录 4:第三人称控制器

    我想知道 UEntity 数据表中的编号跟每个实体表自己的编号之间是否需要统一,现在看来好像不需要统一,但是我也不知道是不是因为我还没看到这两个表有交互的时候 哦我才注意到,这个实体表是用来定义资源的 ...

  5. [Unity] GameFramework 学习记录 6:计时器

    一开始我想不断传递 Delegate public class TimerHandler{private float _elapsedTime;public float ElapsedTime{get ...

  6. Unity+Hololens学习记录-射线应用

    Unity+Hololens学习记录-射线应用 前言 射线介绍: 射线应用元素介绍: Ray RaycastHit Raycast 射线应用实例: 射线碰撞信息获取 Camera发出Ray Gaze射 ...

  7. Unity Shader 学习记录(3) —— CG语言和Shader文件

    1 什么是语义 赋给shader的输入输出的字符串,表达了参数的含义.语义告诉shader从哪里获取数据,又把数据输出到哪里. 2 Shader的三种debug方法 1 假色彩图像 2 VStudio ...

  8. unity shader 学习记录

    记录下我学习unity shader的过程,并把我看到过的高质量教程推荐给大家! 借助插件shaderforge来熟悉着色的效果,并对照着shaderforge自动生成的shader代码手工优化和实现 ...

  9. Unity Shader学习记录(18) —— Shader动画

    纹理动画 纹理动画在游戏中的应用非常广泛.尤其在各种资源都比较局限的移动平台上,我们往往会使用纹理动画来代替复杂的粒子系统等模拟各种动画效果. 11.2.1序列帧动画 _Time是float4类型, ...

最新文章

  1. 2016.4.2 动态规划练习--讲课整理
  2. 模拟真机环境_QFramework 使用指南 2020(八):Res Kit(2)模拟模式与非模拟模式...
  3. 《Python Cookbook(第3版)中文版》——1.9 在两个字典中寻找相同点
  4. yarn界面杀死application
  5. CodeCraft-21 and Codeforces Round #711 (Div. 2) D. Bananas in a Microwave 优化暴力
  6. 前端学习(2979):vue-element-admin结构
  7. php变量函数,回调函数
  8. .Net Framework4.5中Asp.net mvc使用Singal R轮训实现导入进度条功能
  9. 在chrome中通过getComputedStyle()获取透明度的问题
  10. 拓端tecdat|R语言分解商业周期时间序列数据:线性滤波器、HP滤波器、Baxter King滤波器、Beveridge Nelson分解等去趋势方法
  11. php 怎么打出来的,word书名号怎么打出来
  12. 用Python自动化办公操作PPT,掌握这些技巧没压力!
  13. 微信提现免费额度领取,快来领取!我领取了738元
  14. 2021会是怎样的一年
  15. 红外光谱图解析知识大全(图文并茂)
  16. 短时傅里叶变换(STFT)及matlab
  17. 【python+pyqt5】B站直播弹幕姬
  18. 揭秘软件开发中的达摩克利斯之剑
  19. 带上CSDN一起游国庆
  20. 总结了25个Pandas Groupby 经典案例!!

热门文章

  1. Group by 第二选择 OVER
  2. 金融数据公司发展趋势小探
  3. FFTW 和 CUFFT 的使用对比
  4. 微软Kubernetes服务AKS开发正式版空间服务
  5. SQL Server -- SQL NULL值,ISNull(),Oracal NVL(),MYSQL IFNULL(),COALESCE()
  6. swift 闭包的使用
  7. 第一章 Shiro简介——《跟我学Shiro》
  8. -webkit-min-device-pixel-ratio的常见值对照
  9. SqlServer 更改sa密码
  10. ArcGis Server开发Web GIS新手体验(二)