C# 中的访问修饰符和声明修饰符

前言 C# 中的访问修饰符和声明修饰符挺多的,总结一下,做个记录。 访问修饰符 访问修饰符通常作为声明字段数据类型的前缀,它标识了所修饰成员的封装级别。可以选择 5 个访问修饰符,即 public、private、protected、internal和 protected internal。 public 公有的:显式指明可从类的外部访问被它修饰的字段。 private 私有的:只有在声明它们的类和结构中才可以访问。如果不为类成员添加修饰符,那么默认使用的是 private。成员默认为私有成员,公共成员必须显式指定。 protected 受保护的:可在基类中定义只有派生类才能访问的成员。 internal 内部的,同一个程序集中的所有类都可以访问。 protected internal 访问级别为 internal 或 protected。即,“同一个程序集中的所有类,以及所有程序集中的子类都可以访问。 声明修饰符 目前了解的声明修饰符有 8 个,即 partial、static、abstract、Sealed、Virtual、Override、New、Extern。 Partial 在整个同一程序集中定义分部类和结构。 Static 声明属于类型本身而不是属于特定对象的成员。 Abstract 抽象类不可实例化,只能是其他类的基类。类中的方法只声明不实现,方法的实现在他的派生类中完成。其作用是强制所有派生类提供实现。 Sealed 对类使用 sealed 修饰符可以禁止从该类继承。 Virtual 用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。 规则:虚方法只提供默认实现,这种实现可由派生类完全重写;“运行时”遇到虚方法时,他会调用虚成员派生得最远的,重写的实现。 Override 提供从基类继承的成员的新实现。 New 作为修饰符,在基类面前隐藏了派生类重新声明的成员,在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。作为运算符,用于创建对象和调用构造函数。 Extern 用于声明在外部实现的方法。 extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 特性一起使用。 在这种情况下,还必须将方法声明为 static。

浅谈协程

