工具篇:定时系统
我的解决方案CodingKTimer
初识为什么需要定时系统Unity侧:
简化协程计时写法。
协程基于Monobehaviour来实现,而物体激活属性变化会导致中断调用。这可由定时器解决。
不需要依赖于unityAPI。
服务端侧:
简化代码 => 支持多线程、指定线程。
三种定时器TickTimer (高频高精度的毫秒级定时)
支持多线程;
不依赖 Unity引擎环境,可在客户端服务器使用;
可使用外部循环驱动计时,也可使用驱动线程(内部new的)来执行;
定时回调默认是线程池工作线程运行,也就是在驱动线程中运行,也可外部自己驱动Handle运行;
内部使用线程安全字典ConcurrentDictionary来存储Task,遍历过程中Remove无影响。
调用线程线程可以使用新工作线程:
123// 使用新线程:timerThread = new Thread(new ThreadStart(StartTick));timerThread.Start();
也可以在Unity的Update中调用计时器内部 UpdateTas ...
工具篇:protobuf序列化
Protobuf 初识什么是Protobuf
Google Protocol Buffers(简单Protobuf或PB) 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关 、可扩展的序列化结构数据格式 。目前,几乎支持所有主流编程语言 。
他和xml、json一样,都属于数据标记语言。
Protobuf优势
序列化与反序列化速度极快。
与语言及平台无关,兼容性好,通过 proto文件生成多种语言文件 => 实现 服务端、客户端之间 跨语言平台的数据转换。
数据高度压缩 => 占用空间少,节省带宽。
Protobuf使用google官方全版本支持
.net专用版本 作者Marc Gravell(本篇使用)
Protobuf对比C#常规序列化标签不同,常规只需要对类打上[Serializable],而Protobuf需要对类打上[ProtoContract],再对属性打上[ProtoMember(1)],中间的数字是tag对应一个属性。 ...
工具篇:帧同步网络库
我的解决方案CodingK_Session
聊聊网络基础起源起源于1969年美国国防部的军用项目,最初只是一个单个的分组交换网ARPANET(并不是一个互连的网络)。1983年TCP/IP协议成为ARPANET上的标准协议,使所有使用 TCP/IP协议 的计算机都能利用互连网相互通信。因此1983年被当作因特网(Internet)诞生的时间。之后经过不断发展,形成了如今的英特网(Internet)。
网络通信是指什么?计算设备之间通过网络交换数据,更通俗地说法就是:主机A上的某个程序(进程)与主机B上的某个程序(进程)进行数据交换。
网络通信如何实现?计算设备之间通过共同遵守的 网络协议(network protocol) ,以约定好的规则来交换数据。
计算机网络体系结构五层协议的体系结构
OSI七层协议:概念清楚,理论完整,但它复杂不实用。
TCP/IP四层协议:应用非常广泛。实质上,TCP/IP只有上面三层,最下层的网络接口层并没有什么具体内容。
综合前面两者,我们一般采用五层协议的体系结构来学习理解计算机网络原理。
五层协议功能划分应用层:直接为用户的应用进程提供服务。这一层的 ...
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;}
原因那到这里问题就很明显了,是 ...