牧師與魔鬼(牧師與魔鬼的對話視頻)
牧師與魔鬼
0.前言
本博客是中山大學2021學年3D游戲編程與設計課程的第二次課程作業。實現游戲“牧師與魔鬼”,要求使用MVC架構。有許多博客文章與這項任務有關,但大多數都比較簡短。即使看完了,還是很難對整個作業的實施過程有一個清晰的認識。所以希望在實施過程中根據自己的理解寫一篇詳細的博客,為以后有需要的弟弟妹妹們提供一些幫助。感謝這位前輩(https://blog.csdn.net/weixin _ 43867940/文章/詳情/108818301)的博客。沒有他的啟發,我不可能完成這項任務。
設計
總體文檔框架如下
1.1資源的設計
這里的資源設計指的是預制件的設計。每種類型的游戲實體,只需要一個預制件,所以在這個游戲中,需要四個預制件:船、岸、牧師、惡魔。為了簡單起見,預制部件可以用立方體、球體和其他可以在Unity中直接創建的對象來代替。然后為每個預制件創建一個材質,將材質拖拽到對應的預制件上,最簡單的資源創建工作就完成了。預制部件放置在資源/預置文件夾中,材料放置在資源/預置文件夾中。
1.2代碼設計
根據工作需求,代碼設計需要使用MVC架構。即需要實現模型-視圖-控制器的分離。
模型:在游戲中,所有的實體都可以看作模型,可以是具體的,也可以是抽象的。其中,具體的模型有:船、岸、牧師、魔鬼。抽象模型是:點擊和移動。模型只關注實體本身最基本的屬性和方法,沒有考慮它與其他模型的交互。比如一個船模,它有兩個基本特征:可以創建,可以點擊。至于船是怎么載客的,被點擊后船做什么,這都不是模型這個層面應該關心的問題。再比如“動”的抽象模型。它最基本的屬性和方法是:移動的速度和移動的目的地。至于它想動誰,并不是模型本身的慣性。在“點擊”模型中,它只關注誰被點擊了,而不關注點擊觸發的事件是什么。另外,根據我自己的理解,我還加入了一個“位置”模型,這個模型只是提前記錄了游戲過程中所有可能的位置。
控制器:控制器用于控制模型的行為。因此,理論上,模型的每個副本都會有一個對應的控制器(位置模型除外)。例如,船模型將有一個BoatController,它將控制所有以船為目標的操作,例如當單擊船時處理事件,向船添加一名乘客,以及向船減少一名乘客。必須注意的是,直接控制模型的控制器之間沒有耦合關系,也就是說,BoatController只能知道目前船上有多少乘客,而不知道他們是誰(這些信息應該由每個RoleController保存)。而且因為移動的船要同時移動船上所有的乘客,BoatController不能直接移動乘客,所以實際移動船的邏輯不能直接寫在BoatController里(下面應該寫在哪里)。移動模型會有一個MoveController,控制誰要移動,負責判斷當前是否有模型在移動。
此外,還有一類非常重要的控制者,即場景控制者和導演。游戲就像一場戲劇。劇中會有多個場景,一個導演貫穿所有場景。導演控制器必須寫成singleton模式,這樣可以保證所有控制器都屬于同一個劇。每個場景都會有一個單獨的場景控制器,但是在這個游戲中,只有一個FirstController。場景控制器管理場景中的所有模型控制器,并實現它們的綜合行為。就這個游戲而言,FirstController將生成并管理:一個BoatController、兩個LandController、六個RoleController和一個MoveController。這個場景中所有的綜合行為都將在這個場景控制器中實現。例如:移動一艘船涉及到船和乘客的同時移動;流動角色涉及三個方面:離岸、登船和人的狀態的改變;判斷當前游戲是否成功。
最后,以I開頭的控制器都是接口,用來規范同類型控制器應該具有的行為,比如IObjectContoller應該被所有模型的控制器繼承,IScenceController應該被所有場景的控制器繼承,IUserAction負責與視圖通信的接口。
視圖:這里的視圖是GUI,它控制GUI上所有與3D游戲實體無關的組件。比如:標題,重啟按鈕,游戲成功或失敗時的提示。
3.工作流程
為了進一步說明代碼的工作原理,我將以游戲行為“先點擊一個牧師登船,再點擊船移動,游戲判定失敗”為例介紹代碼的工作流程。執行IFirstController中的喚醒功能和UserGUI中的啟動功能。前者初始化第一個場景中的所有3D對象,后者初始化2D GUI以點擊一個牧師。click事件由一個牧師模型(Role.cs)的Click組件(Click.cs)中的OnMouseDown函數捕獲,Click事件傳遞給對應的RoleController.cs(具體傳遞機制請參考RoleController.cs中的CreatModel函數)。RoleController.cs調用DealClick函數來解決Click事件。但是上面已經解釋過了,RoleController.cs并不能真正解決這個點擊事件,所以DealClick的做法是通過唯一導演找到管理他的場景控制者,讓場景控制者來解決這個問題。(請注意,場景控制者可以直接找到他管理的模型控制者,但模型控制者只能通過導演找到其上級場景控制者。)場景控制器調用指定的函數(本例中是MoveRole函數),調動所有相關的模型控制器,真正處理click事件。
再次點擊船,此時的響應邏輯和上面一模一樣。船模型中的click事件會一步一步的傳遞給場景控制器,click事件會被場景控制器的MoveBoat函數處理。執行MoveBoat功能時,會檢查當前游戲狀態,判斷游戲失敗。那么場景控制器中的gameState變量將被設置為FAILED,并且不再允許它處理click事件。UserGUI中的OnGUI函數會一直監聽場景控制器中gameState的值,當它發現這個值已經變得失效時,就會畫出文字“youfailed”。
4.資源
4.1操作模式
在Unity中創建新的3D項目,并用以下鏈接中提供的Assert文件夾替換項目的Assert文件夾。將Assert/Scripts/UserGUI拖動到MainCamera創建一個新的空GameObject,將FirstController拖動到GameObject,然后單擊Run。
4.2代碼
https://gitee . com/GallonC/unity home work/tree/master/home work 2/Assets
4.3視頻
https://www.bilibili.com/video/BV1634y1m75A? SPM _ id _ from = 333 . 999 . 0 . 0