前言 在 Unity 中,对协程的使用度非常高;面试的时候,也多数会被问到。自己都没有系统的整理下协程相关的知识。借此机会,梳理下自己对协程理解,以便更好的理解协程。 什么是协程? 协程(Coroutines)通过字面意思是协助程序。 A coroutine is like a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame。 这是 Unity 官网文档 中对协程的解释. 协程的原理 协程是一个部分执行,遇到条件(yield return)会挂起,知道条件满足才会被唤醒继续执行后面代码的一种函数。 Unity 在每一帧(Frame)都会去处理对象上的协程。Unity 主要是在 Update 后去处理协程(检查协程的条件是否满足) Coroutines 不是多线程,不是异步技术,协程都在 MainThread 中执行,而且每个时刻只有一个 Coroutine 在执行。 Coroutine 是一个 function,可以部分执行,当条件满足时,未来会被再次执行直到整个函数执行完毕。 协程在 unity 脚本执行顺序的位置 测试 根据协程的原理和协程在 Unity momo 脚本执行顺序做一个小测试来验证其原理。 public class Test : MonoBehaviour { void Start () { Debug.

工作自我反省

前言 前段时间看了一本有关程序员的职业素养的书《代码整洁之道 程序员的职业素养》。在这本书里,作者重新定义了专业程序员,要想成为真正专业的程序员,需要什么样的态度、原则、行动;这些态度、原则、行动都源于作者一路走来的亲身体会。可以把这本书当成一份指引,靠它绕开一些弯路,提高自己的职业素养。 本来想要总结程序员的职业素养,作者写的观点简洁明了,苦思良久,实在总结不出啥了。索性总结一下我这段时间工作上的犯过的错误以自省。 打包 面对自己不知道怎么办的时候,想别人请教。 对于打包这件事,面对自己不知道怎么打包,想当然的试着打一下包。殊不知,自己在公共打包环境,试着打包,有可能会对其他人测试环境,造成多大的影响。从而增加修复的工作量。在工作中,要保持严谨的工作态度,不能儿戏。明确自己工作中的每次操作,尤其是跟他人合作,或者在公共的环境下。自己做的每一步操作,都要清楚自己在做什么; 分支合并时,时刻保持清醒 保持清醒,清楚自己的每一步操作,在关键时刻尤为重要。 到项目的后期之后,不同分支(提审分支,稳定分支)在分支合并的时候,一定要清楚该做什么,不该做什么;一定要清楚自己哪些提交是需要cherry-pick 到稳定分支。 ps:(项目规定 merge 操作是单方向的,即:在 master 分支 merge 过 feature 分支之后,就不能再在该 feature 分支 merge master 分支)。 做任何操作都要清楚自己在做什么 在操作命令行的时候,首先明确自己的需求,再者要清楚每一步操作意义;不能抱着试试的想法,有一些操作可能是不可逆的,而自己不清楚,从而会造成不可预知的错误。 对自己的工作负责 接到新任务后,无论是不是新的一项任务,还是功能优化,都要对这项任务进行全面的了解:策划文档,与负责人沟通并确认需求,任务需要的测试环境,测试周期等等。

有关于 .prefab 与自身挂载组件的关系

问题 在 UI Panel 添加了一个粒子特效,打开该 Panel 时,特效不显示,选中特效时,特效又会显示出来。 测试 同事提醒可能跟特效的父级的 Scale 有关系。经过测试,确实跟 Canvas 的 Scale 有关系。因为我们项目 UI 框架设计的原因,将 UIPanel 制作成 prefab 时,将 UIPanel 的 Active 设置为 false;在 UIPanel 在加载成功时,Canvas 的 Scale 为 0,设置 UIPanel.SetActive(true) 之后,Canvas 的 Scale 为 1。 测试 Canvas 的 Scale 为 0 的原因 经过测试,Canvas 的 Scale 为 0 的原因跟 Canvas 的 Render Mode 有关系: Canvas 的 Render Mode 设置不同,对于 RectTransform 组件上的值是有影响的。 当 Renderer Mode 为 Screen Space - Camera 或 Screen Space -Overlay 时 Canvas 的 Scale 会为 0 ,如果为 World Space 时,Scale 就会变为 1。

提问的智慧-阅读笔记

前言 向其他人提问问题是很常见的事情,尤其从事计算机方面的工作,所以拥有提问的智慧尤为重要。提问的智慧这篇文章里面的提问环境是在技术论坛上或者邮件的形式。看完这篇文章之后,结合着自身的情况,写一些总结。 提问之前 1.在工作中遇到项目功能设计上的疑问,先去翻阅相关策划方案;如果还有疑问,把问题总结好再去跟相关人员提疑问。 2.如果遇到技术上的问题; 首先,尝试自己解决问题: 1->自己检查或者试验找到答案; 2->去查阅相关文档或者 API; 3->尝试上网搜索以找到答案; 4-> 尝试阅读源代码以找到答案; 如果做了上述的努力,还是没有找到合适的解决方案,就需要想身边的高手提问题。 提问题时 给别人描述问题的时候,使用清晰,正确,精准并语法正确的语句;也就是仔细,清楚地描述你的问题或 Bug 的症状。不要说一堆话,没有重点,既没有把问题描述清楚,也浪费了别人的时间。 未完待续 …

有关 git rebase 错误使用引发的问题

前言 本文是前几天我在工作中使用 git 指令合并分支的时候出现了问题,而当时采取了直接 “跳过问题” 的解决方案,导致了文件显示不出来了。所以写一份报告总结记录下。 错误 在 master 分支上跟其他分支进行 merge 时,二进制文件出现冲突。后续使用解决冲突的方式不对,导致二进制文件(.png 图片)显示不出来。 表面原因 出现错误的原因是:在出现冲突时,我先错误的使用了 “他人分支”,出现错误 “无法更新一个或多个文件,请确保没有其他的应用正在锁定你的文件” 时,后使用 “标记为已解决”。后来冲突文件消失了,我当时以为问题真的被解决了。 根本原因 在我的分支上跟 master merge 过,后来提交过几次之后,又进行了 rebase 操作重写历史提交信息后没有成功修改我的提交信息,后来我又通过 –soft 操作把我分支上的所有的提交都 reset 了,最后合并成一个提交。 执行 rebase 之后,跟 master merge 之后的文件的提交信息都丢失了,而这些文件在 master 分支上又被其他人修改过。导致我在回到 master 分支之后再跟我的分支 merge ,那些丢失提交信息的文件,就会出现冲突。 rebase 会将合并提交变为普通提交,丢失父节点信息。 使用 “他人分支” 或使用 “我的分支” 解决冲突失败是因为找不到文件的版本号 $ git checkout --theirs /e/Unity_new/client/Assets/Textures/Sprites/Quality/Content/CarQuality_D.png error: path 'Assets/Textures/Sprites/Quality/Content/CarQuality_D.png' does not have their version 思考 对于这一问题的处理方式,我犯了几个错误: 1.对于解决冲突的方式:“他人解决”,“我的解决”,“标记为已解决”,这几个操作所表示的意义不够深刻,导致做出了错误的操作。 2.在 master 分支上进行分支 merge 时候,出现冲突文件错误信息,没有仔细分析。

《游戏编程算法与技巧》读书笔记一

前言 前段时间阅读了一本有关游戏编程的书《游戏编程算法与技巧》,书中介绍了大量今天在游戏行业中用到的算法与技术。包括 2D 和 3D 图形学、物理、人工智能、摄像机等多个方面的技术。 知识框架图 这本书的读书笔记,我打算分成几部分,第一次我按着书上的不同的章节,简单的画了一个框架图,看着比较直观,细节上的内容在后续的博客里加上。

SuperTextMesh MemoryUninstall Bug

前言 前一段时间将 SuperTextMesh 导入到项目中,实现图文混排。最近使用 SuperTextMesh 来实现炫酷的文字特效。在使用过程中,发现了 SuperTextMesh 内存卸载的 Bug。从查找问题到解决断断续续花了有一周的时间,现在问题解决了,写一个总结记录下。 问题描述 项目中,在游戏界面上有使用 SuperTextMesh 来实现文字特效,在网络断开的时候文字会突然消失。经过调试,发现了网络断开的时候,代码在调用了 Resources.UnloadUnusedAssets() ,之后 SuperTextMesh 的文字就消失了。测试将那行代码注释掉,文字就不消失了。于是就沿着这个方向开始查找。 问题复现 为了验证 Bug 确实是资源卸载引起的,重新创建了一个全新的项目,将插件导入空项目中。 运行环境 SuperTextMesh:1.7.1 OS:Windows 10,64 位操作系统,基于 x64 的处理器 Unity:Unity 2017.4.2f2 (64-bit) Visual Studio:2017 复现操作 在场景中,创建 SuperTextMesh,Button;给 Button 添加点击事件,事件里调用 Resources.UnloadUnusedAssets()。开始运行,文字显示;点击按钮 Button, 文字消失。 找出原因 猜想一 当时还未锁定是资源卸载的问题的时候,排查方向是文字的参数发生了变化。 之前美术同事在做特效的时候,也出现过类似的问题,也会消失;然后选中该特效又能显示出来。后来找出的问题是:在过程中,有父集的 Scale 为 0 导致没有显示。所不同的是,我的一开始是显示的,只是后面消失了。 我根据同事的解决办法去检测下,SuperTextMesh 消失后他的 Scale 的情况,一并检测了其他会影响消失的参数,都没有找到问题所在,所以排除这个猜想。 之后的猜想都是关于资源卸载后,将使用中的 Text 里面的资源卸载掉的原因。 猜想二 Resources.UnloadUnusedAssets();会卸载掉不被引用的 assets,查代码找到 SuperTextmMeshData 的一个引用是通过 Resources.Load() 加载资源赋值的,后来看到 data 是一个私有静态成员变量,Resources.UnloadUnusedAssets() 不可能会卸载掉他(静态成员变量的引用一直会在)。 猜想三 问题出现的时候,在 FrameDebug 中 UGUI.

Unity Compilation Bug

前言 前几天在工作中,遇到一个有关 Unity 编译失效的问题,我修改的脚本保存后,Unity 自动编译后,编译失效。 问题描述 我在 VS 里修改了代码保存之后,回到 Unity 里,Unity 自动编译,编译完成之后,还是我修改代码之前的情况(我修改的文件没有被编译)。 问题复现 比如:我修改并了脚本 A,回到 Unity,Unity 自动编译,在编译期间修改并保存了脚本 B。编译完成之后,脚本 B 修改的部分极有可能没有被编译。 找出原因 1.检查了 Unity 的自动编译开关 Edit->Unity Preferences->General->Auto Refresh; 排查了 Unity 的设置问题 2.后来问了同事之后才了解的,这个问题 Unity 标记最后编译时间机制有关系。对于 Unity 而言,VS 只是一个编辑脚本工具,所有的编译工作都在 Unity 这边执行。Unity 不会记每个文件的编译时间,只会记录一个总的最后的编译时间。比如 Unity 编译开始时间为 t1 编译过程需要 10s,最后的编译时间为 t1+10s,如果在这 10s 内又对脚本做了修改,恰好这个脚本已经被编译过了。那这个脚本不会重新被编译,导致了后面的那次修改没有被编译。 解决办法 如果发生了编译失效问题,可以试试以下方法解决: 1.修改并保存编译失效脚本; 2.关闭并重新打开 Unity,重新修改并保存编译失效脚本。 总结与思考 有两点疑问没有解决: 1.Unity 最后编译时间存储在什么地方? 2.各个文件的编译时间存储在什么地方? 后续查 Unity 标记编译时间相关的资料没查到。听同事说这是 Unity 编译的一个 Bug,个人解决不了,只能在做的过程中尽量避免。现在我都会尽量避免在 Unity 执行编译的时候修改脚本。

First Publish FlapyBird

前言 这是我在 GitHub 上发布的第一个游戏作品。确切地说,不能算是一个作品,只能是一个小 Demo。项目中所实现的功能效果,离原版差太多。这也让我明白,要做出好的东西,是需要花费很多精力去做的。 游戏介绍 在《FlappyBird》这款游戏中,玩家只需要用一根手指来操控,点击触摸屏幕,小鸟就会往上飞,不断的点击就会不断的往高处飞。放松手指,则会快速下降。所以玩家要控制小鸟一直向前飞行,然后注意躲避途中高低不平的管子。 项目工程 项目已发布到GitHub Releases:项目地址 制作目的 制作游戏的目的在于锻炼独立做项目的能力。由于工作的安排,有时候自己接触到的功能模块比较单一,这就导致自己涉足的其他方面的机会比较少,所以在工作之余写一些简单的 Demo,FlappyBird 是我前一段时间写的一款 Demo。 流程框架 涉及到知识点总结 遇到的难点 功能难点: 1.最核心的是小鸟的飞行和下落的功能,飞行的不自然,缺少上升下落的角度; 2.使用 JSON 实现本地数据保存和读取来实现排行榜; 3.资源动态管理; 4.png 图片的动态切割 设计难点: 1.游戏框架,目前采用 Manager Of Managers; 2.游戏状态,使用有限状态机管理游戏状态,还未写好。 总结与思考 从项目开始到今天,有三周的时间(工作之外的时间),真正用到项目中总的时间大概就三四天的时间吧,这个项目的也不大,整体难度也不难,做起来感觉很费时间,实现一个小功能,花时间比较多,而且返工的次数很多。 这个项目做下来,自己身上已知的好多问题突显出来了。比如知识的缺乏,缺乏自制力,严重拖延症等。想的太多,做的太少,可能是我最大的问题了。 我接下来要做的是上面列出的难点。之后会不断的完善缺少的功能,不定期的更新 FlappyBird 的项目进度。 反思和记录下来自己问题,努力下一个游戏,项目的完成度和质量高一些。