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 & ...
CLR Via C#个人笔记5 - 基本类型
大章14:字符、字符串和文本处理字符Char类型System.Char
Char类型,在.NET中总是表示成16位Unicode代码值。
Char类型,提供2个静态只读字段:MinValue = \0 和 MaxValue = \uffff。
Char类型,提供GetUnicodeCategory方法,它返回枚举类,表明该字符是Unicode标准定义的控制字符、货币符号、小写字母、大写字母、标点符号、数学符号还是其它字符。
Char类型,在使用ToLower和ToUpper方法时,会需要使用到语言文化来转换,语言文化通过System.Threading.Thread.CurrentCulture静态方法获取。
Char转换数值类型
强转,效率最高。
用Convert类的静态方法。
用IConvertible接口,效率最低,因为要装箱。
123456789101112131415161718Main(){ char c; int n; // 1.强转 c = (Char) 65; n = (int) c; Console.WriteLine(c);// output: ...
王者荣耀复刻项目 技能篇
技能系统流程图
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过程:所有的本地设备(包括操纵者自己)其实就是同步演算+播放器
技能前摇、后摇 ...
C#精要 - 堆栈篇
先说一下什么是栈?数据结构中的栈是一种先进后出的数据结构。
在C#的内存中有用到栈结构,一个线程拥有一个大概1mb的线程栈。一般拿来存放引用指针、值类型、方法的局部变量和实参等。
内存管理栈是一种内存自我管理的结构,压栈自动分配内存,出栈自动清空所占内存。
但因此栈只能在一端对数据进行操作,也就是栈顶端进行操作。
方法调用与线程栈方法的调用追踪就是在栈上完成的。比如我们有一个main方法(程序入口), 在main方法中会调用一个GetPoint的方法。在线程执行时,会将main方法压入栈底(包括编译好的方法指令,参数,和方法内部变量),然后再将GetPoint的方法压入栈底,GetPoint中没有调用其它方法,压栈完毕。出栈顺序是先进后出,也就是后进先出,栈顶的方法GetPoint先执行完毕,然后出栈,所占内存清空,接着main方法执行后出栈,所占内存清空。
再说一下什么是堆?数据结构中的堆,是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
CLR的堆是和栈对立的内存概念,而不是二叉树。一个程序用一个托管堆。托管堆一般拿来存 ...
王者荣耀复刻项目 模型控制篇
模型预处理淘宝、网上资源搞到的人物FBX,全都是一个FBX对应一个动作或者集成在一起。所以需要预先处理一下,这里记录过程。
最终的目的是一个model里带有所有的animation clip动作。因为直接用代码调用播放动画,所以也不需要动画状态机。
导入导入之后,先把动画模式改成Legacy。
动作未切片如果动画clip没有处理,那就自己在Animation里给动作切片就行。
一个fbx对应一个切片这类资源其实蛮麻烦的,需要在场景里拖拽任意一个带动作的model,然后把他作为新的prefab,才能对它的fbx进行编辑。
之后先把其他FBX动画模式改成Legacy!!!这点很重要,否则后面动作用不了的。
最后把其他fbx文件的animation clip用 ctrl+d 拷贝出来,拖到前面做的prefab的animation里,就可以了。
切片规范切片时长最好是要统一的,比如普攻随机动画总时长必须统一。还有诸如死亡动画。技能动画则不用。
代码生成
人物模型角色
主要内容
Arthur: 主节点,用来控制角色的位置移动。
arthur: Model,内附人物骨骼等,用来控制角色的旋转。 ...
CLR Via C#个人笔记4 - 类型和成员基础
大章6:类型和成员基础类型的各种成员
常量(大章7) 数据值恒定不变的符号。public const bool isBoy = true;
字段(大章7)
实例构造器(大章8)
类型构造器(大章8) 是将类型的静态字段初始化为良好初始状态的特殊方法。static ClassName() {}
方法(大章8) 更改或查询类型或对象状态的函数。分静态方法和实例方法。
操作符重载(大章8) 实际是方法,由于不是所有编程语言都支持操作符重载,所以它不是CLS(公共语言规范) 的一部分。
转换操作符(大章8) 是定义如何隐式或显式将对象从一种类型转型为另一种类型的方法。同操作符重载,由于不是所有编程语言都支持,所以它不是CLS(公共语言规范) 的一部分。
属性(大章10) 可以无参,也可以多参。public Int32 this[String s]{get;set;} // 实例有参属性(索引器)
事件(大章11) public event EventHandler SomeEvent; // 实例事件
类型 可以定义其他嵌套类型。通常 ...
王者荣耀复刻项目 网络同步篇
帧同步what什么是同步
在不同的客户端上表现相同。
目前市面上的游戏,一般分为帧同步和状态同步。
什么是帧同步
是一种网络同步技术。
由客户端A发送请求到服务端,再轮播给所有客户端各自在本地进行计算。
帧同步需要确保不同平台运算结果统一。
什么是状态同步
与帧同步最大的区别就是,它不需要按逻辑帧(固定时间间隔)去同步数据,而是根据数据发生改变后才进行同步数据。
why
王者荣耀就是用帧同步方式实现的网络同步。另外LOL用的是状态同步。
帧同步vs状态同步
战斗逻辑。帧同步是在客户端(或移到服务端)进行计算;状态同步一般只在服务端进行计算。
开发压力。帧同步因为在客户端算,要解决不同平台浮点数的差异,需要额外开发定点数替换浮点数;状态同步是在服务端算,相对安全,但对服务端负载要求更为高。
战斗重连。帧同步,玩家重连只能从服务端获取操作序列帧加速运算来恢复重连;状态同步可以随时获取到一个时间点的状态,所以mmo采用这个为主,可以瞬间恢复。
更新频率。帧同步,服务端必须保持定时推送同步信息给客户端,即使没有任何变更;状态同步,可以等某个状态发生变化了才推送同步信息给客户端。
...
王者荣耀复刻项目 战斗篇
全流程
代码结构
技能模块见技能篇:// TODO link
一些小功能的实现摄像机跟随要点是将 人物的位置 映射成 相机的位置。这里简单实现。
将相机的初始偏移值设置好,将角色初始位置能很好的放在中间显示。
Update中进行position对齐
1234void FightMgr.Update(){ // transCameraRoot物体下有一个旋转调整过初始值的相机。 mapRoot.transCameraRoot.position = transFollow.position;}
技能UI映射到地图非指向技能1:后羿的2技能
要点是将 UI拖拽的位置 映射成 地图向量的位置。
将技能UI拖拽起始点做记录,根据 拖动的点 - 拖拽起始点 = dir 获得一个初始的Vector2值。
将dir进行映射,具体做法是方向直接用dir.x和dir.y来作为地图的x、z轴,y轴取0;距离用一个倍乘器乘dir的模。映射好放到一个Vector3里。
将映射好的Vector3,偏转45度,因为相机偏转,技能也一起偏转以便与UI拖拽的方向对其。
123456 ...
CLR Via C#个人笔记3 - 基元类型、引用类型和值类型
大章5:值类型与引用类型基元类型什么是基元类型?
有些数据类型太常用了,为了方便程序员书写,C#编译器允许代码以简化语法来操纵。这些编译器直接支持的数据类型叫做基元类型(primitive type)。
注意一下,一般国人说的类型是指值类型和引用类型的分类,和这里的类型不是一个意思。
比如以下的代码
1234int a = 0;System.Int32 a = 0;int a = new int();System.Int32 a = new System.Int32();
他们4个生成的IL代码是完全一样的。
基元类型一览
基元类型的映射
string和String都是直接映射System.String,所以他们是完全一样的,所以基元类型的本质是映射到FCL(.NET 的 Framework Class Library)类型。
不同语言编译器,对于映射的处理不同,比如C#会将long映射到System.Int64而C++是映射Int32。
隐式转换,C#只会在转换安全的情况下才允许。所谓安全,就是说不会发生数据丢失的情况,比如从低精到高精。显式转换可以允许数据丢失,C#总是会选 ...