——
DAY 1
我发现已有算法有个大盲点——过道根本就放不进去……主要过道要等长就很难受。我一度怀疑自己是不是记错了。直到我看了个游戏视频,认真地数了两个过道的长度……很好真的是等长的=(
(冷知识:新图第一小关的过道长度可以是24块砖,会有至少一块砖其他的不一样)
我蹦出来的第一个想法就是取消之前算法游走点的设计。游走点只能让其所经过的方向上能放等长通道,别的就塞不进去了。就算设计两个的话,两个点生成的房间之间也无法放置通道。不如让房间自己决定怎么放自己得了(自给自足可还行)
首先要想出来房间坐标的规律。我数学老师告诉我“遇事不决就画图”,所以我就画了幅
(这稀烂的比例……)
通过假设生成的四个房间全部一样,我得出了一个不知道对不对的结论:一个房间的x和y值由其上下左右的房间决定(如果有)
这意味着房间的长宽没法完全随机了。某些情况下,新生成的房间宽只有两格,而长可以达到十几格。(死亡走廊是吧)如果再加上固定长宽比的限制话,真没得玩了
我也不知道我是怎么想的,我还是想试一下这种思路能不能写,比如尝试放开长宽比(来自第二天的我:什么毛病,浪费了我宝贵的一天)
第一个版本在傍晚结束。没写完,半路夭折。不如及时止损,想点别的
(主要就这么多,还有别的不想截了,太垃圾了)
——
DAY 2
要不还是再看几个视频吧,昨天就数了两个过道。虽然如果过道长度真的是随机的话,随便数两个就等长的几率不大(・_・;
我去怎么有条26格长的?可能是偏差,数个别的
这回16格长了……偏差也不带这么偏的吧……说不定真的全部随机?那这样可就好写n倍了!
在数了好几条不同地图不同大关的过道后,我得到了以下几个数据:16,19,24,25,26,29。你说它随机,又不完全随;不随机,又不确定是不是真的写死了一些值,毕竟我没有把全部的过道都数一遍。不如就把过道的长度定在16——29的范围里
(这件事告诉我们多个样本的重要性ʕ •ᴥ•ʔ)
写之前梳理一下思路。
1.利用二维数组随机生成方形地图,并用0和1做标志,1代表当前位置有房间,0则相反。
2.根据当前要求的房间量随机将几个房间的标志位置0。此处难点在于怎么置0才能保证在随机的情况下剩下的房间都是连着的
3.随机更改几个房间的大小
4.最后连通每个房间,并保证过道的长度在限制内
5.梦该醒了,笑死根本完不成
现在是两个小时以后,房间类正在重写,上次的模版什么的也全部注释了。目前的代码相对之前来说比较好看,除了没法按预期运行就没什么大的缺点了
顺便提一下,我找回我的断点了!虽然中间几经波折,最后也没有真正的解决(用函数断点代替之前左边的断点,能用就行了),不过终于不用再一个一个Debug.Log了。IDE也换了,换成了VS2022。本来想用VS Code的,但是发现上面的官方调试插件弃用了(更离谱的是官方的弃用了但是其他大佬的扩展版本没有),加上环境怎么也配置不好,便继续用VS了
(一排下来就官方的弃用了)
如果大家能配置好VS Code环境的话我还是推荐VS Code。真的麻雀虽小五脏俱全,启动还快,啥语言都能写。现在虽然写代码舒服了,但是将近2GB的大小只能写C#和F#,怎么想怎么心疼我的2GB(._.)。由于VS庞大的体积,开调试的时候总会卡那么一下,加上Unity老是发疯,动不动就扔出个未响应然后跑到旁边睡觉……综上所述,VS Code永远的神!
我收回我之前说的话。这断点只能用一点点,我想看个函数中间的东西,结果单步调试调试到Unity官方写的类里来了
也没什么大不了的,跳出来不就可以了吗?但是我出不来了!无论我单步跳过还是单步调试,都调不出来,一直在里面打转。按键都快给我按坏了我还在里面
找到bug了。变量名字写错了……除去这个低级错误,这次一次就成实属幸运。目前不仅完成了第一个主线任务,顺便把支线(画出房间)也做了。目前的效果是这样的
点击链接观看视频(依然连测试脚本都懒得写)
目前有大改动的代码如下
目前一切安好,顺便解锁成就:又来了个玩递归的萌新
现在是晚上了,第二步还没开始,因为重构去了。从上面的代码可以看出,当我们每次想获得map内的值时,都要来个双层foreach循环。又因为我有嵌套强迫症,看见大于3次的嵌套就难受,所以我抽取出了一个map类(咱就为了这碟醋才包的饺子)
主要思想就是模仿刚刚用到的迭代器。后期肯定要加上注释,一堆i和j到明天连我都不懂了
——
DAY 3
目前毫无进展,调试调了大半天了啥也没看出来。现在整个类乱成一团,看得我非常迷茫,连注释都不知道怎么写(・_・;
Unity还是老样子,除了它连装都不想装了,直接意外退出,省了我打开任务管理器手动杀进程的工夫(这么贴心的Unity很难不让人想踹几脚)
大家写代码的时候一定要规范命名啊,就100行的程序竟然同时出现x,y和i,
j两对卧龙凤雏。现在我想重命名,但是又有bug,搞得我自己都不知道我写了什么,这代码在干啥。最后只能盯着这堆垃圾在屏幕里快乐地上下跳跃,无辜地扔出一个奇奇怪怪的结果,留下我一个人抱着发烫的电脑骂着根本就不是人的人。算了再逝亿次吧
找到了,不是bug,是最开始整个思路就错了。所以我又浪费了一天!太棒了!********(文明帖子,自动消音)
继续收尸,思路完全错了的代码如下
(它们最后的作用就是帮我水点长度ᶘ ᵒᴥᵒᶅ)
——
DAY 4
我现在在想是不是我顺序搞错了,或许应该先全部置0然后再随机选几个置1,并保证置1的房间都是连着的。但是这么搞不就又回去了吗?那我费力写个map类干啥呢?
我又有了个想法。既然原点(0,0)的房间一定存在,那么从任意房间开始,向(0,0)走,能碰到的就是连着的,碰不到就是被分散了。
但是怎么走呢?怎么保证在遇到分岔点的时候不往回走?而且我现在map里的数据和实际索引是反过来的就很恶心。我感觉我真的想复杂了但是也没有别的思路
最后还是跑去用Debug.Log了。因为每次调试的时候都想在抽盲盒,普通款卡顿,稀有款意外退出,史诗款未响应,隐藏款弹出Unity bug修复器。当然不能指望修复器干什么事,永远都是“尝试修复失败,请将此bug汇报”。累了,我现在感觉我在写日记,但是正经人谁写日记呢?
这个代码就很奇怪,我觉得会出错的的地方反而能跌跌撞撞跑起来;我觉得应该没事的地方反而报异常——然后我找不到。调试有个很烦人的地方:因为我是函数断点,所以会在异常之前进入函数。但是你又不知道它什么时候会报异常,所以只能一步一步走。在你过了几个平稳运行的代码后,你以为这里没事了,所以就快速往前走,但是突然它就宕机了,你又没看到在哪里,又不能往回,只能重新开始,然后周而复始(⌒-⌒; )
好的我连话都说不清楚了。明天继续吧,虽然写这么长了还没进入正题。主要我高估我自己了,没想到我这么废物
——
DAY 5
走了几次了,每次报错的地方都不一样,但是最后报的错都是一样的。我好迷茫,全程三个问题围着我转:为什么不跑?为什么能跑?为什么这么跑?
这几天门外一直有小孩哭,一哭就是一个小时起步。要不是因为我年龄是他的两倍大,我也跟着哭,我还能保证哭得比他还大声
空引用错误真的是万恶之源,什么bug修到最后都剩个空引用。这边修好个InvalidOperation,那边又来个空引用;拿出Debug.Log看是不是空引用,结果Debug.Log跟着一起空引用。我真的吐了啊,我现在连“空”字都不认识了!(似曾相识:应用卡了-->杀进程-->调出任务管理器-->恭喜你又多了个卡着的应用)
在经过5个小时的调试后,我终于找到了bug点,至于怎么修,emmm,我也不知道,我感觉我见鬼了。我在有问题的函数里加了个Debug.Log,让它调用同一个实例对象的同一个方法,并传入固定的值,结果它打印出来的结果竟然不一样?
修好空引用了!然后又报了之前的错!真的太好玩了!
我又又修好了现在的报错,空引用又回来了!我去什么玩意啊?
继续调试,目前一共发现了两个报错点。我的运气也不负众望,调试哪个哪个就声东击西,装作无事发生;另一个看准时机,立刻抛出异常。
我选择同时调试两个地方,按了20分钟继续执行都没结束或者报错,我正疑惑呢,回头一看原来是Unity早就意外退出了……新概念人工智能?就是不让我修?
VS2022没想到还挺智能的,我就写了个foreach语句,它能帮我改成linq,接着还能改成异步,看得我一愣一愣的(我不会告诉你我linq和异步都很差)。我就不智能了,它帮我改了后我不想要但是我改不回来了
现在是进行调试的第8个小时,仍未从根源解决bug点,null仍有发生。于是我在更上层的地方加了个剔除null的语句。不算是一个好的解决办法,甚至都不算一个解决办法,因为在我想运行并测试时,我的Unity已经无法运行任何代码了,一按运行键就崩溃。反复试了六七次后我决定放弃,并决定使用软件修复的最终奥义:重启。哪个不行哪个重启,再没用电脑重启
好的没用,Unity彻底报废。考虑着换最新版本,但也不知道会不会更加不稳定。正常项目开发都是选好一个稳定版本后就几年不换了,就是为了避免新版本可能会更加难用的情况。如果真的要换也是会仔细看更新日志,看看有没有真的很需要的功能,或者是老到完全没办法支持现有环境了
而且换大版本还有可能会出现使用的接口被弃用,然后整个项目全是错误。我也不知道为什么这次这么艰难。刚刚稍微能运行几次没报错后又卡死了。我上次应该是下错了,没下到稳定版本
得了,完成了,稳定版本果然丝滑多了。所以到目前为止,我们用5天的时间和无尽的痛苦换来了跟上期一样——甚至还没上期那么多的算法实现。我不知道我在这里干什么,而且看效果不是特别好,没有像我预期的那样出现团状的房间,可能后面还要修改算法,改下概率什么的。这期就当水帖了,啥也没干(安慰一下自己:至少开头说的过道能放了)
当我没说,它又崩了,又打不开了。我真的麻了,我只希望今天能录到一个成功的。先把完整代码贴出来
最后视频:(就录到这一个,正好是长条。第二次再运行就崩了)
点击链接观看视频
——
一些出现的知识点(不严谨但是差不多就是这样ʕ •ᴥ•ʔ)
(1)位枚举定义跟普通枚举一样,除了枚举的上面多了个[Flags]标志。位枚举每一项的数值都是2的n次方(为了方便和好记也可以采用位移<<的方式进行赋值)
添加一项使用|按位或,取消一项使用&~(好像没有正式名字,但是&是按位与,~是按位取反),判断是否有某项用&按位与
(2)VS中的调试(这个写给第二天憨憨的我看的)继续执行:继续当前代码的执行,直到再次碰到已有断点单步执行:跟它的名字一样,代码执行的每一步都会暂停单步跳过:跳过一些函数等大代码块单步跳出:离开当前函数并回到上次执行的地方
(3)迭代器第二天的使用方法就是包装了一个方法,方法内部获取rooms的迭代器。可以利用迭代器进行遍历。注意迭代器遍历过程中所迭代的列表不能发生改变,否则会引发InvalidOperation。foreach也是使用迭代器,所以无法使用foreach来更改列表的值
(4)Linq(友情提示:代码里出现的所有linq都是由vs自动生成的,我对linq一无所知)相信知道一点sql的人肯定对这个东西很眼熟:select,from,where……linq也可以用方法的形式进行调用,具体操作就是往里面塞个lambda作为条件。我目前倾向于使用方法(因为要查的都是简单的,一两个方法就够了),至于下面这个,VS写的,我觉得好牛逼就保留下来了(对我就是来搞笑的)
(盲猜一波在干啥:room是从rooms里遍历出来的,let声明result,值为room RelayRequest得结果。从条件 !result.ReachOrigin 中选出new{},然后把它丢掉。如果选出来了就会执行下面的遍历,没选出来就跳过)
顺便引出来接下来的知识点
(5)_丢弃运算符如果有一个方法返回的结果你不想要,那就把它丢了吧!比搞个临时变量强买强卖好多了。一个比较常见的案例就是同时有两个返回值的方法(其实在上面的代码里我也写了个),返回是否成功的布尔值和out参数。如果只想要个布尔值那就可以out _来敷衍过去
(6)拷贝列表的值C#里面不能直接 列表1=列表2,因为这样传的是引用,相当于这两玩意是一个东西。我在上面用了ForEach,这样就只会复制值
这期就这样了。我知道很水,甚至往回走了,不过没事放松一下也不错。以后就不能用这种格式了,否则这系列就要改个名字了:编程劝退日记。等下要不这期就叫这个名字得了
我也不知道下期干啥,如果Unity还不好那下期就只能写怎么删除Unity了