——
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了