GameFramework框架学习:应用篇
参考写在前面!!!
本文是在腾讯大佬花桑的GF解析文章的基础上,自己阅读源码并尝试总结、应用、拓展的个人笔记!水印以示尊敬。
写在前面其实半年前就知道gf,但是那时候刚入门unity没多久,看了猫仙人的simple gf来学习,很可惜只学到了皮毛也就是一些常见的设计模式比如状态机、对象池、优先队列轮询在游戏中的应用。经过半年的unity学习与项目积累,再回来看gf的源码觉得,不难且实现优雅,但是内容实在是太多了,记不下来。为了让自己学的结构能穿起来,刨析demo并自己做,很必要。
参考的也是花桑和gf官方的demo。
// TODO 目前只做了刨析demo的流程
流程图
启动场景全流程自己的GameEntry.cs是自己的GameEntry类,而不是UnityGameFramework.Runtime中的GameEntry静态类。
作为游戏的入口,它需要继承MonoBehaviour并在Start方法中进行初始化。因为gf所有控件的初始化是在Awake内结束的,所以Start内拿到他们的时候已经可以安心使用了。
将所有默认的 GameFrameworkComponent 通过Un ...
GameFramework框架学习:原理篇
参考写在前面!!!
本文是在腾讯大佬花桑和大佬猫刀刀的GF解析文章的基础上,阅读源码并尝试总结、应用、拓展的个人笔记!无其他用途,水印以示尊敬。
运行流程启动基于MonoBehaviour来实现。
12345678910111213141516171819202122232425public abstract class GameFrameworkComponent : MonoBehaviour { // 游戏框架组件初始化。 protected virtual void Awake() { GameEntry.RegisterComponent(this); }}public static class GameEntry { // 提供api方便外部访问这个链队,从而获取组件 static readonly GameFrameworkLinkedList<GameFrameworkComponent> s_GameFrameworkComponents = new Ga ...
C#精要 - 小概念篇
闭包闭包的概念内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时的值,而是在外部新建一个对象再把对象的引用传给内层函数。
使用闭包比如在winform想实现:当用户关闭窗体时,给用户一个提示框。
12345678private void Form1_Load(object sender, EventArgs e){ string tipWords = "您将关闭当前对话框"; this.FormClosing += delegate { MessageBox.Show(tipWords); };}
闭包陷阱因为内层函数取得的外层函数是其“在父函数范围内(看闭包实现可以知道这不准确)”的最终值,所以遇到需要变动的值(比如循环变量)很容易写错代码。
比如说你想输出1-100的数字:
12345678for (int i = 0; i < 100; i++){ Task.Run(() =& ...
C#精要 - 值类篇
什么是值类型,什么是引用类型?结构体、枚举是值类型,类是引用类型。当然,所有类型都是隐式继承自Object的。
值类型有哪些结构体、枚举。
所有“结构体struct”都是抽象类System.ValueType的直接派生类,因此它不能再继承类了。而System.ValueType本身又直接从System.Object派生。
所有“枚举enum”都从System.Enum抽象类派生,System.Enum本身有直接从System.ValueType派生。
// 哦?你说System.Enum和System.ValueType抽象类?是的,虽然所有的枚举(enum type)都是值类型、内存分配也在栈上、会被装箱,但他们都继承自System.Enum抽象类,而System.Enum抽象类本身是引用类型。
结构体(struct type)也是一样的,System.ValueType抽象类型本身也是个类,是引用类型。
至于为什么,这是一种隐式继承,是由编译器做到的。怎么实现的我没有了解,但知道他们的IL代码不一样的,内部有很多字面值关键词 literal。
值类型特点
值类型实例一般在线程栈 ...
CLR Via C#个人笔记7 - 线程处理
大章26:线程基础Widnows的线程概念在没有线程概念的时候,机器都是“单线程”运行的,长时间运行的任务会阻止其他任务执行(16位windows下打印文档很容易“冻结”整个机器导致各种程序出错)。
所以微软设计新的OS内核来改进这些问题,该内核决定在进程中运行应用程序的每个实例。进程实际是应用程序的实例要使用的资源的集合,每个进程都被赋予了一个虚拟地址空间来避免被其它进程访问。
但是光这样还不够,如果机器只有一个CPU,应用程序死循环仍然会导致其他程序无法运行。线程就是微软交出的解决方案,它是一个Windows概念,它的职责是对CPU进行虚拟化,为每个进程都提供该进程专用的线程(功能相当于原来的一个物理CPU)。所以单物理CPU机器,一个进程死循环,不影响其他进程。
线程开销⭐和一切虚拟化机制一样,线程有空间(内存耗用)和时间(运行时的执行性能)上的开销。
下面对每个线程都有的开销一一介绍。
①线程内核对象 (thread kernel object)这是OS为系统中创建的每个线程都分配并初始化的数据结构之一。
对象中包括对线程进行描述的属性、**线程上下文(thread conte ...
背包问题
基础01背包问题概述n种物品每种只有1个。
每个物品有自己的weight和value,求解一个MAX_Weight的容量的背包尽可能多装value的解法。
暴力法
重量
价值
物品0
1
15
物品1
3
20
物品2
4
30
背包MAX重量为4。
每个物品只有2个状态(0或1),直接用回溯算法进行枚举。解决本题的时间复杂度为O(2^n) = 8。
动态规划法dp数组一个二维数组,
下标i 对应条件0~i 的物品任取,下标j 对应背包重量。
dp[i][j] 的值 对应 当0~i的物品任取、一个容量为j的背包所放物品的最大value。
递推公式考虑一个dp[i][j]的前后。
首先dp[i][j]前面说过,代表i、j情况下的最大value,
那么不放物品i的最大价值:dp[i-1][j](不考虑放入物品i但保持j背包重量的情况下的最大价值)
从而推出放物品i的最大价值:dp[i-1][j-weight[i]] + value[i](一定放物品i的背包的最大价值)
从上面的递进关系可以推出公式,dp[i][j] = max(dp[i-1][j], dp[i-1] ...
C#传入方法中的是一个指针
现象起因是工作中,在一个方法中对一个List进行了重赋值大概是,
123// rezeptTekiyouUiList是参数rezeptTekiyouUiList = rezeptTekiyouUiList.OrderBy(o => o.SubSeq).ThenBy(o => o.KomokuSeq).ToList();// ...后续对rezeptTekiyouUiList继续操作
然后发现退出方法后,后续对list的操作不起效了…查了一会之后发现,不止是ToList,这样的也会失效:
1234567891011public void ReSort(List<Test> list){ list = new List<Test>(); list.Add(new Test(){val = 1});}//甚至下面的也不行,val修改失败public void ReSort(Test test){ test = new Test(); test.val = 2;}
原因那到这里问题就很明显了,是 ...
CLR Via C#个人笔记6 - 核心机制
大章20:异常和状态管理异常处理机制什么是“异常”
首先对异常有一个基本理解,对于一些预想外的情况(比如中途转换失败),需要对既有代码进行进一步的安全性保证,就需要由对异常的处理。
平时代码throw抛出就会结束后续代码的执行,终止进程,但是如果在try里throw就会被catch接住,执行catch内代码;如果catch也抛出但被更上层的catch抓住了,抛出地点的后续代码就不会执行了,但仍然会执行对应finally内的代码,之后finally结束后的代码不会执行。
异常处理标准流程
123456789101112131415161718192021private void SomeMethod() { try { // do method } catch (InvalidOperationException){ // 异常预想情况1,从InvalidOperationException恢复的代码放在这 } catch (IOException){ // 异 ...
A*算法
A*算法A*算法是什么原理
主要利用到3个数值,
G Cost:从出发点到该点已花费的距离。
H Cost:从该点到终点的最乐观距离(不考虑障碍等因素)。
F Cost = G Cost + H Cost,它越低,作为寻径选择就越有吸引力。
目标是简单选择最低的F Cost,一步一步往后踩,每一步都记录附近没踩过的格子的F Cost到列表里。每踩下去一步后,如果发现周围邻近的格子F Cost都比过去的某个列表里的格子的F Cost大,就用那个列表里的格子继续踩。
不断重复,直到我们到达目标节点。
NodeBase
12345678910111213public class Nodebase { public float G { get; private set; } public float H { get; private set; } public float F => G+H public Nodebase Connection { get; private set & ...
王者荣耀复刻项目 技能篇
技能系统流程图
Skill数据类 SkillCfg:
拥有伤害值、动画切片名等等基础信息。
拥有技能类型、碰撞关系的技能逻辑体需要用到的枚举信息。
拥有BuffList、BulletCfg用于动态创建Buff和Bullet。
逻辑类 Skill:
Buff
数据类 BuffCfg。给策划配表用,只有数值(碰撞关系、伤害数值)。
逻辑类 Buff。本身用状态机实现。
复杂的Buff自己派生BuffCfg、Buff来实现数据、逻辑。
Bullet
目标追踪型:如果Skill是指向型的、且存在BulletCfg,就会被当作指向型弹道技能。
位置确定型:如果Skill是非指向型的、且存在BulletCfg,就会被当作非指向型弹道技能。
Bullet结构自身并不附带任何Buff。
子弹伤害、效果在Bullet的命中回调中通过读取Skill伤害、Skill的BuffList实现。
技能实现// TODO 梳理一整个战斗网络包(位移、技能)Send-Rsp-Tick过程:所有的本地设备(包括操纵者自己)其实就是同步演算+播放器
技能前摇、后摇 ...




